<commit_before>package graph

// All a node needs to do is identify itself. This allows the user to pass in nodes more
// interesting than an int, but also allow us to reap the benefits of having a map-storable,
// ==able type.
type Node interface {
	ID() int
}

// Allows edges to do something more interesting that just be a group of nodes. While the methods
// are called Head and Tail, they are not considered directed unless the given interface specifies
// otherwise.
type Edge interface {
	Head() Node
	Tail() Node
}

// A Graph implements the behavior of an undirected graph.
//
// All methods in Graph are implicitly undirected. Graph algorithms that care about directionality
// will intelligently choose the DirectedGraph behavior if that interface is also implemented,
// even if the function itself only takes in a Graph (or a super-interface of graph).
type Graph interface {
	// NodeExists returns true when node is currently in the graph.
	NodeExists(node Node) bool
	// NodeList returns a list of all nodes in no particular order, useful for
	// determining things like if a graph is fully connected. The caller is
	// free to modify this list. Implementations should construct a new list
	// and not return internal representation.
	NodeList() []Node
	// Neighbors returns all nodes connected by any edge to this node.
	Neighbors(node Node) []Node
	// EdgeBetween returns an edge between node and neighbor such that
	// Head is one argument and Tail is the other. If no
	// such edge exists, this function returns nil.
	EdgeBetween(node, neighbor Node) Edge
}

// Directed graphs are characterized by having seperable Heads and Tails in their edges.
// That is, if node1 goes to node2, that does not necessarily imply that node2 goes to node1.
//
// While it's possible for a directed graph to have fully reciprocal edges (i.e. the graph is
// symmetric) -- it is not required to be. The graph is also required to implement Graph
// because in many cases it can be useful to know all neighbors regardless of direction.
type DirectedGraph interface {
	Graph
	// Successors gives the nodes connected by OUTBOUND edges.
	// If the graph is an undirected graph, this set is equal to Predecessors.
	Successors(node Node) []Node
	// EdgeTo returns an edge between node and successor such that
	// Head returns node and Tail returns successor, if no
	// such edge exists, this function returns nil.
	EdgeTo(node, successor Node) Edge
	// Predecessors gives the nodes connected by INBOUND edges.
	// If the graph is an undirected graph, this set is equal to Successors.
	Predecessors(node Node) []Node
}

// Returns all undirected edges in the graph
type EdgeLister interface {
	EdgeList() []Edge
}

type EdgeListGraph interface {
	Graph
	EdgeLister
}

// Returns all directed edges in the graph.
type DirectedEdgeLister interface {
	DirectedEdgeList() []Edge
}

type DirectedEdgeListGraph interface {
	Graph
	DirectedEdgeLister
}

// A crunch graph forces a sparse graph to become a dense graph. That is, if the node IDs are
// [1,4,9,7] it would "crunch" the ids into the contiguous block [0,1,2,3]. Order is not
// required to be preserved between the non-cruched and crunched instances (that means in
// the example above 0 may correspond to 4 or 7 or 9, not necessarily 1).
//
// All dense graphs should have the first ID as 0.
type CrunchGraph interface {
	Graph
	Crunch()
}

// A Graph that implements Coster has an actual cost between adjacent nodes, also known as a
// weighted graph. If a graph implements coster and a function needs to read cost (e.g. A*),
// this function will take precedence over the Uniform Cost function (all weights are 1) if "nil"
// is passed in for the function argument.
//
// If the argument is nil, or the edge is invalid for some reason, this should return math.Inf(1)
type Coster interface {
	Cost(edge Edge) float64
}

// Guarantees that something implementing Coster is also a Graph.
type CostGraph interface {
	Coster
	Graph
}

// A graph that implements HeuristicCoster implements a heuristic between any two given nodes.
// Like Coster, if a graph implements this and a function needs a heuristic cost (e.g. A*), this
// function will take precedence over the Null Heuristic (always returns 0) if "nil" is passed in
// for the function argument. If HeuristicCost is not intended to be used, it can be implemented as
// the null heuristic (always returns 0.)
type HeuristicCoster interface {
	// HeuristicCost returns a heuristic cost between any two nodes.
	HeuristicCost(node1, node2 Node) float64
}

// A Mutable Graph is a graph that can be changed in an arbitrary way. It is useful for several
// algorithms; for instance, Johnson's Algorithm requires adding a temporary node and changing
// edge weights. Another case where this is used is computing minimum spanning trees. Since trees
// are graphs, a minimum spanning tree can be created using this interface.
//
// Note that just because a graph does not implement MutableGraph does not mean that this package
// expects it to be invariant (though even a MutableGraph should be treated as invariant while an
// algorithm is operating on it), it simply means that without this interface this package can not
// properly handle the graph in order to, say, fill it with a minimum spanning tree.
//
// In functions that take a MutableGraph as an argument, it should not be the same as the Graph
// argument as concurrent modification will likely cause problems.
//
// Mutable graphs should always record the IDs as they are represented -- which means they are
// sparse by nature.
//
// Mutable graphs are required to keep the exact Nodes and Edges passed in, and return
// the originals when asked.
type MutableGraph interface {
	CostGraph
	// NewNode adds a node with an arbitrary ID and returns the new, unique ID
	// used.
	NewNode() Node
	// Adds a node to the graph
	AddNode(node Node)
	// AddEdge connects two nodes in the graph. Neither node is required
	// to have been added before this is called. If directed is false,
	// it also adds the reciprocal edge. If this is called a second time,
	// it overrides any existing edge.
	AddEdge(e Edge, cost float64, directed bool)
	// RemoveNode removes a node from the graph, as well as any edges
	// attached to it
	RemoveNode(node Node)
	// RemoveEdge removes a connection between two nodes, but does not
	// remove Head nor Tail under any circumstance. As with AddEdge, if
	// directed is false it also removes the reciprocal edge. This function
	// should be treated as a no-op and not an error if the edge doesn't exist.
	RemoveEdge(e Edge, directed bool)
	// EmptyGraph clears the graph of all nodes and edges.
	EmptyGraph()
}

// A DStarGraph is a special interface that allows the DStarLite function to be used on a graph.
//
// D*-lite is an algorithm that allows for the graph representation to change when actions are
// taken, whether this be from actions taken by the agent or simply new information gathered.
// As such, there's a Move function, that allows the graph to take into account an agent moving
// to the next node. This is always followed by a call to ChangedEdges.
//
// Traditionally in D*-lite, the algorithm would scan every edge to see if the cost changed, and
// then update its information if it detected any changes. This slightly remixed step allows the
// graph to provide notification of any changes, and even provide an alternate cost function if it
// needs to. This can be used to speed up the algorithm significantly since the graph no longer has
// to scan for changes, and only updates when told to. If changedEdges is nil or of len 0, no
// updates will be performed. If changedEdges is not nil, it will update the internal
// representation. If newCostFunc is non-nil it will be swapped with dStar's current cost function
// if and only if changedEdges is non-nil/len>0, however, newCostFunc is not required to be non-nil
// if updates are present. DStar will continue using the current cost function if that is the case.
type DStarGraph interface {
	Graph
	Move(target Node)
	ChangedEdges() (newCostFunc func(Node, Node) float64, changedEdges []Edge)
}

// A function that returns the cost of following an edge
type CostFunc func(Edge) float64

// Estimates the cost of travelling between two nodes
type HeuristicCostFunc func(Node, Node) float64
<commit_msg>Added convenience constants to make Add and Remove edge clearer<commit_after>package graph

// All a node needs to do is identify itself. This allows the user to pass in nodes more
// interesting than an int, but also allow us to reap the benefits of having a map-storable,
// ==able type.
type Node interface {
	ID() int
}

// Allows edges to do something more interesting that just be a group of nodes. While the methods
// are called Head and Tail, they are not considered directed unless the given interface specifies
// otherwise.
type Edge interface {
	Head() Node
	Tail() Node
}

// A Graph implements the behavior of an undirected graph.
//
// All methods in Graph are implicitly undirected. Graph algorithms that care about directionality
// will intelligently choose the DirectedGraph behavior if that interface is also implemented,
// even if the function itself only takes in a Graph (or a super-interface of graph).
type Graph interface {
	// NodeExists returns true when node is currently in the graph.
	NodeExists(node Node) bool
	// NodeList returns a list of all nodes in no particular order, useful for
	// determining things like if a graph is fully connected. The caller is
	// free to modify this list. Implementations should construct a new list
	// and not return internal representation.
	NodeList() []Node
	// Neighbors returns all nodes connected by any edge to this node.
	Neighbors(node Node) []Node
	// EdgeBetween returns an edge between node and neighbor such that
	// Head is one argument and Tail is the other. If no
	// such edge exists, this function returns nil.
	EdgeBetween(node, neighbor Node) Edge
}

// Directed graphs are characterized by having seperable Heads and Tails in their edges.
// That is, if node1 goes to node2, that does not necessarily imply that node2 goes to node1.
//
// While it's possible for a directed graph to have fully reciprocal edges (i.e. the graph is
// symmetric) -- it is not required to be. The graph is also required to implement Graph
// because in many cases it can be useful to know all neighbors regardless of direction.
type DirectedGraph interface {
	Graph
	// Successors gives the nodes connected by OUTBOUND edges.
	// If the graph is an undirected graph, this set is equal to Predecessors.
	Successors(node Node) []Node
	// EdgeTo returns an edge between node and successor such that
	// Head returns node and Tail returns successor, if no
	// such edge exists, this function returns nil.
	EdgeTo(node, successor Node) Edge
	// Predecessors gives the nodes connected by INBOUND edges.
	// If the graph is an undirected graph, this set is equal to Successors.
	Predecessors(node Node) []Node
}

// Returns all undirected edges in the graph
type EdgeLister interface {
	EdgeList() []Edge
}

type EdgeListGraph interface {
	Graph
	EdgeLister
}

// Returns all directed edges in the graph.
type DirectedEdgeLister interface {
	DirectedEdgeList() []Edge
}

type DirectedEdgeListGraph interface {
	Graph
	DirectedEdgeLister
}

// A crunch graph forces a sparse graph to become a dense graph. That is, if the node IDs are
// [1,4,9,7] it would "crunch" the ids into the contiguous block [0,1,2,3]. Order is not
// required to be preserved between the non-cruched and crunched instances (that means in
// the example above 0 may correspond to 4 or 7 or 9, not necessarily 1).
//
// All dense graphs should have the first ID as 0.
type CrunchGraph interface {
	Graph
	Crunch()
}

// A Graph that implements Coster has an actual cost between adjacent nodes, also known as a
// weighted graph. If a graph implements coster and a function needs to read cost (e.g. A*),
// this function will take precedence over the Uniform Cost function (all weights are 1) if "nil"
// is passed in for the function argument.
//
// If the argument is nil, or the edge is invalid for some reason, this should return math.Inf(1)
type Coster interface {
	Cost(edge Edge) float64
}

// Guarantees that something implementing Coster is also a Graph.
type CostGraph interface {
	Coster
	Graph
}

// A graph that implements HeuristicCoster implements a heuristic between any two given nodes.
// Like Coster, if a graph implements this and a function needs a heuristic cost (e.g. A*), this
// function will take precedence over the Null Heuristic (always returns 0) if "nil" is passed in
// for the function argument. If HeuristicCost is not intended to be used, it can be implemented as
// the null heuristic (always returns 0.)
type HeuristicCoster interface {
	// HeuristicCost returns a heuristic cost between any two nodes.
	HeuristicCost(node1, node2 Node) float64
}

// A Mutable Graph is a graph that can be changed in an arbitrary way. It is useful for several
// algorithms; for instance, Johnson's Algorithm requires adding a temporary node and changing
// edge weights. Another case where this is used is computing minimum spanning trees. Since trees
// are graphs, a minimum spanning tree can be created using this interface.
//
// Note that just because a graph does not implement MutableGraph does not mean that this package
// expects it to be invariant (though even a MutableGraph should be treated as invariant while an
// algorithm is operating on it), it simply means that without this interface this package can not
// properly handle the graph in order to, say, fill it with a minimum spanning tree.
//
// In functions that take a MutableGraph as an argument, it should not be the same as the Graph
// argument as concurrent modification will likely cause problems.
//
// Mutable graphs should always record the IDs as they are represented -- which means they are
// sparse by nature.
//
// Mutable graphs are required to keep the exact Nodes and Edges passed in, and return
// the originals when asked.
type MutableGraph interface {
	CostGraph
	// NewNode adds a node with an arbitrary ID and returns the new, unique ID
	// used.
	NewNode() Node
	// Adds a node to the graph
	AddNode(node Node)
	// AddEdge connects two nodes in the graph. Neither node is required
	// to have been added before this is called. If directed is false,
	// it also adds the reciprocal edge. If this is called a second time,
	// it overrides any existing edge.
	AddEdge(e Edge, cost float64, directed bool)
	// RemoveNode removes a node from the graph, as well as any edges
	// attached to it
	RemoveNode(node Node)
	// RemoveEdge removes a connection between two nodes, but does not
	// remove Head nor Tail under any circumstance. As with AddEdge, if
	// directed is false it also removes the reciprocal edge. This function
	// should be treated as a no-op and not an error if the edge doesn't exist.
	RemoveEdge(e Edge, directed bool)
	// EmptyGraph clears the graph of all nodes and edges.
	EmptyGraph()
}

// A DStarGraph is a special interface that allows the DStarLite function to be used on a graph.
//
// D*-lite is an algorithm that allows for the graph representation to change when actions are
// taken, whether this be from actions taken by the agent or simply new information gathered.
// As such, there's a Move function, that allows the graph to take into account an agent moving
// to the next node. This is always followed by a call to ChangedEdges.
//
// Traditionally in D*-lite, the algorithm would scan every edge to see if the cost changed, and
// then update its information if it detected any changes. This slightly remixed step allows the
// graph to provide notification of any changes, and even provide an alternate cost function if it
// needs to. This can be used to speed up the algorithm significantly since the graph no longer has
// to scan for changes, and only updates when told to. If changedEdges is nil or of len 0, no
// updates will be performed. If changedEdges is not nil, it will update the internal
// representation. If newCostFunc is non-nil it will be swapped with dStar's current cost function
// if and only if changedEdges is non-nil/len>0, however, newCostFunc is not required to be non-nil
// if updates are present. DStar will continue using the current cost function if that is the case.
type DStarGraph interface {
	Graph
	Move(target Node)
	ChangedEdges() (newCostFunc func(Node, Node) float64, changedEdges []Edge)
}

// A function that returns the cost of following an edge
type CostFunc func(Edge) float64

// Estimates the cost of travelling between two nodes
type HeuristicCostFunc func(Node, Node) float64

// Convenience constants for AddEdge and RemoveEdge
const (
	Directed   bool = true
	Undirected      = false
)
<|endoftext|>


<commit_before>package randomstring

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRangeInt(t *testing.T) {
	assert.Equal(t, rangeInt(1, 5), []int{1, 2, 3, 4, 5}, "they should be equal")
	assert.Equal(t, rangeInt(5, 1), []int{}, "a > b empty return")
	assert.Equal(t, rangeInt(1, 1), []int{1}, "a = b should return a")
	assert.Equal(t, rangeInt(0, 1), []int{0, 1}, "should be equal")
	assert.Equal(t, rangeInt(2, 4), []int{2, 3, 4}, "should be equal")
	assert.Equal(t, rangeInt(-5, 0), []int{-5, -4, -3, -2, -1, 0}, "should be equal")
}

/*func TestIntToStringRange(t *testing.T) {
	t.Error("Fail!")
}

func TestAppendIntRanges(t *testing.T) {
	t.Error("Fail!")
}

func TestAppendStrRanges(t *testing.T) {
	t.Error("Fail!")
}

func TestPrepend(t *testing.T) {
	t.Error("Fail!")
}

func TestPrependArray(t *testing.T) {
	t.Error("Fail!")
}

func TestShift(t *testing.T) {
	t.Error("Fail!")
}

func TestRandInt(t *testing.T) {
	t.Error("Fail!")
}

func TestRandomString(t *testing.T) {
	t.Error("Fail!")
}

func TestDeleteFromIndex(t *testing.T) {
	t.Error("Fail!")
}

func TestDeleteKeysFromArray(t *testing.T) {
	t.Error("Fail!")
}

func TestArrayToMap(t *testing.T) {
	t.Error("Fail!")
}

func TestSmartSplit(t *testing.T) {
	t.Error("Fail!")
}*/
<commit_msg>More unit tests<commit_after>package randomstring

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestRangeInt(t *testing.T) {
	assert.Equal(t, []int{1, 2, 3, 4, 5}, rangeInt(1, 5), "they should be equal")
	assert.Equal(t, []int{}, rangeInt(5, 1), "a > b empty return")
	assert.Equal(t, []int{1}, rangeInt(1, 1), "a = b should return a")
	assert.Equal(t, []int{0, 1}, rangeInt(0, 1), "should be equal")
	assert.Equal(t, []int{2, 3, 4}, rangeInt(2, 4), "should be equal")
	assert.Equal(t, []int{-5, -4, -3, -2, -1, 0}, rangeInt(-5, 0), "should be equal")
}

func TestIntToStringRange(t *testing.T) {
	assert.Equal(t, []string{"!", "\"", "#"}, intToStringRange([]int{33, 34, 35}), "they should be equal")
	assert.Equal(t, []string{}, intToStringRange([]int{}), "should be equal")
	assert.Equal(t, []string{"1"}, intToStringRange([]int{49}), "should be equal")
}

func TestAppendIntRanges(t *testing.T) {
	assert.Equal(t, rangeInt(1, 10), appendIntRanges([][]int{rangeInt(1, 5), rangeInt(6, 10)}), "they should be equal")
	assert.Equal(t, []int(nil), appendIntRanges([][]int{}), "they should be equal")
}

func TestAppendStrRanges(t *testing.T) {
	assert.Equal(t, []string{"a", "b", "c", "d", "e"}, appendStrRanges([][]string{[]string{"a", "b", "c"}, []string{"d", "e"}}), "they should be equal")
	assert.Equal(t, []string(nil), appendStrRanges([][]string{}), "they should be equal")
}

func TestPrepend(t *testing.T) {
	assert.Equal(t, []string{"a"}, prepend("a", []string{}), "should be equal")
	assert.Equal(t, []string{"a", "b", "c"}, prepend("a", []string{"b", "c"}), "should be equal")
}

func TestPrependArray(t *testing.T) {
	assert.Equal(t, []string{"a"}, prependArray([]string{"a"}, []string{}), "should be equal")
	assert.Equal(t, []string{}, prependArray([]string{}, []string{}), "should be equal")
	assert.Equal(t, []string{"a"}, prependArray([]string{}, []string{"a"}), "should be equal")
	assert.Equal(t, []string{"a", "b", "c"}, prependArray([]string{"a", "b"}, []string{"c"}), "should be equal")
	assert.Equal(t, []string{"a", "b", "c"}, prependArray([]string{"a"}, []string{"b", "c"}), "should be equal")
}

/*
func TestShift(t *testing.T) {
	t.Error("Fail!")
}

func TestRandInt(t *testing.T) {
	t.Error("Fail!")
}

func TestRandomString(t *testing.T) {
	t.Error("Fail!")
}

func TestDeleteFromIndex(t *testing.T) {
	t.Error("Fail!")
}

func TestDeleteKeysFromArray(t *testing.T) {
	t.Error("Fail!")
}

func TestArrayToMap(t *testing.T) {
	t.Error("Fail!")
}

func TestSmartSplit(t *testing.T) {
	t.Error("Fail!")
}*/
<|endoftext|>


<commit_before>package gapi

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// DashboardMeta represents Grafana dashboard meta.
type DashboardMeta struct {
	IsStarred bool   `json:"isStarred"`
	Slug      string `json:"slug"`
	Folder    int64  `json:"folderId"`
}

// DashboardSaveResponse represents the Grafana API response to creating or saving a dashboard.
type DashboardSaveResponse struct {
	Slug    string `json:"slug"`
	ID      int64  `json:"id"`
	UID     string `json:"uid"`
	Status  string `json:"status"`
	Version int64  `json:"version"`
}

// Dashboard represents a Grafana dashboard.
type Dashboard struct {
	Meta      DashboardMeta          `json:"meta"`
	Model     map[string]interface{} `json:"dashboard"`
	Folder    int64                  `json:"folderId"`
	Overwrite bool                   `json:"overwrite"`
	Message   string 				 `json:"message"`
}

// SaveDashboard is a deprecated method for saving a Grafana dashboard. Use NewDashboard.
// Deprecated: Use NewDashboard instead.
func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) {
	wrapper := map[string]interface{}{
		"dashboard": model,
		"overwrite": overwrite,
	}
	data, err := json.Marshal(wrapper)
	if err != nil {
		return nil, err
	}

	result := &DashboardSaveResponse{}
	err = c.request("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data), &result)
	if err != nil {
		return nil, err
	}

	return result, err
}

// NewDashboard creates a new Grafana dashboard.
func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, error) {
	data, err := json.Marshal(dashboard)
	if err != nil {
		return nil, err
	}

	result := &DashboardSaveResponse{}
	err = c.request("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data), &result)
	if err != nil {
		return nil, err
	}

	return result, err
}

// Dashboards fetches and returns all dashboards.
func (c *Client) Dashboards() ([]FolderDashboardSearchResponse, error) {
	params := map[string]string{
		"type": "dash-db",
	}
	return c.FolderDashboardSearch(params)
}

// Dashboard will be removed.
// Deprecated: Starting from Grafana v5.0. Use DashboardByUID instead.
func (c *Client) Dashboard(slug string) (*Dashboard, error) {
	return c.dashboard(fmt.Sprintf("/api/dashboards/db/%s", slug))
}

// DashboardByUID gets a dashboard by UID.
func (c *Client) DashboardByUID(uid string) (*Dashboard, error) {
	return c.dashboard(fmt.Sprintf("/api/dashboards/uid/%s", uid))
}

func (c *Client) dashboard(path string) (*Dashboard, error) {
	result := &Dashboard{}
	err := c.request("GET", path, nil, nil, &result)
	if err != nil {
		return nil, err
	}
	result.Folder = result.Meta.Folder

	return result, err
}

// DeleteDashboard will be removed.
// Deprecated: Starting from Grafana v5.0. Use DeleteDashboardByUID instead.
func (c *Client) DeleteDashboard(slug string) error {
	return c.deleteDashboard(fmt.Sprintf("/api/dashboards/db/%s", slug))
}

// DeleteDashboardByUID deletes a dashboard by UID.
func (c *Client) DeleteDashboardByUID(uid string) error {
	return c.deleteDashboard(fmt.Sprintf("/api/dashboards/uid/%s", uid))
}

func (c *Client) deleteDashboard(path string) error {
	return c.request("DELETE", path, nil, nil, nil)
}
<commit_msg>weird Go spacing<commit_after>package gapi

import (
	"bytes"
	"encoding/json"
	"fmt"
)

// DashboardMeta represents Grafana dashboard meta.
type DashboardMeta struct {
	IsStarred bool   `json:"isStarred"`
	Slug      string `json:"slug"`
	Folder    int64  `json:"folderId"`
}

// DashboardSaveResponse represents the Grafana API response to creating or saving a dashboard.
type DashboardSaveResponse struct {
	Slug    string `json:"slug"`
	ID      int64  `json:"id"`
	UID     string `json:"uid"`
	Status  string `json:"status"`
	Version int64  `json:"version"`
}

// Dashboard represents a Grafana dashboard.
type Dashboard struct {
	Meta      DashboardMeta          `json:"meta"`
	Model     map[string]interface{} `json:"dashboard"`
	Folder    int64                  `json:"folderId"`
	Overwrite bool                   `json:"overwrite"`
	Message   string                 `json:"message"`
}

// SaveDashboard is a deprecated method for saving a Grafana dashboard. Use NewDashboard.
// Deprecated: Use NewDashboard instead.
func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) {
	wrapper := map[string]interface{}{
		"dashboard": model,
		"overwrite": overwrite,
	}
	data, err := json.Marshal(wrapper)
	if err != nil {
		return nil, err
	}

	result := &DashboardSaveResponse{}
	err = c.request("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data), &result)
	if err != nil {
		return nil, err
	}

	return result, err
}

// NewDashboard creates a new Grafana dashboard.
func (c *Client) NewDashboard(dashboard Dashboard) (*DashboardSaveResponse, error) {
	data, err := json.Marshal(dashboard)
	if err != nil {
		return nil, err
	}

	result := &DashboardSaveResponse{}
	err = c.request("POST", "/api/dashboards/db", nil, bytes.NewBuffer(data), &result)
	if err != nil {
		return nil, err
	}

	return result, err
}

// Dashboards fetches and returns all dashboards.
func (c *Client) Dashboards() ([]FolderDashboardSearchResponse, error) {
	params := map[string]string{
		"type": "dash-db",
	}
	return c.FolderDashboardSearch(params)
}

// Dashboard will be removed.
// Deprecated: Starting from Grafana v5.0. Use DashboardByUID instead.
func (c *Client) Dashboard(slug string) (*Dashboard, error) {
	return c.dashboard(fmt.Sprintf("/api/dashboards/db/%s", slug))
}

// DashboardByUID gets a dashboard by UID.
func (c *Client) DashboardByUID(uid string) (*Dashboard, error) {
	return c.dashboard(fmt.Sprintf("/api/dashboards/uid/%s", uid))
}

func (c *Client) dashboard(path string) (*Dashboard, error) {
	result := &Dashboard{}
	err := c.request("GET", path, nil, nil, &result)
	if err != nil {
		return nil, err
	}
	result.Folder = result.Meta.Folder

	return result, err
}

// DeleteDashboard will be removed.
// Deprecated: Starting from Grafana v5.0. Use DeleteDashboardByUID instead.
func (c *Client) DeleteDashboard(slug string) error {
	return c.deleteDashboard(fmt.Sprintf("/api/dashboards/db/%s", slug))
}

// DeleteDashboardByUID deletes a dashboard by UID.
func (c *Client) DeleteDashboardByUID(uid string) error {
	return c.deleteDashboard(fmt.Sprintf("/api/dashboards/uid/%s", uid))
}

func (c *Client) deleteDashboard(path string) error {
	return c.request("DELETE", path, nil, nil, nil)
}
<|endoftext|>


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

package upgrades

import (
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/api/keymanager"
	"github.com/juju/juju/utils/ssh"
)

func ensureSystemSSHKey(context Context) error {
	privateKey, publicKey, err := readOrMakeSystemIdentity(context)
	if err != nil {
		return errors.Trace(err)
	}
	if publicKey == "" {
		// privateKey was read from disk, so it exists.
		return nil
	}
	if err := updateAuthorizedKeys(context, publicKey); err != nil {
		return errors.Trace(err)
	}
	if err := writeSystemIdentity(context, privateKey); err != nil {
		return errors.Trace(err)
	}
	return nil
}

// Somewhere in the 1.20 cycle the system-identity was added to the
// state serving info collection in the database, however no migration
// step was added to take the identity file from disk and put it into the
// new value in the database.
func ensureSystemSSHKeyRedux(context Context) error {
	// If there is a system-identity in the database already, we don't need to
	// do anything.
	stateInfo, err := context.State().StateServingInfo()
	if err != nil {
		logger.Errorf("failed to read state serving info: %v", err)
		return errors.Trace(err)
	}
	if stateInfo.SystemIdentity != "" {
		logger.Infof("state serving info has a system identity already, all good")
		// We are good. One exists already.
		return nil
	}

	privateKey, publicKey, err := readOrMakeSystemIdentity(context)
	if err != nil {
		logger.Errorf("failed to read or make system identity: %v", err)
		return errors.Trace(err)
	}

	if err := state.SetSystemIdentity(context.State(), privateKey); err != nil {
		if errors.Cause(err) == txn.ErrAborted {
			logger.Errorf("someone else has set system identity already")
			// Another state server upgrading concurrently has updated
			// the system identity so it is no longer empty. So discard
			// anything that was created, reread the system info and write
			// out the file.  We also assume that the other upgrade has
			// updated the authorized keys already.
			stateInfo, err := context.State().StateServingInfo()
			if err != nil {
				logger.Errorf("failed to read state serving info: %v", err)
				return errors.Trace(err)
			}
			if stateInfo.SystemIdentity == "" {
				logger.Errorf("but the transaction said it would be there...")
				return errors.New("some weird state inconsistency exists")
			}
			if err := writeSystemIdentity(context, stateInfo.SystemIdentity); err != nil {
				logger.Errorf("failed to write the system identity file: %v", err)
				return errors.Trace(err)
			}
			return nil
		}

		logger.Errorf("failed to set system identity: %v", err)
		return errors.Annotate(err, "cannot set state serving info")
	}

	// If the public key is empty then the system identity was read
	// from the file on disk already, so we are done.
	if publicKey == "" {
		logger.Infof("publicKey is empty, so we have read it from disk, so should be in auth keys already")
		return nil
	}

	if err := updateAuthorizedKeys(context, publicKey); err != nil {
		return errors.Trace(err)
	}
	if err := writeSystemIdentity(context, privateKey); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func readOrMakeSystemIdentity(context Context) (privateKey, publicKey string, err error) {
	identityFile := context.AgentConfig().SystemIdentityPath()
	// Don't generate a key unless we have to.
	keyExists, err := systemKeyExists(identityFile)
	if err != nil {
		return "", "", errors.Annotate(err, "failed to check system key exists")
	}
	if keyExists {
		logger.Infof("key exists, reading contents")

		// Read the contents.
		contents, err := ioutil.ReadFile(identityFile)
		if err != nil {
			return "", "", errors.Trace(err)
		}
		// If we are just reading the private key,
		return string(contents), "", nil
	}

	logger.Infof("generating new key")
	privateKey, publicKey, err = ssh.GenerateKey(config.JujuSystemKey)
	if err != nil {
		return "", "", errors.Annotate(err, "failed to create system key")
	}
	return privateKey, publicKey, nil
}

func updateAuthorizedKeys(context Context, publicKey string) error {
	logger.Infof("setting new authorized key for %q", publicKey)

	keyManager := keymanager.NewClient(context.APIState())
	errResults, err := keyManager.AddKeys(config.JujuSystemKey, publicKey)
	apiErr := err
	if apiErr == nil {
		apiErr = errResults[0].Error
	}
	if err != nil || errResults[0].Error != nil {
		return errors.Annotate(apiErr, "failed to update authorised keys with new system key")
	}
	return nil
}

func writeSystemIdentity(context Context, privateKey string) error {
	identityFile := context.AgentConfig().SystemIdentityPath()
	logger.Infof("writing system identity to %q", identityFile)
	if err := ioutil.WriteFile(identityFile, []byte(privateKey), 0600); err != nil {
		return errors.Annotate(err, "failed to write identity file")
	}
	return nil
}

func systemKeyExists(identityFile string) (bool, error) {
	_, err := os.Stat(identityFile)
	if err == nil {
		return true, nil
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	return false, nil
}
<commit_msg>update error message<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upgrades

import (
	"io/ioutil"
	"os"

	"github.com/juju/errors"
	"gopkg.in/mgo.v2/txn"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/api/keymanager"
	"github.com/juju/juju/utils/ssh"
)

func ensureSystemSSHKey(context Context) error {
	privateKey, publicKey, err := readOrMakeSystemIdentity(context)
	if err != nil {
		return errors.Trace(err)
	}
	if publicKey == "" {
		// privateKey was read from disk, so it exists.
		return nil
	}
	if err := updateAuthorizedKeys(context, publicKey); err != nil {
		return errors.Trace(err)
	}
	if err := writeSystemIdentity(context, privateKey); err != nil {
		return errors.Trace(err)
	}
	return nil
}

// Somewhere in the 1.20 cycle the system-identity was added to the
// state serving info collection in the database, however no migration
// step was added to take the identity file from disk and put it into the
// new value in the database.
func ensureSystemSSHKeyRedux(context Context) error {
	// If there is a system-identity in the database already, we don't need to
	// do anything.
	stateInfo, err := context.State().StateServingInfo()
	if err != nil {
		logger.Errorf("failed to read state serving info: %v", err)
		return errors.Trace(err)
	}
	if stateInfo.SystemIdentity != "" {
		logger.Infof("state serving info has a system identity already, all good")
		// We are good. One exists already.
		return nil
	}

	privateKey, publicKey, err := readOrMakeSystemIdentity(context)
	if err != nil {
		logger.Errorf("failed to read or make system identity: %v", err)
		return errors.Trace(err)
	}

	if err := state.SetSystemIdentity(context.State(), privateKey); err != nil {
		if errors.Cause(err) == txn.ErrAborted {
			logger.Errorf("someone else has set system identity already")
			// Another state server upgrading concurrently has updated
			// the system identity so it is no longer empty. So discard
			// anything that was created, reread the system info and write
			// out the file.  We also assume that the other upgrade has
			// updated the authorized keys already.
			stateInfo, err := context.State().StateServingInfo()
			if err != nil {
				logger.Errorf("failed to read state serving info: %v", err)
				return errors.Trace(err)
			}
			if stateInfo.SystemIdentity == "" {
				logger.Errorf("but the transaction said it would be there...")
				return errors.New("system identity is not set")
			}
			if err := writeSystemIdentity(context, stateInfo.SystemIdentity); err != nil {
				logger.Errorf("failed to write the system identity file: %v", err)
				return errors.Trace(err)
			}
			return nil
		}

		logger.Errorf("failed to set system identity: %v", err)
		return errors.Annotate(err, "cannot set state serving info")
	}

	// If the public key is empty then the system identity was read
	// from the file on disk already, so we are done.
	if publicKey == "" {
		logger.Infof("publicKey is empty, so we have read it from disk, so should be in auth keys already")
		return nil
	}

	if err := updateAuthorizedKeys(context, publicKey); err != nil {
		return errors.Trace(err)
	}
	if err := writeSystemIdentity(context, privateKey); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func readOrMakeSystemIdentity(context Context) (privateKey, publicKey string, err error) {
	identityFile := context.AgentConfig().SystemIdentityPath()
	// Don't generate a key unless we have to.
	keyExists, err := systemKeyExists(identityFile)
	if err != nil {
		return "", "", errors.Annotate(err, "failed to check system key exists")
	}
	if keyExists {
		logger.Infof("key exists, reading contents")

		// Read the contents.
		contents, err := ioutil.ReadFile(identityFile)
		if err != nil {
			return "", "", errors.Trace(err)
		}
		// If we are just reading the private key,
		return string(contents), "", nil
	}

	logger.Infof("generating new key")
	privateKey, publicKey, err = ssh.GenerateKey(config.JujuSystemKey)
	if err != nil {
		return "", "", errors.Annotate(err, "failed to create system key")
	}
	return privateKey, publicKey, nil
}

func updateAuthorizedKeys(context Context, publicKey string) error {
	logger.Infof("setting new authorized key for %q", publicKey)

	keyManager := keymanager.NewClient(context.APIState())
	errResults, err := keyManager.AddKeys(config.JujuSystemKey, publicKey)
	apiErr := err
	if apiErr == nil {
		apiErr = errResults[0].Error
	}
	if err != nil || errResults[0].Error != nil {
		return errors.Annotate(apiErr, "failed to update authorised keys with new system key")
	}
	return nil
}

func writeSystemIdentity(context Context, privateKey string) error {
	identityFile := context.AgentConfig().SystemIdentityPath()
	logger.Infof("writing system identity to %q", identityFile)
	if err := ioutil.WriteFile(identityFile, []byte(privateKey), 0600); err != nil {
		return errors.Annotate(err, "failed to write identity file")
	}
	return nil
}

func systemKeyExists(identityFile string) (bool, error) {
	_, err := os.Stat(identityFile)
	if err == nil {
		return true, nil
	}
	if !os.IsNotExist(err) {
		return false, err
	}
	return false, nil
}
<|endoftext|>


<commit_before>package uploaders

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"regexp"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-tools/go-android/sdk"
)

// ApkInfo ...
type ApkInfo struct {
	AppName       string
	PackageName   string
	VersionCode   string
	VersionName   string
	MinSDKVersion string
}

func filterPackageInfos(aaptOut string) (string, string, string) {
	pattern := `package: name=\'(?P<package_name>.*)\' versionCode=\'(?P<version_code>.*)\' versionName=\'(?P<version_name>.*)\' platformBuildVersionName=`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 4 {
		return matches[1], matches[2], matches[3]
	}
	return "", "", ""
}

func filterAppLable(aaptOut string) string {
	pattern := `application: label=\'(?P<label>.+)\' icon=`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}

	pattern = `application-label:\'(?P<label>.*)\'`
	re = regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}

	return ""
}

func filterMinSDKVersion(aaptOut string) string {
	pattern := `sdkVersion:\'(?P<min_sdk_version>.*)\'`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}
	return ""
}

func getAPKInfo(apkPth string) (ApkInfo, error) {
	androidHome := os.Getenv("ANDROID_HOME")
	if androidHome == "" {
		return ApkInfo{}, errors.New("ANDROID_HOME environment not set")
	}

	sdkModel, err := sdk.New(androidHome)
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to create sdk model, error: %s", err)
	}

	aaptPth, err := sdkModel.LatestBuildToolPath("aapt")
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to find latest aapt binary, error: %s", err)
	}

	aaptOut, err := command.New(aaptPth, "dump", "badging", apkPth).RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to get apk infos, output: %s, error: %s", aaptOut, err)
	}

	appName := filterAppLable(aaptOut)
	packageName, versionCode, versionName := filterPackageInfos(aaptOut)
	minSDKVersion := filterMinSDKVersion(aaptOut)

	return ApkInfo{
		AppName:       appName,
		PackageName:   packageName,
		VersionCode:   versionCode,
		VersionName:   versionName,
		MinSDKVersion: minSDKVersion,
	}, nil
}

// DeployAPK ...
func DeployAPK(pth, buildURL, token, notifyUserGroups, notifyEmails, isEnablePublicPage string) (string, error) {
	log.Printf("analyzing apk")

	apkInfo, err := getAPKInfo(pth)
	if err != nil {
		return "", err
	}

	appInfo := map[string]interface{}{
		"app_name":        apkInfo.AppName,
		"package_name":    apkInfo.PackageName,
		"version_code":    apkInfo.VersionCode,
		"version_name":    apkInfo.VersionName,
		"min_sdk_version": apkInfo.MinSDKVersion,
	}

	log.Printf("  apk infos: %v", appInfo)

	// ---

	fileSize, err := fileSizeInBytes(pth)
	if err != nil {
		return "", fmt.Errorf("failed to get apk size, error: %s", err)
	}

	apkInfoMap := map[string]interface{}{
		"file_size_bytes": fmt.Sprintf("%f", fileSize),
		"app_info":        appInfo,
	}

	artifactInfoBytes, err := json.Marshal(apkInfoMap)
	if err != nil {
		return "", fmt.Errorf("failed to marshal apk infos, error: %s", err)
	}

	// ---

	uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "android-apk")
	if err != nil {
		return "", fmt.Errorf("failed to create apk artifact, error: %s", err)
	}

	if err := uploadArtifact(uploadURL, pth, "application/vnd.android.package-archive"); err != nil {
		return "", fmt.Errorf("failed to upload apk artifact, error: %s", err)
	}

	publicInstallPage, err := finishArtifact(buildURL, token, artifactID, string(artifactInfoBytes), notifyUserGroups, notifyEmails, isEnablePublicPage)
	if err != nil {
		return "", fmt.Errorf("failed to finish apk artifact, error: %s", err)
	}

	return publicInstallPage, nil
}
<commit_msg>apk analyser issue fix (#65)<commit_after>package uploaders

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"regexp"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-tools/go-android/sdk"
)

// ApkInfo ...
type ApkInfo struct {
	AppName       string
	PackageName   string
	VersionCode   string
	VersionName   string
	MinSDKVersion string
}

func filterPackageInfos(aaptOut string) (string, string, string) {
	// build tools version >= 28 package: name='sample.results.test.multiple.bitrise.com.multipletestresultssample' versionCode='1' versionName='1.0'
	// build tools version < 28 package: name='sample.results.test.multiple.bitrise.com.multipletestresultssample' versionCode='1' versionName='1.0' platformBuildVersionName=''
	pattern := `package: name=\'(?P<package_name>.*)\' versionCode=\'(?P<version_code>.*)\' versionName=\'(?P<version_name>.*)\'`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 4 {
		return matches[1], matches[2], matches[3]
	}
	return "", "", ""
}

func filterAppLable(aaptOut string) string {
	pattern := `application: label=\'(?P<label>.+)\' icon=`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}

	pattern = `application-label:\'(?P<label>.*)\'`
	re = regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}

	return ""
}

func filterMinSDKVersion(aaptOut string) string {
	pattern := `sdkVersion:\'(?P<min_sdk_version>.*)\'`
	re := regexp.MustCompile(pattern)
	if matches := re.FindStringSubmatch(aaptOut); len(matches) == 2 {
		return matches[1]
	}
	return ""
}

func getAPKInfo(apkPth string) (ApkInfo, error) {
	androidHome := os.Getenv("ANDROID_HOME")
	if androidHome == "" {
		return ApkInfo{}, errors.New("ANDROID_HOME environment not set")
	}

	sdkModel, err := sdk.New(androidHome)
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to create sdk model, error: %s", err)
	}

	aaptPth, err := sdkModel.LatestBuildToolPath("aapt")
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to find latest aapt binary, error: %s", err)
	}

	aaptOut, err := command.New(aaptPth, "dump", "badging", apkPth).RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return ApkInfo{}, fmt.Errorf("failed to get apk infos, output: %s, error: %s", aaptOut, err)
	}

	appName := filterAppLable(aaptOut)
	packageName, versionCode, versionName := filterPackageInfos(aaptOut)
	minSDKVersion := filterMinSDKVersion(aaptOut)

	return ApkInfo{
		AppName:       appName,
		PackageName:   packageName,
		VersionCode:   versionCode,
		VersionName:   versionName,
		MinSDKVersion: minSDKVersion,
	}, nil
}

// DeployAPK ...
func DeployAPK(pth, buildURL, token, notifyUserGroups, notifyEmails, isEnablePublicPage string) (string, error) {
	log.Printf("analyzing apk")

	apkInfo, err := getAPKInfo(pth)
	if err != nil {
		return "", err
	}

	appInfo := map[string]interface{}{
		"app_name":        apkInfo.AppName,
		"package_name":    apkInfo.PackageName,
		"version_code":    apkInfo.VersionCode,
		"version_name":    apkInfo.VersionName,
		"min_sdk_version": apkInfo.MinSDKVersion,
	}

	log.Printf("  apk infos: %v", appInfo)

	// ---

	fileSize, err := fileSizeInBytes(pth)
	if err != nil {
		return "", fmt.Errorf("failed to get apk size, error: %s", err)
	}

	apkInfoMap := map[string]interface{}{
		"file_size_bytes": fmt.Sprintf("%f", fileSize),
		"app_info":        appInfo,
	}

	artifactInfoBytes, err := json.Marshal(apkInfoMap)
	if err != nil {
		return "", fmt.Errorf("failed to marshal apk infos, error: %s", err)
	}

	// ---

	uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "android-apk")
	if err != nil {
		return "", fmt.Errorf("failed to create apk artifact, error: %s", err)
	}

	if err := uploadArtifact(uploadURL, pth, "application/vnd.android.package-archive"); err != nil {
		return "", fmt.Errorf("failed to upload apk artifact, error: %s", err)
	}

	publicInstallPage, err := finishArtifact(buildURL, token, artifactID, string(artifactInfoBytes), notifyUserGroups, notifyEmails, isEnablePublicPage)
	if err != nil {
		return "", fmt.Errorf("failed to finish apk artifact, error: %s", err)
	}

	return publicInstallPage, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package utils

import (
	"testing"
)

func TestIntComparator(t *testing.T) {

	// i1,i2,expected
	tests := [][]interface{}{
		{1, 1, 0},
		{1, 2, -1},
		{2, 1, 1},
		{11, 22, -1},
		{0, 0, 0},
		{1, 0, 1},
		{0, 1, -1},
	}

	for _, test := range tests {
		actual := IntComparator(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}

func TestStringComparator(t *testing.T) {

	// s1,s2,expected
	tests := [][]interface{}{
		{"a", "a", 0},
		{"a", "b", -1},
		{"b", "a", 1},
		{"aa", "aab", -1},
		{"", "", 0},
		{"a", "", 1},
		{"", "a", -1},
		{"", "aaaaaaa", -1},
	}

	for _, test := range tests {
		actual := StringComparator(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}

func TestCustomComparator(t *testing.T) {

	type Custom struct {
		id   int
		name string
	}

	byID := func(a, b interface{}) int {
		c1 := a.(Custom)
		c2 := b.(Custom)
		switch {
		case c1.id > c2.id:
			return 1
		case c1.id < c2.id:
			return -1
		default:
			return 0
		}
	}

	// o1,o2,expected
	tests := [][]interface{}{
		{Custom{1, "a"}, Custom{1, "a"}, 0},
		{Custom{1, "a"}, Custom{2, "b"}, -1},
		{Custom{2, "b"}, Custom{1, "a"}, 1},
		{Custom{1, "a"}, Custom{1, "b"}, 0},
	}

	for _, test := range tests {
		actual := byID(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}
<commit_msg>- fix comparator test<commit_after>// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package utils

import (
	"testing"
)

func TestIntComparator(t *testing.T) {

	// i1,i2,expected
	tests := [][]interface{}{
		{1, 1, 0},
		{1, 2, -1},
		{2, 1, 1},
		{11, 22, -11},
		{0, 0, 0},
		{1, 0, 1},
		{0, 1, -1},
	}

	for _, test := range tests {
		actual := IntComparator(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}

func TestStringComparator(t *testing.T) {

	// s1,s2,expected
	tests := [][]interface{}{
		{"a", "a", 0},
		{"a", "b", -1},
		{"b", "a", 1},
		{"aa", "aab", -1},
		{"", "", 0},
		{"a", "", 1},
		{"", "a", -1},
		{"", "aaaaaaa", -1},
	}

	for _, test := range tests {
		actual := StringComparator(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}

func TestCustomComparator(t *testing.T) {

	type Custom struct {
		id   int
		name string
	}

	byID := func(a, b interface{}) int {
		c1 := a.(Custom)
		c2 := b.(Custom)
		switch {
		case c1.id > c2.id:
			return 1
		case c1.id < c2.id:
			return -1
		default:
			return 0
		}
	}

	// o1,o2,expected
	tests := [][]interface{}{
		{Custom{1, "a"}, Custom{1, "a"}, 0},
		{Custom{1, "a"}, Custom{2, "b"}, -1},
		{Custom{2, "b"}, Custom{1, "a"}, 1},
		{Custom{1, "a"}, Custom{1, "b"}, 0},
	}

	for _, test := range tests {
		actual := byID(test[0], test[1])
		expected := test[2]
		if actual != expected {
			t.Errorf("Got %v expected %v", actual, expected)
		}
	}
}
<|endoftext|>


<commit_before>package jars

import (
	"archive/zip"
	"bufio"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type Manifest struct {
	Map map[string]string
}

func (m *Manifest) Parse(s string) {
	if m.Map == nil {
		m.Map = make(map[string]string)
	}

	index := strings.IndexRune(s, ':')
	if index != -1 {
		key := s[0:index]
		value := strings.TrimSpace(s[index+1:])
		m.Map[key] = value
	}
}

func (m *Manifest) PrintHeaders() {
	fmt.Printf("%s=%d\n", "Headers found in Manifest", len(m.Map))
	for k, v := range m.Map {
		fmt.Println(k)
		fmt.Println(v)
	}
}

func (m *Manifest) BundleSymbolicName() string {
	v := m.Map["Bundle-SymbolicName"]
	index := strings.IndexRune(v, ';')
	if index != -1 {
		v = v[0:index]
	}
	return v
}

func ParseJar(fileName string) (*Manifest, string) {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		fmt.Printf("No such file or directory: %s\n", fileName)
		return nil, ""
	}

	zip, err := zip.OpenReader(fileName)
	if err != nil {
		fmt.Printf("Unable to process: %s\n\t[%q]\n", fileName, err)
		return nil, ""
	}
	defer zip.Close()

	var retVal Manifest

	for _, f := range zip.File {
		if f.Name == "META-INF/MANIFEST.MF" {
			zipEntry, err := f.Open()
			if err != nil {
				log.Fatal(err)
			}
			retVal = Manifest{}
			reader := bufio.NewReader(zipEntry)
			if reader != nil {
				header := make([]string, 0)
				for {
					bytes, _, err := reader.ReadLine()
					if len(bytes) > 0 {
						if len(header) == 0 {
							header = append(header, string(bytes))
						} else if bytes[0] != ' ' {
							header = append(header, "\n")
							retVal.Parse(strings.Join(header, ""))
							header = make([]string, 0)
							header = append(header, string(bytes))
						} else {
							header = append(header, string(bytes[1:]))
						}
					}
					if err != nil {
						break
					}
				}
			}
			zipEntry.Close()
			break
		}
	}

	return &retVal, ""
}

// Returns a map of file names to Manifest entries
func FindBundles(path string) (*map[string]string, int) {
	var pathToJar = make(map[string]string)
	var counter = 0

	vis := func(path string, info os.FileInfo, error error) error {
		counter++
		if info.IsDir() || !strings.HasSuffix(path, ".jar") {
			return nil
		}
		mf, _ := ParseJar(path)
		if mf != nil && mf.BundleSymbolicName() != "" {
			pathToJar[path] = mf.BundleSymbolicName()
		}
		return nil
	}

	filepath.Walk(path, vis)

	return &pathToJar, counter
}
<commit_msg>Added some comments<commit_after>package jars

import (
	"archive/zip"
	"bufio"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type Manifest struct {
	Map map[string]string
}

// Construct a Manifest from a string representation
func (m *Manifest) Parse(s string) {
	if m.Map == nil {
		m.Map = make(map[string]string)
	}

	index := strings.IndexRune(s, ':')
	if index != -1 {
		key := s[0:index]
		value := strings.TrimSpace(s[index+1:])
		m.Map[key] = value
	}
}

// Print all the headers in the Manifest
func (m *Manifest) PrintHeaders() {
	fmt.Printf("%s=%d\n", "Headers found in Manifest", len(m.Map))
	for k, v := range m.Map {
		fmt.Println(k)
		fmt.Println(v)
	}
}

// Return the Bundle-SymbolicName in the Manifest or nil.
func (m *Manifest) BundleSymbolicName() string {
	v := m.Map["Bundle-SymbolicName"]
	index := strings.IndexRune(v, ';')
	if index != -1 {
		v = v[0:index]
	}
	return v
}

// Loads a jar and reads its manifest if it exist returning a Manifest
func ParseJar(fileName string) (*Manifest, string) {
	if _, err := os.Stat(fileName); os.IsNotExist(err) {
		fmt.Printf("No such file or directory: %s\n", fileName)
		return nil, ""
	}

	zip, err := zip.OpenReader(fileName)
	if err != nil {
		fmt.Printf("Unable to process: %s\n\t[%q]\n", fileName, err)
		return nil, ""
	}
	defer zip.Close()

	var retVal Manifest

	for _, f := range zip.File {
		if f.Name == "META-INF/MANIFEST.MF" {
			zipEntry, err := f.Open()
			if err != nil {
				log.Fatal(err)
			}
			retVal = Manifest{}
			reader := bufio.NewReader(zipEntry)
			if reader != nil {
				header := make([]string, 0)
				for {
					bytes, _, err := reader.ReadLine()
					if len(bytes) > 0 {
						if len(header) == 0 {
							header = append(header, string(bytes))
						} else if bytes[0] != ' ' {
							header = append(header, "\n")
							retVal.Parse(strings.Join(header, ""))
							header = make([]string, 0)
							header = append(header, string(bytes))
						} else {
							header = append(header, string(bytes[1:]))
						}
					}
					if err != nil {
						break
					}
				}
			}
			zipEntry.Close()
			break
		}
	}

	return &retVal, ""
}

// Returns a map of file names to Manifest entries
func FindBundles(path string) (*map[string]string, int) {
	var pathToJar = make(map[string]string)
	var counter = 0

	vis := func(path string, info os.FileInfo, error error) error {
		counter++
		if info.IsDir() || !strings.HasSuffix(path, ".jar") {
			return nil
		}
		mf, _ := ParseJar(path)
		if mf != nil && mf.BundleSymbolicName() != "" {
			pathToJar[path] = mf.BundleSymbolicName()
		}
		return nil
	}

	filepath.Walk(path, vis)

	return &pathToJar, counter
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsCallerIdentity() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsCallerIdentityRead,

		Schema: map[string]*schema.Schema{
			"account_id": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"user_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*AWSClient).stsconn

	res, err := client.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		return fmt.Errorf("Error getting Caller Identity: %v", err)
	}

	log.Printf("[DEBUG] Reading Caller Identity.")
	d.SetId(time.Now().UTC().String())

	if *res.Account == "" {
		log.Println("[DEBUG] No Account ID available, failing")
		return fmt.Errorf("No AWS Account ID is available to the provider. Please ensure that\n" +
			"skip_requesting_account_id is not set on the AWS provider.")
	}

	log.Printf("[DEBUG] Setting AWS Account ID to %s.", *res.Account)
	d.Set("account_id", *res.Account)
	d.Set("arn", *res.Arn)
	d.Set("user_id", *res.UserId)
	return nil
}
<commit_msg>dont dereference pointers on Set<commit_after>package aws

import (
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsCallerIdentity() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceAwsCallerIdentityRead,

		Schema: map[string]*schema.Schema{
			"account_id": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"arn": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"user_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func dataSourceAwsCallerIdentityRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*AWSClient).stsconn

	res, err := client.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		return fmt.Errorf("Error getting Caller Identity: %v", err)
	}

	log.Printf("[DEBUG] Reading Caller Identity.")
	d.SetId(time.Now().UTC().String())

	if *res.Account == "" {
		log.Println("[DEBUG] No Account ID available, failing")
		return fmt.Errorf("No AWS Account ID is available to the provider. Please ensure that\n" +
			"skip_requesting_account_id is not set on the AWS provider.")
	}

	log.Printf("[DEBUG] Setting AWS Account ID to %s.", *res.Account)
	d.Set("account_id", res.Account)
	d.Set("arn", res.Arn)
	d.Set("user_id", res.UserId)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 data

import (
	"database/sql"
	"fmt"
	"os"
	"path"
	"runtime"
	"sync"

	"github.com/30x/apid-core"
	"github.com/30x/apid-core/data/wrap"
	"github.com/mattn/go-sqlite3"
)

const (
	configDataDriverKey = "data_driver"
	configDataSourceKey = "data_source"
	configDataPathKey   = "data_path"

	commonDBID      = "common"
	commonDBVersion = "base"

	defaultTraceLevel = "warn"
)

var log, dbTraceLog apid.LogService
var config apid.ConfigService

var dbMap = make(map[string]*sql.DB)
var dbMapSync sync.RWMutex

func CreateDataService() apid.DataService {
	config = apid.Config()
	log = apid.Log().ForModule("data")

	// we don't want to trace normally
	config.SetDefault("DATA_TRACE_LOG_LEVEL", defaultTraceLevel)
	dbTraceLog = apid.Log().ForModule("data_trace")

	config.SetDefault(configDataDriverKey, "sqlite3")
	config.SetDefault(configDataSourceKey, "file:%s")
	config.SetDefault(configDataPathKey, "sqlite")

	return &dataService{}
}

type dataService struct {
}

func (d *dataService) DB() (apid.DB, error) {
	return d.dbVersionForID(commonDBID, commonDBVersion)
}

func (d *dataService) DBForID(id string) (apid.DB, error) {
	if id == commonDBID {
		return nil, fmt.Errorf("reserved ID: %s", id)
	}
	return d.dbVersionForID(id, commonDBVersion)
}

func (d *dataService) DBVersion(version string) (apid.DB, error) {
	if version == commonDBVersion {
		return nil, fmt.Errorf("reserved version: %s", version)
	}
	return d.dbVersionForID(commonDBID, version)
}

func (d *dataService) DBVersionForID(id, version string) (apid.DB, error) {
	if id == commonDBID {
		return nil, fmt.Errorf("reserved ID: %s", id)
	}
	if version == commonDBVersion {
		return nil, fmt.Errorf("reserved version: %s", version)
	}
	return d.dbVersionForID(id, version)
}

// will set DB to close and delete when no more references
func (d *dataService) ReleaseDB(id, version string) {
	versionedID := VersionedDBID(id, version)

	dbMapSync.Lock()
	defer dbMapSync.Unlock()

	db := dbMap[versionedID]
	if db != nil {
		dbMap[versionedID] = nil
		log.Warn("SETTING FINALIZER")
		finalizer := Delete(versionedID)
		runtime.SetFinalizer(db, finalizer)
	}

	return
}

func (d *dataService) dbVersionForID(id, version string) (db *sql.DB, err error) {

	versionedID := VersionedDBID(id, version)

	dbMapSync.RLock()
	db = dbMap[versionedID]
	dbMapSync.RUnlock()
	if db != nil {
		return
	}

	dbMapSync.Lock()
	defer dbMapSync.Unlock()

	db = dbMap[versionedID]
	if db != nil {
		return
	}

	dataPath := DBPath(versionedID)

	if err = os.MkdirAll(path.Dir(dataPath), 0700); err != nil {
		return
	}

	log.Infof("LoadDB: %s", dataPath)
	source := fmt.Sprintf(config.GetString(configDataSourceKey), dataPath)

	wrappedDriverName := "dd:" + config.GetString(configDataDriverKey)
	driver := wrap.NewDriver(&sqlite3.SQLiteDriver{}, dbTraceLog)
	func() {
		// just ignore the "registered twice" panic
		defer func() {
			recover()
		}()
		sql.Register(wrappedDriverName, driver)
	}()

	db, err = sql.Open(wrappedDriverName, source)
	if err != nil {
		log.Errorf("error loading db: %s", err)
		return
	}

	err = db.Ping()
	if err != nil {
		log.Errorf("error pinging db: %s", err)
		return
	}

	sqlString := "PRAGMA journal_mode=WAL;"
	_, err = db.Exec(sqlString)
	if err != nil {
		log.Errorf("error setting journal_mode: %s", err)
		return
	}

	sqlString = "PRAGMA foreign_keys = ON;"
	_, err = db.Exec(sqlString)
	if err != nil {
		log.Errorf("error enabling foreign_keys: %s", err)
		return
	}

	dbMap[versionedID] = db
	return
}

func Delete(versionedID string) interface{} {
	return func(db *sql.DB) {
		err := db.Close()
		if err != nil {
			log.Errorf("error closing DB: %v", err)
		}
		dataDir := path.Dir(DBPath(versionedID))
		err = os.RemoveAll(dataDir)
		if err != nil {
			log.Errorf("error removing DB files: %v", err)
		}
		delete(dbMap, versionedID)
	}
}

func VersionedDBID(id, version string) string {
	return path.Join(id, version)
}

func DBPath(id string) string {
	storagePath := config.GetString("local_storage_path")
	relativeDataPath := config.GetString(configDataPathKey)
	return path.Join(storagePath, relativeDataPath, id, "sqlite3")
}
<commit_msg>Add periodic DB Conn Info.<commit_after>// Copyright 2017 Google Inc.
//
// 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 data

import (
	"database/sql"
	"fmt"
	"time"
	"os"
	"path"
	"runtime"
	"sync"
	"github.com/30x/apid-core"
	"github.com/30x/apid-core/data/wrap"
	"github.com/mattn/go-sqlite3"
)

const (
	configDataDriverKey = "data_driver"
	configDataSourceKey = "data_source"
	configDataPathKey   = "data_path"
	statCollectionInterval = 10
	commonDBID      = "common"
	commonDBVersion = "base"

	defaultTraceLevel = "warn"
)

var log, dbTraceLog apid.LogService
var config apid.ConfigService

var dbMap = make(map[string]*sql.DB)
var dbMapSync sync.RWMutex

func CreateDataService() apid.DataService {
	config = apid.Config()
	log = apid.Log().ForModule("data")

	// we don't want to trace normally
	config.SetDefault("DATA_TRACE_LOG_LEVEL", defaultTraceLevel)
	dbTraceLog = apid.Log().ForModule("data_trace")

	config.SetDefault(configDataDriverKey, "sqlite3")
	config.SetDefault(configDataSourceKey, "file:%s")
	config.SetDefault(configDataPathKey, "sqlite")

	return &dataService{}
}

type dataService struct {
}

func (d *dataService) DB() (apid.DB, error) {
	return d.dbVersionForID(commonDBID, commonDBVersion)
}

func (d *dataService) DBForID(id string) (apid.DB, error) {
	if id == commonDBID {
		return nil, fmt.Errorf("reserved ID: %s", id)
	}
	return d.dbVersionForID(id, commonDBVersion)
}

func (d *dataService) DBVersion(version string) (apid.DB, error) {
	if version == commonDBVersion {
		return nil, fmt.Errorf("reserved version: %s", version)
	}
	return d.dbVersionForID(commonDBID, version)
}

func (d *dataService) DBVersionForID(id, version string) (apid.DB, error) {
	if id == commonDBID {
		return nil, fmt.Errorf("reserved ID: %s", id)
	}
	if version == commonDBVersion {
		return nil, fmt.Errorf("reserved version: %s", version)
	}
	return d.dbVersionForID(id, version)
}

// will set DB to close and delete when no more references
func (d *dataService) ReleaseDB(id, version string) {
	versionedID := VersionedDBID(id, version)

	dbMapSync.Lock()
	defer dbMapSync.Unlock()

	db := dbMap[versionedID]
	if db != nil {
		dbMap[versionedID] = nil
		log.Warn("SETTING FINALIZER")
		finalizer := Delete(versionedID)
		runtime.SetFinalizer(db, finalizer)
	}

	return
}

func (d *dataService) dbVersionForID(id, version string) (db *sql.DB, err error) {

	versionedID := VersionedDBID(id, version)

	dbMapSync.RLock()
	db = dbMap[versionedID]
	dbMapSync.RUnlock()
	if db != nil {
		return
	}

	dbMapSync.Lock()
	defer dbMapSync.Unlock()

	db = dbMap[versionedID]
	if db != nil {
		return
	}

	dataPath := DBPath(versionedID)

	if err = os.MkdirAll(path.Dir(dataPath), 0700); err != nil {
		return
	}

	log.Infof("LoadDB: %s", dataPath)
	source := fmt.Sprintf(config.GetString(configDataSourceKey), dataPath)

	wrappedDriverName := "dd:" + config.GetString(configDataDriverKey)
	driver := wrap.NewDriver(&sqlite3.SQLiteDriver{}, dbTraceLog)
	func() {
		// just ignore the "registered twice" panic
		defer func() {
			recover()
		}()
		sql.Register(wrappedDriverName, driver)
	}()

	db, err = sql.Open(wrappedDriverName, source)
	if err != nil {
		log.Errorf("error loading db: %s", err)
		return
	}

	err = db.Ping()
	if err != nil {
		log.Errorf("error pinging db: %s", err)
		return
	}

	sqlString := "PRAGMA journal_mode=WAL;"
	_, err = db.Exec(sqlString)
	if err != nil {
		log.Errorf("error setting journal_mode: %s", err)
		return
	}

	sqlString = "PRAGMA foreign_keys = ON;"
	_, err = db.Exec(sqlString)
	if err != nil {
		log.Errorf("error enabling foreign_keys: %s", err)
		return
	}
	dbLvl := config.GetString("log_level")
	if dbLvl == "Debug" {
		go printDBStatsInfo(db, versionedID)
	}
	dbMap[versionedID] = db
	return
}

func Delete(versionedID string) interface{} {
	return func(db *sql.DB) {
		err := db.Close()
		if err != nil {
			log.Errorf("error closing DB: %v", err)
		}
		dataDir := path.Dir(DBPath(versionedID))
		err = os.RemoveAll(dataDir)
		if err != nil {
			log.Errorf("error removing DB files: %v", err)
		}
		delete(dbMap, versionedID)
	}
}

func VersionedDBID(id, version string) string {
	return path.Join(id, version)
}

func DBPath(id string) string {
	storagePath := config.GetString("local_storage_path")
	relativeDataPath := config.GetString(configDataPathKey)
	return path.Join(storagePath, relativeDataPath, id, "sqlite3")
}

func printDBStatsInfo(db *sql.DB, versionedId string) {
	tick := time.Duration(statCollectionInterval * time.Second)
	for _ = range time.Tick(tick) {
		log.Debugf("Current number of open DB for ver {%s} is {%d}", versionedId, db.Stats().OpenConnections)
	}
}
<|endoftext|>


<commit_before>// +build linux

package fs

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/configs"
	libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
	"github.com/pkg/errors"
	"golang.org/x/sys/unix"
)

var (
	subsystemsLegacy = subsystemSet{
		&CpusetGroup{},
		&DevicesGroup{},
		&MemoryGroup{},
		&CpuGroup{},
		&CpuacctGroup{},
		&PidsGroup{},
		&BlkioGroup{},
		&HugetlbGroup{},
		&NetClsGroup{},
		&NetPrioGroup{},
		&PerfEventGroup{},
		&FreezerGroup{},
		&NameGroup{GroupName: "name=systemd", Join: true},
	}
	HugePageSizes, _ = cgroups.GetHugePageSize()
)

var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")

type subsystemSet []subsystem

func (s subsystemSet) Get(name string) (subsystem, error) {
	for _, ss := range s {
		if ss.Name() == name {
			return ss, nil
		}
	}
	return nil, errSubsystemDoesNotExist
}

type subsystem interface {
	// Name returns the name of the subsystem.
	Name() string
	// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
	GetStats(path string, stats *cgroups.Stats) error
	// Removes the cgroup represented by 'cgroupData'.
	Remove(*cgroupData) error
	// Creates and joins the cgroup represented by 'cgroupData'.
	Apply(*cgroupData) error
	// Set the cgroup represented by cgroup.
	Set(path string, cgroup *configs.Cgroup) error
}

type manager struct {
	mu       sync.Mutex
	cgroups  *configs.Cgroup
	rootless bool // ignore permission-related errors
	paths    map[string]string
}

func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgroups.Manager {
	return &manager{
		cgroups:  cg,
		paths:    paths,
		rootless: rootless,
	}
}

// The absolute path to the root of the cgroup hierarchies.
var cgroupRootLock sync.Mutex
var cgroupRoot string

// Gets the cgroupRoot.
func getCgroupRoot() (string, error) {
	cgroupRootLock.Lock()
	defer cgroupRootLock.Unlock()

	if cgroupRoot != "" {
		return cgroupRoot, nil
	}

	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return "", err
	}
	defer f.Close()

	var root string
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		text := scanner.Text()
		fields := strings.Split(text, " ")
		// Safe as mountinfo encodes mountpoints with spaces as \040.
		index := strings.Index(text, " - ")
		postSeparatorFields := strings.Fields(text[index+3:])
		numPostFields := len(postSeparatorFields)

		// This is an error as we can't detect if the mount is for "cgroup"
		if numPostFields == 0 {
			return "", fmt.Errorf("mountinfo: found no fields post '-' in %q", text)
		}

		if postSeparatorFields[0] == "cgroup" {
			// Check that the mount is properly formatted.
			if numPostFields < 3 {
				return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
			}

			root = filepath.Dir(fields[4])
			break
		}
	}
	if err := scanner.Err(); err != nil {
		return "", err
	}
	if root == "" {
		return "", errors.New("no cgroup mount found in mountinfo")
	}

	if _, err := os.Stat(root); err != nil {
		return "", err
	}

	cgroupRoot = root
	return cgroupRoot, nil
}

type cgroupData struct {
	root      string
	innerPath string
	config    *configs.Cgroup
	pid       int
}

// isIgnorableError returns whether err is a permission error (in the loose
// sense of the word). This includes EROFS (which for an unprivileged user is
// basically a permission error) and EACCES (for similar reasons) as well as
// the normal EPERM.
func isIgnorableError(rootless bool, err error) bool {
	// We do not ignore errors if we are root.
	if !rootless {
		return false
	}
	// TODO: rm errors.Cause once we switch to %w everywhere
	err = errors.Cause(err)
	// Is it an ordinary EPERM?
	if errors.Is(err, os.ErrPermission) {
		return true
	}
	// Handle some specific syscall errors.
	var errno unix.Errno
	if errors.As(err, &errno) {
		return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES
	}
	return false
}

func (m *manager) getSubsystems() subsystemSet {
	return subsystemsLegacy
}

func (m *manager) Apply(pid int) (err error) {
	if m.cgroups == nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()

	var c = m.cgroups

	d, err := getCgroupData(m.cgroups, pid)
	if err != nil {
		return err
	}

	m.paths = make(map[string]string)
	if c.Paths != nil {
		for name, path := range c.Paths {
			_, err := d.path(name)
			if err != nil {
				if cgroups.IsNotFound(err) {
					continue
				}
				return err
			}
			m.paths[name] = path
		}
		return cgroups.EnterPid(m.paths, pid)
	}

	for _, sys := range m.getSubsystems() {
		p, err := d.path(sys.Name())
		if err != nil {
			// The non-presence of the devices subsystem is
			// considered fatal for security reasons.
			if cgroups.IsNotFound(err) && sys.Name() != "devices" {
				continue
			}
			return err
		}
		m.paths[sys.Name()] = p

		if err := sys.Apply(d); err != nil {
			// In the case of rootless (including euid=0 in userns), where an
			// explicit cgroup path hasn't been set, we don't bail on error in
			// case of permission problems. Cases where limits have been set
			// (and we couldn't create our own cgroup) are handled by Set.
			if isIgnorableError(m.rootless, err) && m.cgroups.Path == "" {
				delete(m.paths, sys.Name())
				continue
			}
			return err
		}

	}
	return nil
}

func (m *manager) Destroy() error {
	if m.cgroups == nil || m.cgroups.Paths != nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()
	if err := cgroups.RemovePaths(m.paths); err != nil {
		return err
	}
	m.paths = make(map[string]string)
	return nil
}

func (m *manager) Path(subsys string) string {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.paths[subsys]
}

func (m *manager) GetStats() (*cgroups.Stats, error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	stats := cgroups.NewStats()
	for name, path := range m.paths {
		sys, err := m.getSubsystems().Get(name)
		if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
			continue
		}
		if err := sys.GetStats(path, stats); err != nil {
			return nil, err
		}
	}
	return stats, nil
}

func (m *manager) Set(container *configs.Config) error {
	if container.Cgroups == nil {
		return nil
	}

	// If Paths are set, then we are just joining cgroups paths
	// and there is no need to set any values.
	if m.cgroups != nil && m.cgroups.Paths != nil {
		return nil
	}

	m.mu.Lock()
	defer m.mu.Unlock()
	for _, sys := range m.getSubsystems() {
		path := m.paths[sys.Name()]
		if err := sys.Set(path, container.Cgroups); err != nil {
			if m.rootless && sys.Name() == "devices" {
				continue
			}
			// When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
			// However, errors from other subsystems are not ignored.
			// see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
			if path == "" {
				// We never created a path for this cgroup, so we cannot set
				// limits for it (though we have already tried at this point).
				return fmt.Errorf("cannot set %s limit: container could not join or create cgroup", sys.Name())
			}
			return err
		}
	}

	return nil
}

// Freeze toggles the container's freezer cgroup depending on the state
// provided
func (m *manager) Freeze(state configs.FreezerState) (Err error) {
	path := m.Path("freezer")
	if m.cgroups == nil || path == "" {
		return errors.New("cannot toggle freezer: cgroups not configured for container")
	}

	prevState := m.cgroups.Resources.Freezer
	m.cgroups.Resources.Freezer = state
	defer func() {
		if Err != nil {
			m.cgroups.Resources.Freezer = prevState
		}
	}()

	freezer, err := m.getSubsystems().Get("freezer")
	if err != nil {
		return err
	}
	if err := freezer.Set(path, m.cgroups); err != nil {
		return err
	}
	return nil
}

func (m *manager) GetPids() ([]int, error) {
	return cgroups.GetPids(m.Path("devices"))
}

func (m *manager) GetAllPids() ([]int, error) {
	return cgroups.GetAllPids(m.Path("devices"))
}

func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
	root, err := getCgroupRoot()
	if err != nil {
		return nil, err
	}

	if (c.Name != "" || c.Parent != "") && c.Path != "" {
		return nil, errors.New("cgroup: either Path or Name and Parent should be used")
	}

	// XXX: Do not remove this code. Path safety is important! -- cyphar
	cgPath := libcontainerUtils.CleanPath(c.Path)
	cgParent := libcontainerUtils.CleanPath(c.Parent)
	cgName := libcontainerUtils.CleanPath(c.Name)

	innerPath := cgPath
	if innerPath == "" {
		innerPath = filepath.Join(cgParent, cgName)
	}

	return &cgroupData{
		root:      root,
		innerPath: innerPath,
		config:    c,
		pid:       pid,
	}, nil
}

func (raw *cgroupData) path(subsystem string) (string, error) {
	mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem)
	// If we didn't mount the subsystem, there is no point we make the path.
	if err != nil {
		return "", err
	}

	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
	if filepath.IsAbs(raw.innerPath) {
		// Sometimes subsystems can be mounted together as 'cpu,cpuacct'.
		return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil
	}

	// Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating
	// process could in container and shared pid namespace with host, and
	// /proc/1/cgroup could point to whole other world of cgroups.
	parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
	if err != nil {
		return "", err
	}

	return filepath.Join(parentPath, raw.innerPath), nil
}

func (raw *cgroupData) join(subsystem string) (string, error) {
	path, err := raw.path(subsystem)
	if err != nil {
		return "", err
	}
	if err := os.MkdirAll(path, 0755); err != nil {
		return "", err
	}
	if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil {
		return "", err
	}
	return path, nil
}

func removePath(p string, err error) error {
	if err != nil {
		return err
	}
	if p != "" {
		return os.RemoveAll(p)
	}
	return nil
}

func (m *manager) GetPaths() map[string]string {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.paths
}

func (m *manager) GetCgroups() (*configs.Cgroup, error) {
	return m.cgroups, nil
}

func (m *manager) GetFreezerState() (configs.FreezerState, error) {
	dir := m.Path("freezer")
	freezer, err := m.getSubsystems().Get("freezer")

	// If the container doesn't have the freezer cgroup, say it's undefined.
	if err != nil || dir == "" {
		return configs.Undefined, nil
	}
	return freezer.(*FreezerGroup).GetState(dir)
}

func (m *manager) Exists() bool {
	return cgroups.PathExists(m.Path("devices"))
}
<commit_msg>cgroups/fs/path: optimize<commit_after>// +build linux

package fs

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/opencontainers/runc/libcontainer/cgroups"
	"github.com/opencontainers/runc/libcontainer/configs"
	libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
	"github.com/pkg/errors"
	"golang.org/x/sys/unix"
)

var (
	subsystemsLegacy = subsystemSet{
		&CpusetGroup{},
		&DevicesGroup{},
		&MemoryGroup{},
		&CpuGroup{},
		&CpuacctGroup{},
		&PidsGroup{},
		&BlkioGroup{},
		&HugetlbGroup{},
		&NetClsGroup{},
		&NetPrioGroup{},
		&PerfEventGroup{},
		&FreezerGroup{},
		&NameGroup{GroupName: "name=systemd", Join: true},
	}
	HugePageSizes, _ = cgroups.GetHugePageSize()
)

var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")

type subsystemSet []subsystem

func (s subsystemSet) Get(name string) (subsystem, error) {
	for _, ss := range s {
		if ss.Name() == name {
			return ss, nil
		}
	}
	return nil, errSubsystemDoesNotExist
}

type subsystem interface {
	// Name returns the name of the subsystem.
	Name() string
	// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
	GetStats(path string, stats *cgroups.Stats) error
	// Removes the cgroup represented by 'cgroupData'.
	Remove(*cgroupData) error
	// Creates and joins the cgroup represented by 'cgroupData'.
	Apply(*cgroupData) error
	// Set the cgroup represented by cgroup.
	Set(path string, cgroup *configs.Cgroup) error
}

type manager struct {
	mu       sync.Mutex
	cgroups  *configs.Cgroup
	rootless bool // ignore permission-related errors
	paths    map[string]string
}

func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgroups.Manager {
	return &manager{
		cgroups:  cg,
		paths:    paths,
		rootless: rootless,
	}
}

// The absolute path to the root of the cgroup hierarchies.
var cgroupRootLock sync.Mutex
var cgroupRoot string

// Gets the cgroupRoot.
func getCgroupRoot() (string, error) {
	cgroupRootLock.Lock()
	defer cgroupRootLock.Unlock()

	if cgroupRoot != "" {
		return cgroupRoot, nil
	}

	f, err := os.Open("/proc/self/mountinfo")
	if err != nil {
		return "", err
	}
	defer f.Close()

	var root string
	scanner := bufio.NewScanner(f)
	for scanner.Scan() {
		text := scanner.Text()
		fields := strings.Split(text, " ")
		// Safe as mountinfo encodes mountpoints with spaces as \040.
		index := strings.Index(text, " - ")
		postSeparatorFields := strings.Fields(text[index+3:])
		numPostFields := len(postSeparatorFields)

		// This is an error as we can't detect if the mount is for "cgroup"
		if numPostFields == 0 {
			return "", fmt.Errorf("mountinfo: found no fields post '-' in %q", text)
		}

		if postSeparatorFields[0] == "cgroup" {
			// Check that the mount is properly formatted.
			if numPostFields < 3 {
				return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
			}

			root = filepath.Dir(fields[4])
			break
		}
	}
	if err := scanner.Err(); err != nil {
		return "", err
	}
	if root == "" {
		return "", errors.New("no cgroup mount found in mountinfo")
	}

	if _, err := os.Stat(root); err != nil {
		return "", err
	}

	cgroupRoot = root
	return cgroupRoot, nil
}

type cgroupData struct {
	root      string
	innerPath string
	config    *configs.Cgroup
	pid       int
}

// isIgnorableError returns whether err is a permission error (in the loose
// sense of the word). This includes EROFS (which for an unprivileged user is
// basically a permission error) and EACCES (for similar reasons) as well as
// the normal EPERM.
func isIgnorableError(rootless bool, err error) bool {
	// We do not ignore errors if we are root.
	if !rootless {
		return false
	}
	// TODO: rm errors.Cause once we switch to %w everywhere
	err = errors.Cause(err)
	// Is it an ordinary EPERM?
	if errors.Is(err, os.ErrPermission) {
		return true
	}
	// Handle some specific syscall errors.
	var errno unix.Errno
	if errors.As(err, &errno) {
		return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES
	}
	return false
}

func (m *manager) getSubsystems() subsystemSet {
	return subsystemsLegacy
}

func (m *manager) Apply(pid int) (err error) {
	if m.cgroups == nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()

	var c = m.cgroups

	d, err := getCgroupData(m.cgroups, pid)
	if err != nil {
		return err
	}

	m.paths = make(map[string]string)
	if c.Paths != nil {
		for name, path := range c.Paths {
			_, err := d.path(name)
			if err != nil {
				if cgroups.IsNotFound(err) {
					continue
				}
				return err
			}
			m.paths[name] = path
		}
		return cgroups.EnterPid(m.paths, pid)
	}

	for _, sys := range m.getSubsystems() {
		p, err := d.path(sys.Name())
		if err != nil {
			// The non-presence of the devices subsystem is
			// considered fatal for security reasons.
			if cgroups.IsNotFound(err) && sys.Name() != "devices" {
				continue
			}
			return err
		}
		m.paths[sys.Name()] = p

		if err := sys.Apply(d); err != nil {
			// In the case of rootless (including euid=0 in userns), where an
			// explicit cgroup path hasn't been set, we don't bail on error in
			// case of permission problems. Cases where limits have been set
			// (and we couldn't create our own cgroup) are handled by Set.
			if isIgnorableError(m.rootless, err) && m.cgroups.Path == "" {
				delete(m.paths, sys.Name())
				continue
			}
			return err
		}

	}
	return nil
}

func (m *manager) Destroy() error {
	if m.cgroups == nil || m.cgroups.Paths != nil {
		return nil
	}
	m.mu.Lock()
	defer m.mu.Unlock()
	if err := cgroups.RemovePaths(m.paths); err != nil {
		return err
	}
	m.paths = make(map[string]string)
	return nil
}

func (m *manager) Path(subsys string) string {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.paths[subsys]
}

func (m *manager) GetStats() (*cgroups.Stats, error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	stats := cgroups.NewStats()
	for name, path := range m.paths {
		sys, err := m.getSubsystems().Get(name)
		if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
			continue
		}
		if err := sys.GetStats(path, stats); err != nil {
			return nil, err
		}
	}
	return stats, nil
}

func (m *manager) Set(container *configs.Config) error {
	if container.Cgroups == nil {
		return nil
	}

	// If Paths are set, then we are just joining cgroups paths
	// and there is no need to set any values.
	if m.cgroups != nil && m.cgroups.Paths != nil {
		return nil
	}

	m.mu.Lock()
	defer m.mu.Unlock()
	for _, sys := range m.getSubsystems() {
		path := m.paths[sys.Name()]
		if err := sys.Set(path, container.Cgroups); err != nil {
			if m.rootless && sys.Name() == "devices" {
				continue
			}
			// When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
			// However, errors from other subsystems are not ignored.
			// see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
			if path == "" {
				// We never created a path for this cgroup, so we cannot set
				// limits for it (though we have already tried at this point).
				return fmt.Errorf("cannot set %s limit: container could not join or create cgroup", sys.Name())
			}
			return err
		}
	}

	return nil
}

// Freeze toggles the container's freezer cgroup depending on the state
// provided
func (m *manager) Freeze(state configs.FreezerState) (Err error) {
	path := m.Path("freezer")
	if m.cgroups == nil || path == "" {
		return errors.New("cannot toggle freezer: cgroups not configured for container")
	}

	prevState := m.cgroups.Resources.Freezer
	m.cgroups.Resources.Freezer = state
	defer func() {
		if Err != nil {
			m.cgroups.Resources.Freezer = prevState
		}
	}()

	freezer, err := m.getSubsystems().Get("freezer")
	if err != nil {
		return err
	}
	if err := freezer.Set(path, m.cgroups); err != nil {
		return err
	}
	return nil
}

func (m *manager) GetPids() ([]int, error) {
	return cgroups.GetPids(m.Path("devices"))
}

func (m *manager) GetAllPids() ([]int, error) {
	return cgroups.GetAllPids(m.Path("devices"))
}

func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
	root, err := getCgroupRoot()
	if err != nil {
		return nil, err
	}

	if (c.Name != "" || c.Parent != "") && c.Path != "" {
		return nil, errors.New("cgroup: either Path or Name and Parent should be used")
	}

	// XXX: Do not remove this code. Path safety is important! -- cyphar
	cgPath := libcontainerUtils.CleanPath(c.Path)
	cgParent := libcontainerUtils.CleanPath(c.Parent)
	cgName := libcontainerUtils.CleanPath(c.Name)

	innerPath := cgPath
	if innerPath == "" {
		innerPath = filepath.Join(cgParent, cgName)
	}

	return &cgroupData{
		root:      root,
		innerPath: innerPath,
		config:    c,
		pid:       pid,
	}, nil
}

func (raw *cgroupData) path(subsystem string) (string, error) {
	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
	if filepath.IsAbs(raw.innerPath) {
		mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem)
		// If we didn't mount the subsystem, there is no point we make the path.
		if err != nil {
			return "", err
		}

		// Sometimes subsystems can be mounted together as 'cpu,cpuacct'.
		return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil
	}

	// Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating
	// process could in container and shared pid namespace with host, and
	// /proc/1/cgroup could point to whole other world of cgroups.
	parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
	if err != nil {
		return "", err
	}

	return filepath.Join(parentPath, raw.innerPath), nil
}

func (raw *cgroupData) join(subsystem string) (string, error) {
	path, err := raw.path(subsystem)
	if err != nil {
		return "", err
	}
	if err := os.MkdirAll(path, 0755); err != nil {
		return "", err
	}
	if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil {
		return "", err
	}
	return path, nil
}

func removePath(p string, err error) error {
	if err != nil {
		return err
	}
	if p != "" {
		return os.RemoveAll(p)
	}
	return nil
}

func (m *manager) GetPaths() map[string]string {
	m.mu.Lock()
	defer m.mu.Unlock()
	return m.paths
}

func (m *manager) GetCgroups() (*configs.Cgroup, error) {
	return m.cgroups, nil
}

func (m *manager) GetFreezerState() (configs.FreezerState, error) {
	dir := m.Path("freezer")
	freezer, err := m.getSubsystems().Get("freezer")

	// If the container doesn't have the freezer cgroup, say it's undefined.
	if err != nil || dir == "" {
		return configs.Undefined, nil
	}
	return freezer.(*FreezerGroup).GetState(dir)
}

func (m *manager) Exists() bool {
	return cgroups.PathExists(m.Path("devices"))
}
<|endoftext|>