<commit_before>// Copyright 2016 Mirantis
//
// 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 extensions

import (
	"encoding/json"
	"errors"
	"net"

	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/api/meta"
	"k8s.io/client-go/1.5/pkg/api/unversioned"
	"k8s.io/client-go/1.5/pkg/apimachinery/announced"
	"k8s.io/client-go/1.5/pkg/runtime"

	"github.com/Mirantis/k8s-externalipcontroller/pkg/netutils"
)

const (
	GroupName string = "ipcontroller.ext"
	Version   string = "v1"
)

var (
	SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: Version}
	SchemeBuilder      = runtime.NewSchemeBuilder(addKnownTypes)
)

func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(
		SchemeGroupVersion,
		&IpNode{},
		&IpNodeList{},
		&IpClaim{},
		&IpClaimList{},
		&IpClaimPool{},
		&IpClaimPoolList{},

		&api.ListOptions{},
		&api.DeleteOptions{},
	)
	return nil
}

func init() {
	if err := announced.NewGroupMetaFactory(
		&announced.GroupMetaFactoryArgs{
			GroupName:                  GroupName,
			VersionPreferenceOrder:     []string{SchemeGroupVersion.Version},
			AddInternalObjectsToScheme: SchemeBuilder.AddToScheme,
		},
		announced.VersionToSchemeFunc{
			SchemeGroupVersion.Version: SchemeBuilder.AddToScheme,
		},
	).Announce().RegisterAndEnable(); err != nil {
		panic(err)
	}
}

type IpNode struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// used as a heartbeat
	Revision int64 `json:"generation,string"`
}

func (e *IpNode) GetObjectKind() unversioned.ObjectKind {
	return &e.TypeMeta
}

func (e *IpNode) GetObjectMeta() meta.Object {
	return &e.Metadata
}

type IpNodeList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpNode `json:"items" protobuf:"bytes,2,rep,name=items"`
}

type IpClaim struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Spec IpClaimSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
}

func (e *IpClaim) GetObjectKind() unversioned.ObjectKind {
	return &e.TypeMeta
}

func (e *IpClaim) GetObjectMeta() meta.Object {
	return &e.Metadata
}

type IpClaimList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpClaim `json:"items" protobuf:"bytes,2,rep,name=items"`
}

type IpClaimSpec struct {
	// NodeName used to identify where IPClaim is assigned (IPNode.Name)
	NodeName string `json:"nodeName" protobuf:"bytes,10,opt,name=nodeName"`
	Cidr     string `json:"cidr,omitempty" protobuf:"bytes,10,opt,name=cidr"`
	Link     string `json:"link" protobuf:"bytes,10,opt,name=link"`
}

type IpClaimPool struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Spec IpClaimPoolSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
}

type IpClaimPoolSpec struct {
	CIDR      string            `json:"cidr" protobuf:"bytes,10,opt,name=cidr"`
	Ranges    [][]string        `json:"ranges,omitempty" protobuf:"bytes,5,opt,name=ranges"`
	Allocated map[string]string `json:"allocated,omitempty" protobuf:"bytes,2,opt,name=allocated"`
}

type IpClaimPoolList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpClaimPool `json:"items" protobuf:"bytes,2,rep,name=items"`
}

func (p *IpClaimPool) AvailableIP() (availableIP string, err error) {
	ip, network, err := net.ParseCIDR(p.Spec.CIDR)
	if err != nil {
		return
	}

	var dropOffIP net.IP

	ranges := [][]net.IP{}

	//in case 'Ranges' is not set for the pool assume ranges of the
	//network itself
	if p.Spec.Ranges != nil {
		for _, r := range p.Spec.Ranges {
			ip = net.ParseIP(r[0])
			dropOffIP = net.ParseIP(r[len(r)-1])
			netutils.IPIncrement(dropOffIP)

			ranges = append(ranges, []net.IP{ip, dropOffIP})
		}
	} else {
		//network address is not usable
		netutils.IPIncrement(ip)
		ranges = [][]net.IP{{ip, dropOffIP}}
	}

	for _, r := range ranges {
		curAddr := r[0]
		nextAddr := make(net.IP, len(curAddr))
		copy(nextAddr, curAddr)
		netutils.IPIncrement(nextAddr)

		firstOut := r[len(r)-1]

		for network.Contains(curAddr) && network.Contains(nextAddr) && !curAddr.Equal(firstOut) {
			if _, exists := p.Spec.Allocated[curAddr.String()]; !exists {
				return curAddr.String(), nil
			}
			netutils.IPIncrement(curAddr)
			netutils.IPIncrement(nextAddr)

		}
	}

	return "", errors.New("There is no free IP left in the pool")
}

func (p *IpClaimPool) GetObjectKind() unversioned.ObjectKind {
	return &p.TypeMeta
}

func (p *IpClaimPool) GetObjectMeta() meta.Object {
	return &p.Metadata
}

// see https://github.com/kubernetes/client-go/issues/8
type ExampleIpNode IpNode
type ExampleIpNodesList IpNodeList
type ExampleIpClaim IpClaim
type ExampleIpClaimList IpClaimList
type ExampleIpClaimPool IpClaimPool
type ExampleIpClaimPoolList IpClaimPoolList

func (e *IpClaimPool) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimPool{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimPool(tmp)
	*e = tmp2
	return nil
}

func (e *IpClaimPoolList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimPoolList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimPoolList(tmp)
	*e = tmp2
	return nil
}

func (e *IpNode) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpNode{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpNode(tmp)
	*e = tmp2
	return nil
}

func (el *IpNodeList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpNodesList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpNodeList(tmp)
	*el = tmp2
	return nil
}

func (e *IpClaim) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaim{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaim(tmp)
	*e = tmp2
	return nil
}

func (el *IpClaimList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimList(tmp)
	*el = tmp2
	return nil
}
<commit_msg>fix type<commit_after>// Copyright 2016 Mirantis
//
// 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 extensions

import (
	"encoding/json"
	"errors"
	"net"

	"k8s.io/client-go/1.5/pkg/api"
	"k8s.io/client-go/1.5/pkg/api/meta"
	"k8s.io/client-go/1.5/pkg/api/unversioned"
	"k8s.io/client-go/1.5/pkg/apimachinery/announced"
	"k8s.io/client-go/1.5/pkg/runtime"

	"github.com/Mirantis/k8s-externalipcontroller/pkg/netutils"
)

const (
	GroupName string = "ipcontroller.ext"
	Version   string = "v1"
)

var (
	SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: Version}
	SchemeBuilder      = runtime.NewSchemeBuilder(addKnownTypes)
)

func addKnownTypes(scheme *runtime.Scheme) error {
	scheme.AddKnownTypes(
		SchemeGroupVersion,
		&IpNode{},
		&IpNodeList{},
		&IpClaim{},
		&IpClaimList{},
		&IpClaimPool{},
		&IpClaimPoolList{},

		&api.ListOptions{},
		&api.DeleteOptions{},
	)
	return nil
}

func init() {
	if err := announced.NewGroupMetaFactory(
		&announced.GroupMetaFactoryArgs{
			GroupName:                  GroupName,
			VersionPreferenceOrder:     []string{SchemeGroupVersion.Version},
			AddInternalObjectsToScheme: SchemeBuilder.AddToScheme,
		},
		announced.VersionToSchemeFunc{
			SchemeGroupVersion.Version: SchemeBuilder.AddToScheme,
		},
	).Announce().RegisterAndEnable(); err != nil {
		panic(err)
	}
}

type IpNode struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// used as a heartbeat
	Revision int64 `json:",string"`
}

func (e *IpNode) GetObjectKind() unversioned.ObjectKind {
	return &e.TypeMeta
}

func (e *IpNode) GetObjectMeta() meta.Object {
	return &e.Metadata
}

type IpNodeList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpNode `json:"items" protobuf:"bytes,2,rep,name=items"`
}

type IpClaim struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Spec IpClaimSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
}

func (e *IpClaim) GetObjectKind() unversioned.ObjectKind {
	return &e.TypeMeta
}

func (e *IpClaim) GetObjectMeta() meta.Object {
	return &e.Metadata
}

type IpClaimList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpClaim `json:"items" protobuf:"bytes,2,rep,name=items"`
}

type IpClaimSpec struct {
	// NodeName used to identify where IPClaim is assigned (IPNode.Name)
	NodeName string `json:"nodeName" protobuf:"bytes,10,opt,name=nodeName"`
	Cidr     string `json:"cidr,omitempty" protobuf:"bytes,10,opt,name=cidr"`
	Link     string `json:"link" protobuf:"bytes,10,opt,name=link"`
}

type IpClaimPool struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard object metadata
	Metadata api.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Spec IpClaimPoolSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
}

type IpClaimPoolSpec struct {
	CIDR      string            `json:"cidr" protobuf:"bytes,10,opt,name=cidr"`
	Ranges    [][]string        `json:"ranges,omitempty" protobuf:"bytes,5,opt,name=ranges"`
	Allocated map[string]string `json:"allocated,omitempty" protobuf:"bytes,2,opt,name=allocated"`
}

type IpClaimPoolList struct {
	unversioned.TypeMeta `json:",inline"`

	// Standard list metadata.
	unversioned.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []IpClaimPool `json:"items" protobuf:"bytes,2,rep,name=items"`
}

func (p *IpClaimPool) AvailableIP() (availableIP string, err error) {
	ip, network, err := net.ParseCIDR(p.Spec.CIDR)
	if err != nil {
		return
	}

	var dropOffIP net.IP

	ranges := [][]net.IP{}

	//in case 'Ranges' is not set for the pool assume ranges of the
	//network itself
	if p.Spec.Ranges != nil {
		for _, r := range p.Spec.Ranges {
			ip = net.ParseIP(r[0])
			dropOffIP = net.ParseIP(r[len(r)-1])
			netutils.IPIncrement(dropOffIP)

			ranges = append(ranges, []net.IP{ip, dropOffIP})
		}
	} else {
		//network address is not usable
		netutils.IPIncrement(ip)
		ranges = [][]net.IP{{ip, dropOffIP}}
	}

	for _, r := range ranges {
		curAddr := r[0]
		nextAddr := make(net.IP, len(curAddr))
		copy(nextAddr, curAddr)
		netutils.IPIncrement(nextAddr)

		firstOut := r[len(r)-1]

		for network.Contains(curAddr) && network.Contains(nextAddr) && !curAddr.Equal(firstOut) {
			if _, exists := p.Spec.Allocated[curAddr.String()]; !exists {
				return curAddr.String(), nil
			}
			netutils.IPIncrement(curAddr)
			netutils.IPIncrement(nextAddr)

		}
	}

	return "", errors.New("There is no free IP left in the pool")
}

func (p *IpClaimPool) GetObjectKind() unversioned.ObjectKind {
	return &p.TypeMeta
}

func (p *IpClaimPool) GetObjectMeta() meta.Object {
	return &p.Metadata
}

// see https://github.com/kubernetes/client-go/issues/8
type ExampleIpNode IpNode
type ExampleIpNodesList IpNodeList
type ExampleIpClaim IpClaim
type ExampleIpClaimList IpClaimList
type ExampleIpClaimPool IpClaimPool
type ExampleIpClaimPoolList IpClaimPoolList

func (e *IpClaimPool) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimPool{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimPool(tmp)
	*e = tmp2
	return nil
}

func (e *IpClaimPoolList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimPoolList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimPoolList(tmp)
	*e = tmp2
	return nil
}

func (e *IpNode) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpNode{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpNode(tmp)
	*e = tmp2
	return nil
}

func (el *IpNodeList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpNodesList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpNodeList(tmp)
	*el = tmp2
	return nil
}

func (e *IpClaim) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaim{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaim(tmp)
	*e = tmp2
	return nil
}

func (el *IpClaimList) UnmarshalJSON(data []byte) error {
	tmp := ExampleIpClaimList{}
	err := json.Unmarshal(data, &tmp)
	if err != nil {
		return err
	}
	tmp2 := IpClaimList(tmp)
	*el = tmp2
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold Authors

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

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

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

package jib

import (
	"os/exec"
	"sort"
	"strings"

	"os"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/karrick/godirwalk"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

func getDependencies(cmd *exec.Cmd) ([]string, error) {
	stdout, err := util.RunCmdOut(cmd)
	if err != nil {
		return nil, err
	}

	// Parses stdout for the dependencies, one per line
	lines := strings.Split(string(stdout), "\n")

	var deps []string
	for _, dep := range lines {
		if dep == "" {
			continue
		}

		// TODO(coollog): Remove this once Jib deps are prepended with special sequence.
		// Skips the project directory itself. This is necessary as some wrappers print the project directory for some reason.
		if dep == cmd.Dir {
			continue
		}

		// Resolves directories recursively.
		info, err := os.Stat(dep)
		if err != nil {
			if os.IsNotExist(err) {
				logrus.Debugf("could not stat dependency: %s", err)
				continue // Ignore files that don't exist
			}
			return nil, errors.Wrapf(err, "unable to stat file %s", dep)
		}

		if !info.IsDir() {
			deps = append(deps, dep)
			continue
		}

		if err = godirwalk.Walk(dep, &godirwalk.Options{
			Unsorted: true,
			Callback: func(path string, _ *godirwalk.Dirent) error {
				deps = append(deps, path)
				return nil
			},
		}); err != nil {
			return nil, errors.Wrap(err, "filepath walk")
		}
	}

	sort.Strings(deps)
	return deps, nil
}
<commit_msg>Use os.SameFile() to check for mvnw working-dir echo bug<commit_after>/*
Copyright 2018 The Skaffold Authors

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

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

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

package jib

import (
	"os/exec"
	"sort"
	"strings"

	"os"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
	"github.com/karrick/godirwalk"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

func getDependencies(cmd *exec.Cmd) ([]string, error) {
	stdout, err := util.RunCmdOut(cmd)
	if err != nil {
		return nil, err
	}

	cmdDirInfo, err := os.Stat(cmd.Dir)
	if err != nil {
		return nil, err
	}

	// Parses stdout for the dependencies, one per line
	lines := strings.Split(string(stdout), "\n")

	var deps []string
	for _, dep := range lines {
		if dep == "" {
			continue
		}

		// Resolves directories recursively.
		info, err := os.Stat(dep)
		if err != nil {
			if os.IsNotExist(err) {
				logrus.Debugf("could not stat dependency: %s", err)
				continue // Ignore files that don't exist
			}
			return nil, errors.Wrapf(err, "unable to stat file %s", dep)
		}

		// TODO(coollog): Remove this once Jib deps are prepended with special sequence.
		// Skips the project directory itself. This is necessary as some wrappers print the project directory for some reason.
		if os.SameFile(cmdDirInfo, info) {
			continue
		}

		if !info.IsDir() {
			deps = append(deps, dep)
			continue
		}

		if err = godirwalk.Walk(dep, &godirwalk.Options{
			Unsorted: true,
			Callback: func(path string, _ *godirwalk.Dirent) error {
				deps = append(deps, path)
				return nil
			},
		}); err != nil {
			return nil, errors.Wrap(err, "filepath walk")
		}
	}

	sort.Strings(deps)
	return deps, nil
}
<|endoftext|>


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

package sql

import (
	"bytes"
	"math"

	"github.com/cockroachdb/cockroach/pkg/sql/parser"
)

// formatColumns converts a column signature for a data source /
// planNode to a string. The column types are printed iff the 2nd
// argument specifies so.
func formatColumns(cols ResultColumns, printTypes bool) string {
	var buf bytes.Buffer
	buf.WriteByte('(')
	for i, rCol := range cols {
		if i > 0 {
			buf.WriteString(", ")
		}
		parser.Name(rCol.Name).Format(&buf, parser.FmtSimple)
		// Output extra properties like [hidden,omitted].
		hasProps := false
		outputProp := func(prop string) {
			if hasProps {
				buf.WriteByte(',')
			} else {
				buf.WriteByte('[')
			}
			hasProps = true
			buf.WriteString(prop)
		}
		if rCol.hidden {
			outputProp("hidden")
		}
		if rCol.omitted {
			outputProp("omitted")
		}
		if hasProps {
			buf.WriteByte(']')
		}

		if printTypes {
			buf.WriteByte(' ')
			buf.WriteString(rCol.Typ.String())
		}
	}
	buf.WriteByte(')')
	return buf.String()
}

// newExplainPlanNode instantiates a planNode that runs an EXPLAIN query.
func (p *planner) makeExplainPlanNode(verbose, expanded bool, plan planNode) planNode {
	columns := ResultColumns{
		{Name: "Level", Typ: parser.TypeInt},
		{Name: "Type", Typ: parser.TypeString},
		{Name: "Description", Typ: parser.TypeString},
	}
	if verbose {
		columns = append(columns, ResultColumn{Name: "Columns", Typ: parser.TypeString})
		columns = append(columns, ResultColumn{Name: "Ordering", Typ: parser.TypeString})
	}

	node := &explainPlanNode{
		verbose:  verbose,
		expanded: expanded,
		plan:     plan,
		results:  p.newContainerValuesNode(columns, 0),
	}
	return node
}

// populateExplain extracts the information from planNodes to produce
// the EXPLAIN output into a valuesNode.
func populateExplain(verbose bool, v *valuesNode, plan planNode, level int) error {
	name, description, children := plan.ExplainPlan(verbose)

	row := parser.DTuple{
		parser.NewDInt(parser.DInt(level)),
		parser.NewDString(name),
		parser.NewDString(description),
	}
	if verbose {
		row = append(row, parser.NewDString(formatColumns(plan.Columns(), false)))
		row = append(row, parser.NewDString(plan.Ordering().AsString(plan.Columns())))
	}
	if _, err := v.rows.AddRow(row); err != nil {
		return err
	}

	for _, child := range children {
		if err := populateExplain(verbose, v, child, level+1); err != nil {
			return err
		}
	}
	return nil
}

// explainPlanNode implements the logic for EXPLAIN.
type explainPlanNode struct {
	verbose  bool
	expanded bool
	plan     planNode
	results  *valuesNode
}

func (e *explainPlanNode) ExplainTypes(fn func(string, string)) {}
func (e *explainPlanNode) Next() (bool, error)                  { return e.results.Next() }
func (e *explainPlanNode) Columns() ResultColumns               { return e.results.Columns() }
func (e *explainPlanNode) Ordering() orderingInfo               { return e.results.Ordering() }
func (e *explainPlanNode) Values() parser.DTuple                { return e.results.Values() }
func (e *explainPlanNode) DebugValues() debugValues             { return debugValues{} }
func (e *explainPlanNode) SetLimitHint(n int64, s bool)         { e.results.SetLimitHint(n, s) }
func (e *explainPlanNode) setNeededColumns(_ []bool)            {}
func (e *explainPlanNode) MarkDebug(mode explainMode)           {}
func (e *explainPlanNode) expandPlan() error {
	if e.expanded {
		if err := e.plan.expandPlan(); err != nil {
			return err
		}
		// Trigger limit hint propagation, which would otherwise only occur
		// during the plan's Start() phase. This may trigger additional
		// optimizations (eg. in sortNode) which the user of EXPLAIN will be
		// interested in.
		e.plan.SetLimitHint(math.MaxInt64, true)
	}
	return nil
}
func (e *explainPlanNode) ExplainPlan(v bool) (string, string, []planNode) {
	return "explain", "plan", []planNode{e.plan}
}

func (e *explainPlanNode) Start() error {
	return populateExplain(e.verbose, e.results, e.plan, 0)
}

func (e *explainPlanNode) Close() {
	e.plan.Close()
	e.results.Close()
}
<commit_msg>sql: better encapsulate the EXPLAIN logic.<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//

package sql

import (
	"bytes"
	"math"

	"github.com/cockroachdb/cockroach/pkg/sql/parser"
)

// formatColumns converts a column signature for a data source /
// planNode to a string. The column types are printed iff the 2nd
// argument specifies so.
func formatColumns(cols ResultColumns, printTypes bool) string {
	var buf bytes.Buffer
	buf.WriteByte('(')
	for i, rCol := range cols {
		if i > 0 {
			buf.WriteString(", ")
		}
		parser.Name(rCol.Name).Format(&buf, parser.FmtSimple)
		// Output extra properties like [hidden,omitted].
		hasProps := false
		outputProp := func(prop string) {
			if hasProps {
				buf.WriteByte(',')
			} else {
				buf.WriteByte('[')
			}
			hasProps = true
			buf.WriteString(prop)
		}
		if rCol.hidden {
			outputProp("hidden")
		}
		if rCol.omitted {
			outputProp("omitted")
		}
		if hasProps {
			buf.WriteByte(']')
		}

		if printTypes {
			buf.WriteByte(' ')
			buf.WriteString(rCol.Typ.String())
		}
	}
	buf.WriteByte(')')
	return buf.String()
}

// newExplainPlanNode instantiates a planNode that runs an EXPLAIN query.
func (p *planner) makeExplainPlanNode(verbose, expanded bool, plan planNode) planNode {
	columns := ResultColumns{
		{Name: "Level", Typ: parser.TypeInt},
		{Name: "Type", Typ: parser.TypeString},
		{Name: "Description", Typ: parser.TypeString},
	}
	if verbose {
		columns = append(columns, ResultColumn{Name: "Columns", Typ: parser.TypeString})
		columns = append(columns, ResultColumn{Name: "Ordering", Typ: parser.TypeString})
	}

	node := &explainPlanNode{
		explainer: explainer{
			verbose: verbose,
		},
		expanded: expanded,
		plan:     plan,
		results:  p.newContainerValuesNode(columns, 0),
	}
	return node
}

// explainer represents the run-time state of the EXPLAIN logic.
type explainer struct {
	// verbose indicates whether the output has separate columns for the
	// schema signature and ordering information of the intermediate
	// nodes.
	verbose bool

	// level is the current depth in the tree of planNodes.
	level int
}

// populateExplain extracts the information from planNodes to produce
// the EXPLAIN output into a valuesNode.
func (e *explainer) populateExplain(v *valuesNode, plan planNode) error {
	name, description, children := plan.ExplainPlan(e.verbose)

	row := parser.DTuple{
		parser.NewDInt(parser.DInt(e.level)),
		parser.NewDString(name),
		parser.NewDString(description),
	}
	if e.verbose {
		row = append(row, parser.NewDString(formatColumns(plan.Columns(), false)))
		row = append(row, parser.NewDString(plan.Ordering().AsString(plan.Columns())))
	}
	if _, err := v.rows.AddRow(row); err != nil {
		return err
	}

	e.level++
	defer func() { e.level-- }()
	for _, child := range children {
		if err := e.populateExplain(v, child); err != nil {
			return err
		}
	}

	return nil
}

// explainPlanNode implements the logic for EXPLAIN.
type explainPlanNode struct {
	explainer explainer
	expanded  bool
	plan      planNode
	results   *valuesNode
}

func (e *explainPlanNode) ExplainTypes(fn func(string, string)) {}
func (e *explainPlanNode) Next() (bool, error)                  { return e.results.Next() }
func (e *explainPlanNode) Columns() ResultColumns               { return e.results.Columns() }
func (e *explainPlanNode) Ordering() orderingInfo               { return e.results.Ordering() }
func (e *explainPlanNode) Values() parser.DTuple                { return e.results.Values() }
func (e *explainPlanNode) DebugValues() debugValues             { return debugValues{} }
func (e *explainPlanNode) SetLimitHint(n int64, s bool)         { e.results.SetLimitHint(n, s) }
func (e *explainPlanNode) setNeededColumns(_ []bool)            {}
func (e *explainPlanNode) MarkDebug(mode explainMode)           {}
func (e *explainPlanNode) expandPlan() error {
	if e.expanded {
		if err := e.plan.expandPlan(); err != nil {
			return err
		}
		// Trigger limit hint propagation, which would otherwise only occur
		// during the plan's Start() phase. This may trigger additional
		// optimizations (eg. in sortNode) which the user of EXPLAIN will be
		// interested in.
		e.plan.SetLimitHint(math.MaxInt64, true)
	}
	return nil
}
func (e *explainPlanNode) ExplainPlan(v bool) (string, string, []planNode) {
	return "explain", "plan", []planNode{e.plan}
}

func (e *explainPlanNode) Start() error {
	return e.explainer.populateExplain(e.results, e.plan)
}

func (e *explainPlanNode) Close() {
	e.plan.Close()
	e.results.Close()
}
<|endoftext|>


<commit_before>package cache

import (
	"context"
	"math"
	"sync"
	"time"

	"github.com/coredns/coredns/plugin"
	"github.com/coredns/coredns/plugin/metrics"
	"github.com/coredns/coredns/request"

	"github.com/miekg/dns"
	"github.com/prometheus/client_golang/prometheus"
)

// ServeDNS implements the plugin.Handler interface.
func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := request.Request{W: w, Req: r}

	zone := plugin.Zones(c.Zones).Matches(state.Name())
	if zone == "" {
		return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r)
	}

	now := c.now().UTC()

	server := metrics.WithServer(ctx)

	i, ttl := c.get(now, state, server)
	if i != nil && ttl > 0 {
		resp := i.toMsg(r, now)

		state.SizeAndDo(resp)
		resp, _ = state.Scrub(resp)
		w.WriteMsg(resp)

		if c.prefetch > 0 {
			i.Freq.Update(c.duration, now)

			threshold := int(math.Ceil(float64(c.percentage) / 100 * float64(i.origTTL)))
			if i.Freq.Hits() >= c.prefetch && ttl <= threshold {
				cw := newPrefetchResponseWriter(server, state, c)
				go func(w dns.ResponseWriter) {
					cachePrefetches.WithLabelValues(server).Inc()
					plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r)

					// When prefetching we loose the item i, and with it the frequency
					// that we've gathered sofar. See we copy the frequencies info back
					// into the new item that was stored in the cache.
					if i1 := c.exists(state); i1 != nil {
						i1.Freq.Reset(now, i.Freq.Hits())
					}
				}(cw)
			}
		}
		return dns.RcodeSuccess, nil
	}

	crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server}
	return plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r)
}

// Name implements the Handler interface.
func (c *Cache) Name() string { return "cache" }

func (c *Cache) get(now time.Time, state request.Request, server string) (*item, int) {
	k := hash(state.Name(), state.QType(), state.Do())

	if i, ok := c.ncache.Get(k); ok {
		cacheHits.WithLabelValues(server, Denial).Inc()
		return i.(*item), i.(*item).ttl(now)
	}

	if i, ok := c.pcache.Get(k); ok {
		cacheHits.WithLabelValues(server, Success).Inc()
		return i.(*item), i.(*item).ttl(now)
	}
	cacheMisses.WithLabelValues(server).Inc()
	return nil, 0
}

func (c *Cache) exists(state request.Request) *item {
	k := hash(state.Name(), state.QType(), state.Do())
	if i, ok := c.ncache.Get(k); ok {
		return i.(*item)
	}
	if i, ok := c.pcache.Get(k); ok {
		return i.(*item)
	}
	return nil
}

var (
	cacheSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "size",
		Help:      "The number of elements in the cache.",
	}, []string{"server", "type"})

	cacheHits = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "hits_total",
		Help:      "The count of cache hits.",
	}, []string{"server", "type"})

	cacheMisses = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "misses_total",
		Help:      "The count of cache misses.",
	}, []string{"server"})

	cachePrefetches = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "prefetch_total",
		Help:      "The number of time the cache has prefetched a cached item.",
	}, []string{"server"})

	cacheDrops = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "drops_total",
		Help:      "The number responses that are not cached, because the reply is malformed.",
	}, []string{"server"})
)

var once sync.Once
<commit_msg>plugin/cache: Fix: metric `cache miss total`  shall include ttl case (#1897)<commit_after>package cache

import (
	"context"
	"math"
	"sync"
	"time"

	"github.com/coredns/coredns/plugin"
	"github.com/coredns/coredns/plugin/metrics"
	"github.com/coredns/coredns/request"

	"github.com/miekg/dns"
	"github.com/prometheus/client_golang/prometheus"
)

// ServeDNS implements the plugin.Handler interface.
func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := request.Request{W: w, Req: r}

	zone := plugin.Zones(c.Zones).Matches(state.Name())
	if zone == "" {
		return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r)
	}

	now := c.now().UTC()

	server := metrics.WithServer(ctx)

	i, found := c.get(now, state, server)
	if i != nil && found {
		resp := i.toMsg(r, now)

		state.SizeAndDo(resp)
		resp, _ = state.Scrub(resp)
		w.WriteMsg(resp)

		if c.prefetch > 0 {
			ttl := i.ttl(now)
			i.Freq.Update(c.duration, now)

			threshold := int(math.Ceil(float64(c.percentage) / 100 * float64(i.origTTL)))
			if i.Freq.Hits() >= c.prefetch && ttl <= threshold {
				cw := newPrefetchResponseWriter(server, state, c)
				go func(w dns.ResponseWriter) {
					cachePrefetches.WithLabelValues(server).Inc()
					plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r)

					// When prefetching we loose the item i, and with it the frequency
					// that we've gathered sofar. See we copy the frequencies info back
					// into the new item that was stored in the cache.
					if i1 := c.exists(state); i1 != nil {
						i1.Freq.Reset(now, i.Freq.Hits())
					}
				}(cw)
			}
		}
		return dns.RcodeSuccess, nil
	}

	crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server}
	return plugin.NextOrFailure(c.Name(), c.Next, ctx, crr, r)
}

// Name implements the Handler interface.
func (c *Cache) Name() string { return "cache" }

func (c *Cache) get(now time.Time, state request.Request, server string) (*item, bool) {
	k := hash(state.Name(), state.QType(), state.Do())

	if i, ok := c.ncache.Get(k); ok && i.(*item).ttl(now) > 0 {
		cacheHits.WithLabelValues(server, Denial).Inc()
		return i.(*item), true
	}

	if i, ok := c.pcache.Get(k); ok && i.(*item).ttl(now) > 0 {
		cacheHits.WithLabelValues(server, Success).Inc()
		return i.(*item), true
	}
	cacheMisses.WithLabelValues(server).Inc()
	return nil, false
}

func (c *Cache) exists(state request.Request) *item {
	k := hash(state.Name(), state.QType(), state.Do())
	if i, ok := c.ncache.Get(k); ok {
		return i.(*item)
	}
	if i, ok := c.pcache.Get(k); ok {
		return i.(*item)
	}
	return nil
}

var (
	cacheSize = prometheus.NewGaugeVec(prometheus.GaugeOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "size",
		Help:      "The number of elements in the cache.",
	}, []string{"server", "type"})

	cacheHits = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "hits_total",
		Help:      "The count of cache hits.",
	}, []string{"server", "type"})

	cacheMisses = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "misses_total",
		Help:      "The count of cache misses.",
	}, []string{"server"})

	cachePrefetches = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "prefetch_total",
		Help:      "The number of time the cache has prefetched a cached item.",
	}, []string{"server"})

	cacheDrops = prometheus.NewCounterVec(prometheus.CounterOpts{
		Namespace: plugin.Namespace,
		Subsystem: "cache",
		Name:      "drops_total",
		Help:      "The number responses that are not cached, because the reply is malformed.",
	}, []string{"server"})
)

var once sync.Once
<|endoftext|>


<commit_before>// Package old implements a plugin to remember URLs and announce duplicates.
package old

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/StalkR/goircbot/bot"
	"github.com/StalkR/goircbot/lib/duration"
	"github.com/StalkR/goircbot/lib/nohl"
	"github.com/fluffle/goirc/client"
)

var (
	linkRE    = regexp.MustCompile(`(?:^|\s)(https?://[^\s]+)`)
	backlogRE = regexp.MustCompile("<[+%@&~]?[a-zA-Z0-9_`^\\[\\]-]+>")
)

func readURLs(b bot.Bot, line *client.Line, o *Old, ignore map[string]bool) {
	target := line.Args[0]
	if !strings.HasPrefix(target, "#") {
		return
	}
	if _, ignore := ignore[line.Nick]; ignore {
		return
	}
	text := line.Args[1]
	if backlogRE.MatchString(text) {
		return
	}

	matches := linkRE.FindAllStringSubmatch(text, -1)
	if matches == nil {
		return
	}
	for _, submatches := range matches {
		url := submatches[1]
		i, err := o.Old(url)
		if err != nil {
			if err = o.Add(url, target, line.Nick); err != nil {
				log.Print(err)
			}
			return
		}
		ago := duration.Format(time.Since(i.Time))
		nick := nohl.Nick(b, target, i.Nick)
		b.Privmsg(target, fmt.Sprintf("old! first shared by %v %v ago", nick, ago))
	}
}

// Register registers the plugin with a bot.
func Register(b bot.Bot, oldfile string, ignore []string) {
	ignoremap := make(map[string]bool)
	for _, nick := range ignore {
		ignoremap[nick] = true
	}

	o := load(oldfile)

	b.Conn().HandleFunc("privmsg",
		func(conn *client.Conn, line *client.Line) { readURLs(b, line, o, ignoremap) })

	// Every minute, save to file.
	if len(oldfile) > 0 {
		go func() {
			for _ = range time.Tick(time.Minute) {
				save(oldfile, o)
			}
		}()
	}

	// Every day, clean URLs older than a year so it does not grow infinitely.
	go func() {
		for _ = range time.Tick(time.Hour * 24) {
			o.Clean(time.Hour * 24 * 365)
		}
	}()
}
<commit_msg>plugin/old: backlog match space before nick<commit_after>// Package old implements a plugin to remember URLs and announce duplicates.
package old

import (
	"fmt"
	"log"
	"regexp"
	"strings"
	"time"

	"github.com/StalkR/goircbot/bot"
	"github.com/StalkR/goircbot/lib/duration"
	"github.com/StalkR/goircbot/lib/nohl"
	"github.com/fluffle/goirc/client"
)

var (
	linkRE    = regexp.MustCompile(`(?:^|\s)(https?://[^\s]+)`)
	backlogRE = regexp.MustCompile("<[+%@&~ ]?[a-zA-Z0-9_`^\\[\\]-]+>")
)

func readURLs(b bot.Bot, line *client.Line, o *Old, ignore map[string]bool) {
	target := line.Args[0]
	if !strings.HasPrefix(target, "#") {
		return
	}
	if _, ignore := ignore[line.Nick]; ignore {
		return
	}
	text := line.Args[1]
	if backlogRE.MatchString(text) {
		return
	}

	matches := linkRE.FindAllStringSubmatch(text, -1)
	if matches == nil {
		return
	}
	for _, submatches := range matches {
		url := submatches[1]
		i, err := o.Old(url)
		if err != nil {
			if err = o.Add(url, target, line.Nick); err != nil {
				log.Print(err)
			}
			return
		}
		ago := duration.Format(time.Since(i.Time))
		nick := nohl.Nick(b, target, i.Nick)
		b.Privmsg(target, fmt.Sprintf("old! first shared by %v %v ago", nick, ago))
	}
}

// Register registers the plugin with a bot.
func Register(b bot.Bot, oldfile string, ignore []string) {
	ignoremap := make(map[string]bool)
	for _, nick := range ignore {
		ignoremap[nick] = true
	}

	o := load(oldfile)

	b.Conn().HandleFunc("privmsg",
		func(conn *client.Conn, line *client.Line) { readURLs(b, line, o, ignoremap) })

	// Every minute, save to file.
	if len(oldfile) > 0 {
		go func() {
			for _ = range time.Tick(time.Minute) {
				save(oldfile, o)
			}
		}()
	}

	// Every day, clean URLs older than a year so it does not grow infinitely.
	go func() {
		for _ = range time.Tick(time.Hour * 24) {
			o.Clean(time.Hour * 24 * 365)
		}
	}()
}
<|endoftext|>


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

package main

import (
	"bufio"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

var (
	restHost = flag.String("host", "gerrit-review.googlesource.com", "Host to proxy requests to")
	port     = flag.String("port", ":8081", "Port to serve HTTP requests on")
	prod     = flag.Bool("prod", false, "Serve production assets")
	scheme   = flag.String("scheme", "https", "URL scheme")
	plugins  = flag.String("plugins", "", "Path to local plugins folder")
)

func main() {
	flag.Parse()

	if *prod {
		http.Handle("/", http.FileServer(http.Dir("dist")))
	} else {
		http.Handle("/", http.FileServer(http.Dir("app")))
	}

	http.HandleFunc("/changes/", handleRESTProxy)
	http.HandleFunc("/accounts/", handleRESTProxy)
	http.HandleFunc("/config/", handleRESTProxy)
	http.HandleFunc("/projects/", handleRESTProxy)
	http.HandleFunc("/accounts/self/detail", handleAccountDetail)
	if len(*plugins) > 0 {
		http.Handle("/plugins/", http.StripPrefix("/plugins/",
			http.FileServer(http.Dir(*plugins))))
		log.Println("Local plugins from", *plugins)
	}
	log.Println("Serving on port", *port)
	log.Fatal(http.ListenAndServe(*port, &server{}))
}

func handleRESTProxy(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	req := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme:   *scheme,
			Host:     *restHost,
			Opaque:   r.URL.EscapedPath(),
			RawQuery: r.URL.RawQuery,
		},
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()
	w.WriteHeader(res.StatusCode)
	if _, err := io.Copy(w, patchResponse(r, res)); err != nil {
		log.Println("Error copying response to ResponseWriter:", err)
		return
	}
}

func getJsonPropByPath(json map[string]interface{}, path []string) interface{} {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return nil
	}
	switch json[prop].(type) {
	case map[string]interface{}: // map
		return getJsonPropByPath(json[prop].(map[string]interface{}), path)
	case []interface{}: // array
		return json[prop].([]interface{})
	default:
		return json[prop].(interface{})
	}
}

func setJsonPropByPath(json map[string]interface{}, path []string, value interface{}) {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return // path not found
	}
	if len(path) > 0 {
		setJsonPropByPath(json[prop].(map[string]interface{}), path, value)
	} else {
		json[prop] = value
	}
}

func patchResponse(r *http.Request, res *http.Response) io.Reader {
	switch r.URL.EscapedPath() {
	case "/config/server/info":
		return injectLocalPlugins(res.Body)
	default:
		return res.Body
	}
}

func injectLocalPlugins(r io.Reader) io.Reader {
	// Skip escape prefix
	io.CopyN(ioutil.Discard, r, 5)
	dec := json.NewDecoder(r)

	var response map[string]interface{}
	err := dec.Decode(&response)
	if err != nil {
		log.Fatal(err)
	}

	// Configuration path in the JSON server response
	pluginsPath := []string{"plugin", "html_resource_paths"}

	htmlResources := getJsonPropByPath(response, pluginsPath).([]interface{})
	files, err := ioutil.ReadDir(*plugins)
	if err != nil {
		log.Fatal(err)
	}
	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".html") {
			htmlResources = append(htmlResources, "plugins/"+f.Name())
		}
	}
	setJsonPropByPath(response, pluginsPath, htmlResources)

	reader, writer := io.Pipe()
	go func() {
		defer writer.Close()
		io.WriteString(writer, ")]}'") // Write escape prefix
		err := json.NewEncoder(writer).Encode(&response)
		if err != nil {
			log.Fatal(err)
		}
	}()
	return reader
}

func handleAccountDetail(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}

type gzipResponseWriter struct {
	io.WriteCloser
	http.ResponseWriter
}

func newGzipResponseWriter(w http.ResponseWriter) *gzipResponseWriter {
	gz := gzip.NewWriter(w)
	return &gzipResponseWriter{WriteCloser: gz, ResponseWriter: w}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.WriteCloser.Write(b)
}

func (w gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := w.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, errors.New("gzipResponseWriter: ResponseWriter does not satisfy http.Hijacker interface")
	}
	return h.Hijack()
}

type server struct{}

// Any path prefixes that should resolve to index.html.
var (
	fePaths    = []string{"/q/", "/c/", "/dashboard/"}
	issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
)

func (_ *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s\n", r.Proto, r.Method, r.RemoteAddr, r.URL)
	for _, prefix := range fePaths {
		if strings.HasPrefix(r.URL.Path, prefix) {
			r.URL.Path = "/"
			log.Println("Redirecting to /")
			break
		} else if match := issueNumRE.Find([]byte(r.URL.Path)); match != nil {
			r.URL.Path = "/"
			log.Println("Redirecting to /")
			break
		}
	}
	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
		http.DefaultServeMux.ServeHTTP(w, r)
		return
	}
	w.Header().Set("Content-Encoding", "gzip")
	gzw := newGzipResponseWriter(w)
	defer gzw.Close()
	http.DefaultServeMux.ServeHTTP(gzw, r)
}
<commit_msg>Fix server crash when no local plugins provided<commit_after>// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bufio"
	"compress/gzip"
	"encoding/json"
	"errors"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

var (
	restHost = flag.String("host", "gerrit-review.googlesource.com", "Host to proxy requests to")
	port     = flag.String("port", ":8081", "Port to serve HTTP requests on")
	prod     = flag.Bool("prod", false, "Serve production assets")
	scheme   = flag.String("scheme", "https", "URL scheme")
	plugins  = flag.String("plugins", "", "Path to local plugins folder")
)

func main() {
	flag.Parse()

	if *prod {
		http.Handle("/", http.FileServer(http.Dir("dist")))
	} else {
		http.Handle("/", http.FileServer(http.Dir("app")))
	}

	http.HandleFunc("/changes/", handleRESTProxy)
	http.HandleFunc("/accounts/", handleRESTProxy)
	http.HandleFunc("/config/", handleRESTProxy)
	http.HandleFunc("/projects/", handleRESTProxy)
	http.HandleFunc("/accounts/self/detail", handleAccountDetail)
	if len(*plugins) > 0 {
		http.Handle("/plugins/", http.StripPrefix("/plugins/",
			http.FileServer(http.Dir(*plugins))))
		log.Println("Local plugins from", *plugins)
	}
	log.Println("Serving on port", *port)
	log.Fatal(http.ListenAndServe(*port, &server{}))
}

func handleRESTProxy(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	req := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme:   *scheme,
			Host:     *restHost,
			Opaque:   r.URL.EscapedPath(),
			RawQuery: r.URL.RawQuery,
		},
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()
	w.WriteHeader(res.StatusCode)
	if _, err := io.Copy(w, patchResponse(r, res)); err != nil {
		log.Println("Error copying response to ResponseWriter:", err)
		return
	}
}

func getJsonPropByPath(json map[string]interface{}, path []string) interface{} {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return nil
	}
	switch json[prop].(type) {
	case map[string]interface{}: // map
		return getJsonPropByPath(json[prop].(map[string]interface{}), path)
	case []interface{}: // array
		return json[prop].([]interface{})
	default:
		return json[prop].(interface{})
	}
}

func setJsonPropByPath(json map[string]interface{}, path []string, value interface{}) {
	prop, path := path[0], path[1:]
	if json[prop] == nil {
		return // path not found
	}
	if len(path) > 0 {
		setJsonPropByPath(json[prop].(map[string]interface{}), path, value)
	} else {
		json[prop] = value
	}
}

func patchResponse(r *http.Request, res *http.Response) io.Reader {
	switch r.URL.EscapedPath() {
	case "/config/server/info":
		return injectLocalPlugins(res.Body)
	default:
		return res.Body
	}
}

func injectLocalPlugins(r io.Reader) io.Reader {
	if len(*plugins) == 0 {
		return r
	}
	// Skip escape prefix
	io.CopyN(ioutil.Discard, r, 5)
	dec := json.NewDecoder(r)

	var response map[string]interface{}
	err := dec.Decode(&response)
	if err != nil {
		log.Fatal(err)
	}

	// Configuration path in the JSON server response
	pluginsPath := []string{"plugin", "html_resource_paths"}

	htmlResources := getJsonPropByPath(response, pluginsPath).([]interface{})
	files, err := ioutil.ReadDir(*plugins)
	if err != nil {
		log.Fatal(err)
	}
	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".html") {
			htmlResources = append(htmlResources, "plugins/"+f.Name())
		}
	}
	setJsonPropByPath(response, pluginsPath, htmlResources)

	reader, writer := io.Pipe()
	go func() {
		defer writer.Close()
		io.WriteString(writer, ")]}'") // Write escape prefix
		err := json.NewEncoder(writer).Encode(&response)
		if err != nil {
			log.Fatal(err)
		}
	}()
	return reader
}

func handleAccountDetail(w http.ResponseWriter, r *http.Request) {
	http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
}

type gzipResponseWriter struct {
	io.WriteCloser
	http.ResponseWriter
}

func newGzipResponseWriter(w http.ResponseWriter) *gzipResponseWriter {
	gz := gzip.NewWriter(w)
	return &gzipResponseWriter{WriteCloser: gz, ResponseWriter: w}
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.WriteCloser.Write(b)
}

func (w gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	h, ok := w.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, errors.New("gzipResponseWriter: ResponseWriter does not satisfy http.Hijacker interface")
	}
	return h.Hijack()
}

type server struct{}

// Any path prefixes that should resolve to index.html.
var (
	fePaths    = []string{"/q/", "/c/", "/dashboard/"}
	issueNumRE = regexp.MustCompile(`^\/\d+\/?$`)
)

func (_ *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s\n", r.Proto, r.Method, r.RemoteAddr, r.URL)
	for _, prefix := range fePaths {
		if strings.HasPrefix(r.URL.Path, prefix) {
			r.URL.Path = "/"
			log.Println("Redirecting to /")
			break
		} else if match := issueNumRE.Find([]byte(r.URL.Path)); match != nil {
			r.URL.Path = "/"
			log.Println("Redirecting to /")
			break
		}
	}
	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
		http.DefaultServeMux.ServeHTTP(w, r)
		return
	}
	w.Header().Set("Content-Encoding", "gzip")
	gzw := newGzipResponseWriter(w)
	defer gzw.Close()
	http.DefaultServeMux.ServeHTTP(gzw, r)
}
<|endoftext|>


<commit_before>package process

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

func LoadProcessTree(pid int) (*Process, error) {
	proc, err := os.FindProcess(pid)
	if err != nil {
		return nil, err
	}
	wrapped := &Process{Process: proc}
	if err = wrapped.LoadChildren(); err != nil {
		return nil, err
	}
	return wrapped, nil
}

type Process struct {
	Process  *os.Process
	Children []*Process
}

func (p *Process) String() string {
	jsonBytes, err := json.MarshalIndent(p, "", "  ")
	if err != nil {
		//Use plain formatting
		return fmt.Sprintf("Pid: %d, Children:\n  %+v", p.Process.Pid, p.Children)
	}
	return string(jsonBytes)
}

type commandXml struct {
	Results []struct {
		Properties []struct {
			Name  string `xml:"NAME,attr"`
			Value string `xml:"VALUE"`
		} `xml:"PROPERTY"`
	} `xml:"RESULTS>CIM>INSTANCE"`
}

func (p *Process) processXml(xmlData []byte, columnNames []string) (*commandXml, error) {
	c := &commandXml{}
	if err := xml.Unmarshal(xmlData, c); err != nil {
		return nil, fmt.Errorf("Cannot unmarshal command xml, error: %s. Xml was: %s", err.Error(), string(xmlData))
	}
	return c, nil
}

func (p *Process) LoadChildren() error {
	columnNames := []string{
		"Caption",
		"ProcessId",
	}

	out, err := exec.Command(
		"wmic",
		"process",
		"where",
		fmt.Sprintf("(ParentProcessId=%d)", p.Process.Pid),
		"get",
		strings.Join(columnNames, ","),
		"/FORMAT:RAWXML",
	).CombinedOutput()

	if err != nil {
		return fmt.Errorf("Cannot find child processes. Error: %s. OUTPUT: %s", err.Error(), string(out))
	}

	outStrTrimmed := strings.TrimSpace(string(out))
	if outStrTrimmed == "" {
		return fmt.Errorf("Command returned empty response, cannot parse xml")
	}
	if !strings.HasPrefix(outStrTrimmed, "<") {
		if strings.HasPrefix(outStrTrimmed, "No Instance(s) Available") {
			//In this case the process does not have children processes
			return nil
		}
		return fmt.Errorf("Invalid xml returned from wmic command, xml was: %s", outStrTrimmed)
	}

	x, err := p.processXml(out, columnNames)
	if err != nil {
		return fmt.Errorf("Unable to process xml, error: %s. Xml was: %s", err.Error(), string(out))
	}

	for _, res := range x.Results {
		var childProcId int64
		for _, prop := range res.Properties {
			if prop.Name == "ProcessId" {
				childProcId, err = strconv.ParseInt(prop.Value, 10, 32)
				if err != nil {
					return fmt.Errorf("Got process ID from wmic of '%s' but is invalid int, error: %s", prop.Value, err.Error())
				}
			}
		}

		if childProcId > 0 {
			childProc, err := os.FindProcess(int(childProcId))
			if err != nil {
				return fmt.Errorf("Cannot get os Process for process id %d (parent was %d), error: %s", childProcId, p.Process.Pid, err.Error())
			}
			wrappedChildProc := &Process{Process: childProc}

			if err = wrappedChildProc.LoadChildren(); err != nil {
				return fmt.Errorf("Cannot get child processes of pid %d, error: %s", p.Process.Pid, err.Error())
			}
			p.Children = append(p.Children, wrappedChildProc)
		}
	}

	return nil
}
<commit_msg>Stripped the WMIC and its response xml logic into `https://github.com/go-zero-boilerplate/wmic-xml-command`.<commit_after>package process

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/go-zero-boilerplate/wmic-xml-command"
)

func LoadProcessTree(pid int) (*Process, error) {
	proc, err := os.FindProcess(pid)
	if err != nil {
		return nil, err
	}
	wrapped := &Process{Process: proc}
	if err = wrapped.LoadChildren(); err != nil {
		return nil, err
	}
	return wrapped, nil
}

type Process struct {
	Process  *os.Process
	Children []*Process
}

func (p *Process) String() string {
	jsonBytes, err := json.MarshalIndent(p, "", "  ")
	if err != nil {
		//Use plain formatting
		return fmt.Sprintf("Pid: %d, Children:\n  %+v", p.Process.Pid, p.Children)
	}
	return string(jsonBytes)
}

func (p *Process) LoadChildren() error {
	columnNames := []string{
		"Caption",
		"ProcessId",
	}

	wmicArgs := []string{
		"process",
		"where",
		fmt.Sprintf("(ParentProcessId=%d)", p.Process.Pid),
		"get",
		strings.Join(columnNames, ","),
	}

	responseXml, err := wmic_command.Run(wmicArgs)
	if err != nil {
		parseErr, ok := err.(*wmic_command.XmlParseError)
		if !ok {
			return fmt.Errorf("Cannot find child processes. Error: %s", err.Error())
		}

		xmlTrimmed := strings.TrimSpace(string(parseErr.XmlContent))
		if xmlTrimmed == "" {
			return fmt.Errorf("Command returned empty response, cannot parse xml")
		}
		if !strings.HasPrefix(xmlTrimmed, "<") {
			if strings.HasPrefix(xmlTrimmed, "No Instance(s) Available") {
				//In this case the process does not have children processes
				return nil
			}
			return fmt.Errorf("Invalid xml returned from wmic command, xml was: %s", xmlTrimmed)
		}
	}

	for _, res := range responseXml.Results {
		var childProcId int64
		for _, prop := range res.Properties {
			if prop.Name == "ProcessId" {
				childProcId, err = strconv.ParseInt(prop.Value, 10, 32)
				if err != nil {
					return fmt.Errorf("Got process ID from wmic of '%s' but is invalid int, error: %s", prop.Value, err.Error())
				}
			}
		}

		if childProcId > 0 {
			childProc, err := os.FindProcess(int(childProcId))
			if err != nil {
				return fmt.Errorf("Cannot get os Process for process id %d (parent was %d), error: %s", childProcId, p.Process.Pid, err.Error())
			}
			wrappedChildProc := &Process{Process: childProc}

			if err = wrappedChildProc.LoadChildren(); err != nil {
				return fmt.Errorf("Cannot get child processes of pid %d, error: %s", p.Process.Pid, err.Error())
			}
			p.Children = append(p.Children, wrappedChildProc)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package storage

import (
	"database/sql"
	"strconv"
	"strings"
	"unicode"

	"github.com/juju/errors"
)

var (
	ErrUserDoesNotExist = errors.New("user does not exist")
	ErrTagDoesNotExist  = errors.New("tag does not exist")
	ErrTagNameInvalid   = errors.New("sorry, but tag names can't look like numbers, can't contain commas and spaces")
)

type TaggableType string

const (
	TaggableTypeBookmark TaggableType = "bookmark"
)

// TaggingMode is used for GetTaggings(), SetTaggings: specifies whether given
// argument/returned value should contain all tags (including all supertags),
// or leafs only.
type TaggingMode int

const (
	TaggingModeAll TaggingMode = iota
	TaggingModeLeafs
)

// Either ID or Username should be given.
type GetUserArgs struct {
	ID       *int
	Username *string
}

type UserData struct {
	ID       int
	Username string
	Password string
	Email    string
}

type TagData struct {
	ID          int
	OwnerID     int
	ParentTagID int
	Description string
	Names       []string
	Subtags     []TagData
}

type GetTagOpts struct {
	GetNames   bool
	GetSubtags bool
}

type TaggableData struct {
	ID        int
	OwnerID   int
	Type      TaggableType
	CreatedAt uint64
	UpdatedAt uint64
}

type BookmarkData struct {
	// We don't embedding TaggableData here since we don't want Type to be here
	ID        int
	OwnerID   int
	CreatedAt uint64
	UpdatedAt uint64
	URL       string
	Comment   string
}

type Storage interface {
	//-- Common
	Connect() error
	ApplyMigrations() error
	Tx(fn func(*sql.Tx) error) error
	//-- Users
	GetUser(tx *sql.Tx, args *GetUserArgs) (*UserData, error)
	CreateUser(tx *sql.Tx, ud *UserData) (userID int, err error)
	//-- Tags
	CreateTag(tx *sql.Tx, td *TagData) (tagID int, err error)
	GetTagIDByPath(tx *sql.Tx, ownerID int, tagPath string) (int, error)
	GetTagIDByName(tx *sql.Tx, parentTagID int, tagName string) (int, error)
	GetRootTagID(tx *sql.Tx, ownerID int) (int, error)
	GetTag(tx *sql.Tx, tagID int, opts *GetTagOpts) (*TagData, error)
	GetTags(
		tx *sql.Tx, parentTagID int, opts *GetTagOpts,
	) ([]TagData, error)
	GetTagNames(tx *sql.Tx, tagID int) ([]string, error)
	//-- Taggables (bookmarks)
	CreateTaggable(tx *sql.Tx, tgbd *TaggableData) (tgbID int, err error)
	CreateBookmark(tx *sql.Tx, bd *BookmarkData) (bkmID int, err error)
	GetTaggedTaggableIDs(
		tx *sql.Tx, tagIDs []int, ownerID *int, ttype *TaggableType,
	) (taggableIDs []int, err error)
	//-- Taggings
	GetTaggings(
		tx *sql.Tx, taggableID int, tm TaggingMode,
	) (tagIDs []int, err error)
	SetTaggings(
		tx *sql.Tx, taggableID int, tagIDs []int, tm TaggingMode,
	) error
}

func ValidateTagName(name string) error {
	// Tag can't look like numbers, because when we get a request which looks
	// like a number, we assume it's a tag id
	_, err := strconv.Atoi(name)
	if err == nil {
		return errors.Annotatef(ErrTagNameInvalid, "%s", name)
	}

	if strings.Contains(name, ",") ||
		strings.Contains(name, "|") || strings.Contains(name, "/") ||
		strings.Contains(name, "~") || strings.Contains(name, "=") ||
		strings.Contains(name, "'") ||
		strings.Contains(name, " ") || strings.Contains(name, "\t") ||
		!isPrintable(name) {
		return errors.Annotatef(ErrTagNameInvalid, "%s", name)
	}

	return nil
}

// checks if s is ascii and printable, aka doesn't include tab, backspace, etc.
func isPrintable(s string) bool {
	for _, r := range s {
		if !unicode.IsPrint(r) {
			return false
		}
	}
	return true
}
<commit_msg>Little formatting change<commit_after>package storage

import (
	"database/sql"
	"strconv"
	"strings"
	"unicode"

	"github.com/juju/errors"
)

var (
	ErrUserDoesNotExist = errors.New("user does not exist")
	ErrTagDoesNotExist  = errors.New("tag does not exist")
	ErrTagNameInvalid   = errors.New("sorry, but tag names can't look like numbers, can't contain commas and spaces")
)

type TaggableType string

const (
	TaggableTypeBookmark TaggableType = "bookmark"
)

// TaggingMode is used for GetTaggings(), SetTaggings: specifies whether given
// argument/returned value should contain all tags (including all supertags),
// or leafs only.
type TaggingMode int

const (
	TaggingModeAll TaggingMode = iota
	TaggingModeLeafs
)

// Either ID or Username should be given.
type GetUserArgs struct {
	ID       *int
	Username *string
}

type UserData struct {
	ID       int
	Username string
	Password string
	Email    string
}

type TagData struct {
	ID          int
	OwnerID     int
	ParentTagID int
	Description string
	Names       []string
	Subtags     []TagData
}

type GetTagOpts struct {
	GetNames   bool
	GetSubtags bool
}

type TaggableData struct {
	ID        int
	OwnerID   int
	Type      TaggableType
	CreatedAt uint64
	UpdatedAt uint64
}

type BookmarkData struct {
	// We don't embed TaggableData here since we don't want Type to be here
	ID        int
	OwnerID   int
	CreatedAt uint64
	UpdatedAt uint64
	URL       string
	Comment   string
}

type Storage interface {
	//-- Common
	Connect() error
	ApplyMigrations() error
	Tx(fn func(*sql.Tx) error) error

	//-- Users
	GetUser(tx *sql.Tx, args *GetUserArgs) (*UserData, error)
	CreateUser(tx *sql.Tx, ud *UserData) (userID int, err error)

	//-- Tags
	CreateTag(tx *sql.Tx, td *TagData) (tagID int, err error)
	GetTagIDByPath(tx *sql.Tx, ownerID int, tagPath string) (int, error)
	GetTagIDByName(tx *sql.Tx, parentTagID int, tagName string) (int, error)
	GetRootTagID(tx *sql.Tx, ownerID int) (int, error)
	GetTag(tx *sql.Tx, tagID int, opts *GetTagOpts) (*TagData, error)
	GetTags(
		tx *sql.Tx, parentTagID int, opts *GetTagOpts,
	) ([]TagData, error)
	GetTagNames(tx *sql.Tx, tagID int) ([]string, error)

	//-- Taggables (bookmarks)
	CreateTaggable(tx *sql.Tx, tgbd *TaggableData) (tgbID int, err error)
	CreateBookmark(tx *sql.Tx, bd *BookmarkData) (bkmID int, err error)
	GetTaggedTaggableIDs(
		tx *sql.Tx, tagIDs []int, ownerID *int, ttype *TaggableType,
	) (taggableIDs []int, err error)

	//-- Taggings
	GetTaggings(
		tx *sql.Tx, taggableID int, tm TaggingMode,
	) (tagIDs []int, err error)
	SetTaggings(
		tx *sql.Tx, taggableID int, tagIDs []int, tm TaggingMode,
	) error
}

func ValidateTagName(name string) error {
	// Tag can't look like numbers, because when we get a request which looks
	// like a number, we assume it's a tag id
	_, err := strconv.Atoi(name)
	if err == nil {
		return errors.Annotatef(ErrTagNameInvalid, "%s", name)
	}

	if strings.Contains(name, ",") ||
		strings.Contains(name, "|") || strings.Contains(name, "/") ||
		strings.Contains(name, "~") || strings.Contains(name, "=") ||
		strings.Contains(name, "'") ||
		strings.Contains(name, " ") || strings.Contains(name, "\t") ||
		!isPrintable(name) {
		return errors.Annotatef(ErrTagNameInvalid, "%s", name)
	}

	return nil
}

// checks if s is ascii and printable, aka doesn't include tab, backspace, etc.
func isPrintable(s string) bool {
	for _, r := range s {
		if !unicode.IsPrint(r) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>/**
* deps - dependency management utility for Linux executables
 */
package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

type dependency struct {
	Name string
	Path string
	Addr string
}

func getDeps(lddOutput string) []dependency {
	lines := strings.Split(lddOutput, "\n")
	depsCount := len(lines) - 1
	deps := make([]dependency, depsCount)

	for i, l := range lines {
		dep := strings.Split(l, " ")

		// ldd has a little weird output:
		// 1) name => path (addr)
		//    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb753d000)
		// 2) path (addr)
		//    /lib/ld-linux.so.2 (0xb7746000)
		// 3) and a strange (this is VDSO provided by kernel, no need to copy it):
		//     linux-gate.so.1 =>  (0xb7745000)
		// so handle different types of it

		switch {
		case len(dep) > 3: // case 1
			deps[i].Name = strings.TrimSpace(dep[0])
			deps[i].Path = strings.TrimSpace(dep[2])
			deps[i].Addr = strings.TrimSpace(dep[3])
		case len(dep) > 1: // case 2
			idx := strings.LastIndex(dep[0], "/")
			deps[i].Name = strings.TrimSpace(string(dep[0][idx+1:]))
			deps[i].Path = strings.TrimSpace(dep[0])
			deps[i].Addr = strings.TrimSpace(dep[1])
		}
	}

	return deps
}

var visitedDeps map[string]bool

func walkDeps(path, dir string) error {
	// Do not walk among visited paths,
	// or else the recursion will be infinite
	if _, ok := visitedDeps[path]; ok {
		fmt.Printf("! %s already copied\n", path)
		return nil
	}

	// Check this path as visited
	visitedDeps[path] = true

	// Get dependency list by executing ldd
	ldd := exec.Command("ldd", path)
	var lddOut bytes.Buffer
	ldd.Stdout = &lddOut
	ldd.Run()

	// Parse ldd's output
	deps := getDeps(lddOut.String())

	// Walk through new dependencies recursively to gather them all
	for _, d := range deps {
		fmt.Printf("-Dependency:\n  name: %s\n  path: %s\n  addr: %s\n", d.Name, d.Path, d.Addr)

		cp := exec.Command("cp", "--parent", d.Path, dir)
		cp.Run()

		if err := walkDeps(d.Path, dir); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("Usage: deps EXECUTABLE PATH\nGather dependencies of an executable")
		return
	}

	what := os.Args[1]
	whereToCopy := os.Args[2]

	if err := os.Mkdir(whereToCopy, 0777); err != nil {
		panic("Could not create output directory - " + err.Error())
	}

	visitedDeps = make(map[string]bool)
	if err := walkDeps(what, whereToCopy); err != nil {
		panic("An error has occured while gathering dependencies - " + err.Error())
	}

	fmt.Println("Finished!")
}
<commit_msg>First step to 'providers' implementation. Added type GetDepsFunc<commit_after>/**
* deps - dependency management utility for Linux executables
 */
package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

type dependency struct {
	Name string
	Path string
	Addr string
}

type GetDepsFunc func(lddOutput string) []dependency

func getDependencies(lddOutput string) []dependency {
	lines := strings.Split(lddOutput, "\n")
	depsCount := len(lines) - 1
	deps := make([]dependency, depsCount)

	for i, l := range lines {
		dep := strings.Split(l, " ")

		// ldd has a little weird output:
		// 1) name => path (addr)
		//    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb753d000)
		// 2) path (addr)
		//    /lib/ld-linux.so.2 (0xb7746000)
		// 3) and a strange (this is VDSO provided by kernel, no need to copy it):
		//     linux-gate.so.1 =>  (0xb7745000)
		// so handle different types of it

		switch {
		case len(dep) > 3: // case 1
			deps[i].Name = strings.TrimSpace(dep[0])
			deps[i].Path = strings.TrimSpace(dep[2])
			deps[i].Addr = strings.TrimSpace(dep[3])
		case len(dep) > 1: // case 2
			idx := strings.LastIndex(dep[0], "/")
			deps[i].Name = strings.TrimSpace(string(dep[0][idx+1:]))
			deps[i].Path = strings.TrimSpace(dep[0])
			deps[i].Addr = strings.TrimSpace(dep[1])
		}
	}

	return deps
}

var visitedDeps map[string]bool

func walkDeps(path, dir string, getDeps GetDepsFunc) error {
	// Do not walk among visited paths,
	// or else the recursion will be infinite
	if _, ok := visitedDeps[path]; ok {
		fmt.Printf("! %s already copied\n", path)
		return nil
	}

	// Check this path as visited
	visitedDeps[path] = true

	// Get dependency list by executing ldd
	ldd := exec.Command("ldd", path)
	var lddOut bytes.Buffer
	ldd.Stdout = &lddOut
	ldd.Run()

	// Parse ldd's output
	deps := getDeps(lddOut.String())

	// Walk through new dependencies recursively to gather them all
	for _, d := range deps {
		fmt.Printf("-Dependency:\n  name: %s\n  path: %s\n  addr: %s\n", d.Name, d.Path, d.Addr)

		cp := exec.Command("cp", "--parent", d.Path, dir)
		cp.Run()

		if err := walkDeps(d.Path, dir, getDeps); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	if len(os.Args) < 3 {
		fmt.Println("Usage: deps EXECUTABLE PATH\nGather dependencies of an executable")
		return
	}

	what := os.Args[1]
	whereToCopy := os.Args[2]

	if err := os.Mkdir(whereToCopy, 0777); err != nil {
		panic("Could not create output directory - " + err.Error())
	}

	visitedDeps = make(map[string]bool)
	if err := walkDeps(what, whereToCopy, getDependencies); err != nil {
		panic("An error has occured while gathering dependencies - " + err.Error())
	}

	fmt.Println("Finished!")
}
<|endoftext|>


<commit_before>package grohl

import (
	"fmt"
	"strings"
	"testing"
	"time"
)

func TestContext(t *testing.T) {
	empty := NewContext(nil)

	empty.Add("a", 1)
	empty.Add("b", 1)

	merged := empty.Merge(Data{"b": 2, "c": 3})

	expected := "a=1 b=2 c=3"
	if log := BuildLog(merged, false); log != expected {
		t.Errorf("Expected: %s\nActual: %s", expected, log)
	}
}

var exampleTime = time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC)
var exampleError = fmt.Errorf("error message")

var examples = map[string]Data{
	"fn=string test=hi": Data{
		"fn": "string", "test": "hi",
	},
	`fn=stringspace test="a b"`: Data{
		"fn": "stringspace", "test": "a b",
	},
	`fn=stringslasher test="slasher \\\\"`: Data{
		"fn": "stringslasher", "test": `slasher \\`,
	},
	`fn=stringeqspace test="x=4, y=10"`: Data{
		"fn": "stringeqspace", "test": "x=4, y=10",
	},
	`fn=stringeq test="x=4,y=10"`: Data{
		"fn": "stringeq", "test": "x=4,y=10",
	},
	`fn=stringspace test="hello world"`: Data{
		"fn": "stringspace", "test": "hello world",
	},
	`fn=stringbothquotes test="echo 'hello' \"world\""`: Data{
		"fn": "stringbothquotes", "test": `echo 'hello' "world"`,
	},
	`fn=stringsinglequotes test="a 'a'"`: Data{
		"fn": "stringsinglequotes", "test": `a 'a'`,
	},
	`fn=stringdoublequotes test='echo "hello"'`: Data{
		"fn": "stringdoublequotes", "test": `echo "hello"`,
	},
	`fn=stringbothquotesnospace test='a"`: Data{
		"fn": "stringbothquotesnospace", "test": `'a"`,
	},
	"fn=emptystring test=nil": Data{
		"fn": "emptystring", "test": "",
	},
	"fn=int test=1": Data{
		"fn": "int", "test": int(1),
	},
	"fn=int8 test=1": Data{
		"fn": "int8", "test": int8(1),
	},
	"fn=int16 test=1": Data{
		"fn": "int16", "test": int16(1),
	},
	"fn=int32 test=1": Data{
		"fn": "int32", "test": int32(1),
	},
	"fn=int64 test=1": Data{
		"fn": "int64", "test": int64(1),
	},
	"fn=uint test=1": Data{
		"fn": "uint", "test": uint(1),
	},
	"fn=uint8 test=1": Data{
		"fn": "uint8", "test": uint8(1),
	},
	"fn=uint16 test=1": Data{
		"fn": "uint16", "test": uint16(1),
	},
	"fn=uint32 test=1": Data{
		"fn": "uint32", "test": uint32(1),
	},
	"fn=uint64 test=1": Data{
		"fn": "uint64", "test": uint64(1),
	},
	"fn=float test=1.000": Data{
		"fn": "float", "test": float32(1.0),
	},
	"fn=bool test=true": Data{
		"fn": "bool", "test": true,
	},
	"fn=nil test=nil": Data{
		"fn": "nil", "test": nil,
	},
	"fn=time test=2000-01-02T03:04:05+0000": Data{
		"fn": "time", "test": exampleTime,
	},
	`fn=error test="error message"`: Data{
		"fn": "error", "test": exampleError,
	},
}

func TestFormat(t *testing.T) {
	for expected, data := range examples {
		if actual := BuildLog(data, false); expected != actual {
			t.Errorf("Expected %s\nGot: %s", expected, actual)
		}
	}
}

func TestFormatWithTime(t *testing.T) {
	data := Data{"fn": "time", "test": 1}
	actual := BuildLog(data, true)
	if !strings.HasPrefix(actual, "now=") {
		t.Errorf("Invalid prefix: %s", actual)
	}
	if !strings.HasSuffix(actual, " fn=time test=1") {
		t.Errorf("Invalid suffix: %s", actual)
	}
}
<commit_msg>put format tests in format_test<commit_after>package grohl

import (
	"testing"
)

func TestContext(t *testing.T) {
	empty := NewContext(nil)

	empty.Add("a", 1)
	empty.Add("b", 1)

	merged := empty.Merge(Data{"b": 2, "c": 3})

	expected := "a=1 b=2 c=3"
	if log := BuildLog(merged, false); log != expected {
		t.Errorf("Expected: %s\nActual: %s", expected, log)
	}
}
<|endoftext|>


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

package service_test

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/exec"
	"github.com/juju/utils/featureflag"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/feature"
	"github.com/juju/juju/juju/osenv"
	"github.com/juju/juju/service"
	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var maybeSystemd = service.InitSystemSystemd

func init() {
	if featureflag.Enabled(feature.LegacyUpstart) {
		maybeSystemd = service.InitSystemUpstart
	}
}

const unknownExecutable = "/sbin/unknown/init/system"

type discoveryTest struct {
	os       version.OSType
	series   string
	expected string
}

func (dt discoveryTest) version() version.Binary {
	return version.Binary{
		OS:     dt.os,
		Series: dt.series,
	}
}

func (dt discoveryTest) log(c *gc.C) {
	c.Logf(" - testing {%q, %q}...", dt.os, dt.series)
}

func (dt discoveryTest) disableLocalDiscovery(c *gc.C, s *discoverySuite) {
	s.PatchLocalDiscoveryDisable()
}

func (dt discoveryTest) disableVersionDiscovery(s *discoverySuite) {
	s.PatchVersion(version.Binary{
		OS: version.Unknown,
	})
}

func (dt discoveryTest) setLocal(c *gc.C, s *discoverySuite) {
	s.PatchLocalDiscoveryNoMatch(dt.expected)
}

func (dt discoveryTest) setVersion(s *discoverySuite) version.Binary {
	vers := dt.version()
	s.PatchVersion(vers)
	return vers
}

func (dt discoveryTest) checkService(c *gc.C, svc service.Service, err error, name string, conf common.Conf) {
	if dt.expected == "" {
		c.Check(err, jc.Satisfies, errors.IsNotFound)
		return
	}

	// Check the success case.
	if !c.Check(err, jc.ErrorIsNil) {
		return
	}
	switch dt.expected {
	case service.InitSystemUpstart:
		c.Check(svc, gc.FitsTypeOf, &upstart.Service{})
	case service.InitSystemSystemd:
		c.Check(svc, gc.FitsTypeOf, &systemd.Service{})
	case service.InitSystemWindows:
		c.Check(svc, gc.FitsTypeOf, &windows.Service{})
	default:
		c.Errorf("unknown expected init system %q", dt.expected)
		return
	}
	if svc == nil {
		return
	}

	c.Check(svc.Name(), gc.Equals, name)
	c.Check(svc.Conf(), jc.DeepEquals, conf)
}

func (dt discoveryTest) checkInitSystem(c *gc.C, name string, ok bool) {
	if dt.expected == "" {
		if !c.Check(ok, jc.IsFalse) {
			c.Logf("found init system %q", name)
		}
	} else {
		c.Check(ok, jc.IsTrue)
		c.Check(name, gc.Equals, dt.expected)
	}
}

var discoveryTests = []discoveryTest{{
	os:       version.Windows,
	expected: service.InitSystemWindows,
}, {
	os:       version.Ubuntu,
	series:   "oneiric",
	expected: "",
}, {
	os:       version.Ubuntu,
	series:   "precise",
	expected: service.InitSystemUpstart,
}, {
	os:       version.Ubuntu,
	series:   "utopic",
	expected: service.InitSystemUpstart,
}, {
	os:       version.Ubuntu,
	series:   "vivid",
	expected: maybeSystemd,
}, {
	os:       version.CentOS,
	series:   "centos7",
	expected: service.InitSystemSystemd,
}, {
	os:       version.Unknown,
	expected: "",
}}

type discoverySuite struct {
	service.BaseSuite

	name string
	conf common.Conf
}

var _ = gc.Suite(&discoverySuite{})

func (s *discoverySuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	s.name = "a-service"
	s.conf = common.Conf{
		Desc:      "some service",
		ExecStart: "/path/to/some-command",
	}
}

func (s *discoverySuite) unsetLegacyUpstart(c *gc.C) {
	err := os.Setenv(osenv.JujuFeatureFlagEnvKey, "")
	c.Assert(err, jc.ErrorIsNil)
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

func (s *discoverySuite) setLegacyUpstart(c *gc.C) {
	err := os.Setenv(osenv.JujuFeatureFlagEnvKey, feature.LegacyUpstart)
	c.Assert(err, jc.ErrorIsNil)
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

func (s *discoverySuite) TestDiscoverServiceLocalHost(c *gc.C) {
	var localInitSystem string
	switch runtime.GOOS {
	case "windows":
		localInitSystem = service.InitSystemWindows
	case "linux":
		localInitSystem, _ = service.VersionInitSystem(version.Current)
	}
	test := discoveryTest{
		os:       version.Current.OS,
		series:   version.Current.Series,
		expected: localInitSystem,
	}
	test.disableVersionDiscovery(s)

	svc, err := service.DiscoverService(s.name, s.conf)
	c.Assert(err, jc.ErrorIsNil)

	test.checkService(c, svc, err, s.name, s.conf)
}

func (s *discoverySuite) TestDiscoverServiceLocalOnly(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		test.setLocal(c, s)
		test.disableVersionDiscovery(s)

		svc, err := service.DiscoverService(s.name, s.conf)

		test.checkService(c, svc, err, s.name, s.conf)
	}
}

func (s *discoverySuite) TestDiscoverServiceVersionFallback(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		test.disableLocalDiscovery(c, s)
		test.setVersion(s)

		svc, err := service.DiscoverService(s.name, s.conf)

		test.checkService(c, svc, err, s.name, s.conf)
	}
}

func (s *discoverySuite) TestVersionInitSystem(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		vers := test.setVersion(s)

		initSystem, ok := service.VersionInitSystem(vers)

		test.checkInitSystem(c, initSystem, ok)
	}
}

func (s *discoverySuite) TestVersionInitSystemLegacyUpstart(c *gc.C) {
	s.setLegacyUpstart(c)
	test := discoveryTest{
		os:       version.Ubuntu,
		series:   "vivid",
		expected: service.InitSystemUpstart,
	}
	vers := test.setVersion(s)

	initSystem, ok := service.VersionInitSystem(vers)

	test.checkInitSystem(c, initSystem, ok)
}

func (s *discoverySuite) TestVersionInitSystemNoLegacyUpstart(c *gc.C) {
	s.unsetLegacyUpstart(c)
	test := discoveryTest{
		os:       version.Ubuntu,
		series:   "vivid",
		expected: service.InitSystemSystemd,
	}
	vers := test.setVersion(s)

	initSystem, ok := service.VersionInitSystem(vers)

	test.checkInitSystem(c, initSystem, ok)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirst(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", true, nil),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initA")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorFirst(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failure),
		service.NewDiscoveryCheck("initB", true, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initB")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirstError(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", true, failure),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initA")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchSecond(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, nil),
		service.NewDiscoveryCheck("initB", true, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initB")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchNone(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, nil),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorMixed(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failure),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorAll(c *gc.C) {
	failureA := errors.New("<failed A>")
	failureB := errors.New("<failed B>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failureA),
		service.NewDiscoveryCheck("initB", false, failureB),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverInitSystemScript(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	script, filename := s.newDiscoverInitSystemScript(c)
	script += filename
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}

func (s *discoverySuite) newDiscoverInitSystemScript(c *gc.C) (string, string) {
	filename := filepath.Join(c.MkDir(), "discover_init_system.sh")
	commands := []string{
		fmt.Sprintf(`
cat > %s << 'EOF'
%s
EOF`[1:], filename, service.DiscoverInitSystemScript()),
		"chmod 0755 " + filename,
	}
	script := strings.Join(commands, "\n") + "\n"
	return script, filename
}

func (s *discoverySuite) TestNewShellSelectCommand(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	script, filename := s.newDiscoverInitSystemScript(c)
	handler := func(initSystem string) (string, bool) {
		return "echo -n " + initSystem, true
	}
	script += "init_system=$(" + filename + ")\n"
	// The script will fail with exit 1 if it cannot match in init system.
	script += service.NewShellSelectCommand("init_system", "exit 1", handler)
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}
<commit_msg>Add a test for posix shells (e.g. dash, bourne).<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package service_test

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	"github.com/juju/utils/exec"
	"github.com/juju/utils/featureflag"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/feature"
	"github.com/juju/juju/juju/osenv"
	"github.com/juju/juju/service"
	"github.com/juju/juju/service/common"
	"github.com/juju/juju/service/systemd"
	"github.com/juju/juju/service/upstart"
	"github.com/juju/juju/service/windows"
	"github.com/juju/juju/version"
)

var maybeSystemd = service.InitSystemSystemd

func init() {
	if featureflag.Enabled(feature.LegacyUpstart) {
		maybeSystemd = service.InitSystemUpstart
	}
}

const unknownExecutable = "/sbin/unknown/init/system"

type discoveryTest struct {
	os       version.OSType
	series   string
	expected string
}

func (dt discoveryTest) version() version.Binary {
	return version.Binary{
		OS:     dt.os,
		Series: dt.series,
	}
}

func (dt discoveryTest) log(c *gc.C) {
	c.Logf(" - testing {%q, %q}...", dt.os, dt.series)
}

func (dt discoveryTest) disableLocalDiscovery(c *gc.C, s *discoverySuite) {
	s.PatchLocalDiscoveryDisable()
}

func (dt discoveryTest) disableVersionDiscovery(s *discoverySuite) {
	s.PatchVersion(version.Binary{
		OS: version.Unknown,
	})
}

func (dt discoveryTest) setLocal(c *gc.C, s *discoverySuite) {
	s.PatchLocalDiscoveryNoMatch(dt.expected)
}

func (dt discoveryTest) setVersion(s *discoverySuite) version.Binary {
	vers := dt.version()
	s.PatchVersion(vers)
	return vers
}

func (dt discoveryTest) checkService(c *gc.C, svc service.Service, err error, name string, conf common.Conf) {
	if dt.expected == "" {
		c.Check(err, jc.Satisfies, errors.IsNotFound)
		return
	}

	// Check the success case.
	if !c.Check(err, jc.ErrorIsNil) {
		return
	}
	switch dt.expected {
	case service.InitSystemUpstart:
		c.Check(svc, gc.FitsTypeOf, &upstart.Service{})
	case service.InitSystemSystemd:
		c.Check(svc, gc.FitsTypeOf, &systemd.Service{})
	case service.InitSystemWindows:
		c.Check(svc, gc.FitsTypeOf, &windows.Service{})
	default:
		c.Errorf("unknown expected init system %q", dt.expected)
		return
	}
	if svc == nil {
		return
	}

	c.Check(svc.Name(), gc.Equals, name)
	c.Check(svc.Conf(), jc.DeepEquals, conf)
}

func (dt discoveryTest) checkInitSystem(c *gc.C, name string, ok bool) {
	if dt.expected == "" {
		if !c.Check(ok, jc.IsFalse) {
			c.Logf("found init system %q", name)
		}
	} else {
		c.Check(ok, jc.IsTrue)
		c.Check(name, gc.Equals, dt.expected)
	}
}

var discoveryTests = []discoveryTest{{
	os:       version.Windows,
	expected: service.InitSystemWindows,
}, {
	os:       version.Ubuntu,
	series:   "oneiric",
	expected: "",
}, {
	os:       version.Ubuntu,
	series:   "precise",
	expected: service.InitSystemUpstart,
}, {
	os:       version.Ubuntu,
	series:   "utopic",
	expected: service.InitSystemUpstart,
}, {
	os:       version.Ubuntu,
	series:   "vivid",
	expected: maybeSystemd,
}, {
	os:       version.CentOS,
	series:   "centos7",
	expected: service.InitSystemSystemd,
}, {
	os:       version.Unknown,
	expected: "",
}}

type discoverySuite struct {
	service.BaseSuite

	name string
	conf common.Conf
}

var _ = gc.Suite(&discoverySuite{})

func (s *discoverySuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	s.name = "a-service"
	s.conf = common.Conf{
		Desc:      "some service",
		ExecStart: "/path/to/some-command",
	}
}

func (s *discoverySuite) unsetLegacyUpstart(c *gc.C) {
	err := os.Setenv(osenv.JujuFeatureFlagEnvKey, "")
	c.Assert(err, jc.ErrorIsNil)
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

func (s *discoverySuite) setLegacyUpstart(c *gc.C) {
	err := os.Setenv(osenv.JujuFeatureFlagEnvKey, feature.LegacyUpstart)
	c.Assert(err, jc.ErrorIsNil)
	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
}

func (s *discoverySuite) TestDiscoverServiceLocalHost(c *gc.C) {
	var localInitSystem string
	switch runtime.GOOS {
	case "windows":
		localInitSystem = service.InitSystemWindows
	case "linux":
		localInitSystem, _ = service.VersionInitSystem(version.Current)
	}
	test := discoveryTest{
		os:       version.Current.OS,
		series:   version.Current.Series,
		expected: localInitSystem,
	}
	test.disableVersionDiscovery(s)

	svc, err := service.DiscoverService(s.name, s.conf)
	c.Assert(err, jc.ErrorIsNil)

	test.checkService(c, svc, err, s.name, s.conf)
}

func (s *discoverySuite) TestDiscoverServiceLocalOnly(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		test.setLocal(c, s)
		test.disableVersionDiscovery(s)

		svc, err := service.DiscoverService(s.name, s.conf)

		test.checkService(c, svc, err, s.name, s.conf)
	}
}

func (s *discoverySuite) TestDiscoverServiceVersionFallback(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		test.disableLocalDiscovery(c, s)
		test.setVersion(s)

		svc, err := service.DiscoverService(s.name, s.conf)

		test.checkService(c, svc, err, s.name, s.conf)
	}
}

func (s *discoverySuite) TestVersionInitSystem(c *gc.C) {
	for _, test := range discoveryTests {
		test.log(c)

		vers := test.setVersion(s)

		initSystem, ok := service.VersionInitSystem(vers)

		test.checkInitSystem(c, initSystem, ok)
	}
}

func (s *discoverySuite) TestVersionInitSystemLegacyUpstart(c *gc.C) {
	s.setLegacyUpstart(c)
	test := discoveryTest{
		os:       version.Ubuntu,
		series:   "vivid",
		expected: service.InitSystemUpstart,
	}
	vers := test.setVersion(s)

	initSystem, ok := service.VersionInitSystem(vers)

	test.checkInitSystem(c, initSystem, ok)
}

func (s *discoverySuite) TestVersionInitSystemNoLegacyUpstart(c *gc.C) {
	s.unsetLegacyUpstart(c)
	test := discoveryTest{
		os:       version.Ubuntu,
		series:   "vivid",
		expected: service.InitSystemSystemd,
	}
	vers := test.setVersion(s)

	initSystem, ok := service.VersionInitSystem(vers)

	test.checkInitSystem(c, initSystem, ok)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirst(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", true, nil),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initA")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorFirst(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failure),
		service.NewDiscoveryCheck("initB", true, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initB")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchFirstError(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", true, failure),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initA")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchSecond(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, nil),
		service.NewDiscoveryCheck("initB", true, nil),
	)

	name, err := service.DiscoverLocalInitSystem()
	c.Assert(err, jc.ErrorIsNil)

	c.Check(name, gc.Equals, "initB")
}

func (s *discoverySuite) TestDiscoverLocalInitSystemMatchNone(c *gc.C) {
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, nil),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorMixed(c *gc.C) {
	failure := errors.New("<failed>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failure),
		service.NewDiscoveryCheck("initB", false, nil),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverLocalInitSystemErrorAll(c *gc.C) {
	failureA := errors.New("<failed A>")
	failureB := errors.New("<failed B>")
	s.PatchLocalDiscovery(
		service.NewDiscoveryCheck("initA", false, failureA),
		service.NewDiscoveryCheck("initB", false, failureB),
	)

	_, err := service.DiscoverLocalInitSystem()

	c.Check(err, jc.Satisfies, errors.IsNotFound)
}

func (s *discoverySuite) TestDiscoverInitSystemScriptBash(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	script, filename := s.newDiscoverInitSystemScript(c)
	script += filename
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}

func (s *discoverySuite) TestDiscoverInitSystemScriptPosix(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	script, filename := s.newDiscoverInitSystemScript(c)
	script += "sh " + filename
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}

func (s *discoverySuite) writeScript(c *gc.C, name, script string) (string, string) {
	filename := filepath.Join(c.MkDir(), name)
	commands := []string{
		fmt.Sprintf(`
cat > %s << 'EOF'
%s
EOF`[1:], filename, script),
		"chmod 0755 " + filename,
	}
	writeScript := strings.Join(commands, "\n") + "\n"
	return writeScript, filename
}

func (s *discoverySuite) newDiscoverInitSystemScript(c *gc.C) (string, string) {
	script := service.DiscoverInitSystemScript()
	return s.writeScript(c, "discover_init_system.sh", script)
}

func (s *discoverySuite) TestNewShellSelectCommandBash(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	discoveryScript := service.DiscoverInitSystemScript()
	handler := func(initSystem string) (string, bool) {
		return "echo -n " + initSystem, true
	}
	script := "init_system=$(" + discoveryScript + ")\n"
	// The script will fail with exit 1 if it cannot match in init system.
	script += service.NewShellSelectCommand("init_system", "exit 1", handler)
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}

func (s *discoverySuite) TestNewShellSelectCommandPosix(c *gc.C) {
	if runtime.GOOS == "windows" {
		c.Skip("not supported on windows")
	}

	discoveryScript := service.DiscoverInitSystemScript()
	handler := func(initSystem string) (string, bool) {
		return "echo -n " + initSystem, true
	}
	script := "init_system=$(" + discoveryScript + ")\n"
	// The script will fail with exit 1 if it cannot match in init system.
	script += service.NewShellSelectCommand("init_system", "exit 1", handler)
	commands, filename := s.writeScript(c, "test_shell_select.sh", script)
	commands += "sh " + filename
	response, err := exec.RunCommands(exec.RunParams{
		Commands: script,
	})
	c.Assert(err, jc.ErrorIsNil)

	initSystem, err := service.DiscoverInitSystem()
	c.Assert(err, jc.ErrorIsNil)
	c.Check(response.Code, gc.Equals, 0)
	c.Check(string(response.Stdout), gc.Equals, initSystem)
	c.Check(string(response.Stderr), gc.Equals, "")
}
<|endoftext|>


<commit_before>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package parser

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/model"
)

type Parser struct {
	logger logger.Logger
}

func New(logger logger.Logger) (*Parser, error) {
	return &Parser{
		logger: logger,
	}, nil
}

func (parser *Parser) Parse(item *dataaccess.Item) (*model.Item, error) {

	// convert the files
	files := make([]*model.File, 0, len(item.Files()))
	for _, file := range item.Files() {

		fileModel, err := model.NewFile(file)
		if err != nil {
			parser.logger.Warn("Unable to convert file %q.", file)
			continue
		}

		files = append(files, fileModel)
	}

	itemModel, err := model.NewItem(item.Route(), files)
	if err != nil {
		return nil, fmt.Errorf("Unable to convert item %q. Error: %s", item, err)
	}

	return itemModel, nil
}
<commit_msg>Extracted a file conversion method from the Parse function<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package parser

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/logger"
	"github.com/andreaskoch/allmark2/dataaccess"
	"github.com/andreaskoch/allmark2/model"
)

type Parser struct {
	logger logger.Logger
}

func New(logger logger.Logger) (*Parser, error) {
	return &Parser{
		logger: logger,
	}, nil
}

func (parser *Parser) Parse(item *dataaccess.Item) (*model.Item, error) {

	// convert the files
	files := parser.convertFiles(item.Files())

	itemModel, err := model.NewItem(item.Route(), files)
	if err != nil {
		return nil, fmt.Errorf("Unable to convert item %q. Error: %s", item, err)
	}

	return itemModel, nil
}

func (parser *Parser) convertFiles(dataaccessFiles []*dataaccess.File) []*model.File {

	files := make([]*model.File, 0, len(dataaccessFiles))

	for _, file := range dataaccessFiles {

		fileModel, err := model.NewFile(file)
		if err != nil {
			parser.logger.Warn("Unable to convert file %q.", file)
			continue
		}

		files = append(files, fileModel)
	}

	return files
}
<|endoftext|>