<commit_before>// Copyright (c) 2016 Pulcy.
//
// 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 deployment

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"

	"github.com/ryanuber/columnize"

	"github.com/pulcy/j2/fleet"
	"github.com/pulcy/j2/jobs"
)

// Run creates all applicable unit files and deploys them onto the configured cluster.
func (d *Deployment) Run() error {
	// Fetch all current units
	f, err := d.newFleetTunnel()
	if err != nil {
		return maskAny(err)
	}
	allUnits, err := f.List()
	if err != nil {
		return maskAny(err)
	}

	// Prepare UI
	ui := newStateUI(d.verbose)
	defer ui.Close()

	// Find out which current units belong to the configured job
	remainingLoadedJobUnitNames := selectUnitNames(allUnits, d.createUnitNamePredicate())

	// Create scaling group units
	defer d.cleanup()
	if err := d.generateScalingGroups(); err != nil {
		return maskAny(err)
	}

	// Ask for confirmation
	maxScale := d.scalingGroups[len(d.scalingGroups)-1].scalingGroup

	// Go over every scale
	step := 1
	totalModifications := 0
	for sgIndex, sg := range d.scalingGroups {
		// Select the loaded units that belong to this scaling group
		correctScalingGroupPredicate := func(unitName string) bool {
			return jobs.IsUnitForScalingGroup(unitName, d.job.Name, sg.scalingGroup)
		}
		loadedScalingGroupUnitNames := selectUnitNames(remainingLoadedJobUnitNames, correctScalingGroupPredicate)
		// Update remainingLoadedJobUnitNames
		remainingLoadedJobUnitNames = selectUnitNames(remainingLoadedJobUnitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Select the loaded unit name that have become obsolete
		obsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, notPredicate(containsPredicate(sg.unitNames)))
		notObsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, containsPredicate(sg.unitNames))

		// Select the unit names that are modified and need an update
		statusMap, err := f.Status()
		if err != nil {
			return maskAny(err)
		}
		isModifiedPredicate := d.isModifiedPredicate(sg, statusMap, f, ui)
		modifiedUnitNames := selectUnitNames(notObsoleteUnitNames, isModifiedPredicate)
		isFailedPredicate := d.isFailedPredicate(sg, statusMap, f, ui)
		failedUnitNames := selectUnitNames(notObsoleteUnitNames, isFailedPredicate)
		unitNamesToDestroy := append(append(obsoleteUnitNames, modifiedUnitNames...), failedUnitNames...)
		newUnitNames := selectUnitNames(sg.unitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Are there any changes?
		anyModifications := (len(loadedScalingGroupUnitNames) != len(sg.fileNames)) || (len(unitNamesToDestroy) > 0)

		// Confirm modifications
		if anyModifications && !d.force {
			curScale := sg.scalingGroup
			changes := []string{"# Unit | Action"}
			changes = append(changes, formatChanges("# ", obsoleteUnitNames, "Remove (is obsolete) !!!")...)
			changes = append(changes, formatChanges("# ", modifiedUnitNames, "Update")...)
			changes = append(changes, formatChanges("# ", failedUnitNames, "Failed state")...)
			changes = append(changes, formatChanges("# ", newUnitNames, "Create")...)
			sort.Strings(changes[1:])
			formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
			ui.HeaderSink <- fmt.Sprintf("Step %d: Update scaling group %d of %d on '%s'.\n%s\n", step, curScale, maxScale, d.cluster.Stack, formattedChanges)
			if !d.autoContinue {
				if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
					return maskAny(err)
				}
			}
		}

		// Destroy the obsolete & modified units
		if len(unitNamesToDestroy) > 0 {
			if err := d.destroyUnits(f, unitNamesToDestroy, ui); err != nil {
				return maskAny(err)
			}

			InterruptibleSleep(ui.MessageSink, d.DestroyDelay, "Waiting for %s...")
		}

		// Now launch everything
		if err := launchUnits(f, sg.fileNames, ui); err != nil {
			return maskAny(err)
		}

		// Wait a bit and ask for confirmation before continuing (only when more groups will follow)
		if anyModifications && sgIndex+1 < len(d.scalingGroups) {
			nextScale := d.scalingGroups[sgIndex+1].scalingGroup
			InterruptibleSleep(ui.MessageSink, d.SliceDelay, fmt.Sprintf("Waiting %s before continuing with scaling group %d of %d...", "%s", nextScale, maxScale))
		}

		// Update counters
		if anyModifications {
			totalModifications++
		}
		step++
		ui.Clear()
	}

	// Destroy remaining units
	if len(remainingLoadedJobUnitNames) > 0 {
		changes := []string{"# Unit | Action"}
		changes = append(changes, formatChanges("# ", remainingLoadedJobUnitNames, "Remove (is obsolete) !!!")...)
		sort.Strings(changes[1:])
		formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
		ui.HeaderSink <- fmt.Sprintf("Step %d: Cleanup of obsolete units on '%s'.\n%s\n", step, d.cluster.Stack, formattedChanges)
		if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
			return maskAny(err)
		}

		if err := d.destroyUnits(f, remainingLoadedJobUnitNames, ui); err != nil {
			return maskAny(err)
		}

		totalModifications++
	}

	// Notify in case we did nothing
	if totalModifications == 0 {
		ui.MessageSink <- "No modifications needed."
	} else {
		ui.MessageSink <- "Done."
	}

	return nil
}

// isFailedPredicate creates a predicate that returns true when the given unit file is in the failed status.
func (d *Deployment) isFailedPredicate(sg scalingGroupUnits, status fleet.StatusMap, f fleet.FleetTunnel, ui *stateUI) func(string) bool {
	return func(unitName string) bool {
		ui.MessageSink <- fmt.Sprintf("Checking state of %s", unitName)
		unitState, found := status.Get(unitName)
		if !found {
			ui.Verbosef("Unit '%s' is not found\n", unitName)
			return true
		}
		if unitState == "failed" {
			ui.Verbosef("Unit '%s' is in failed state\n", unitName)
			return true
		}
		return false
	}
}

// isModifiedPredicate creates a predicate that returns true when the given unit file is modified
func (d *Deployment) isModifiedPredicate(sg scalingGroupUnits, status fleet.StatusMap, f fleet.FleetTunnel, ui *stateUI) func(string) bool {
	return func(unitName string) bool {
		if d.force {
			return true
		}
		ui.MessageSink <- fmt.Sprintf("Checking %s for modifications", unitName)
		cat, err := f.Cat(unitName)
		if err != nil {
			ui.Verbosef("Failed to cat '%s': %#v\n", unitName, err)
			return true // Assume it is modified
		}
		newCat, err := readUnit(unitName, sg.fileNames)
		if err != nil {
			ui.Verbosef("Failed to read new '%s' unit: %#v\n", unitName, err)
			return true // Assume it is modified
		}
		if !compareUnitContent(unitName, cat, newCat, ui) {
			return true
		}
		ui.Verbosef("Unit '%s' has not changed\n", unitName)
		return false
	}
}

func readUnit(unitName string, files []string) (string, error) {
	for _, fileName := range files {
		if unitName != filepath.Base(fileName) {
			continue
		}
		data, err := ioutil.ReadFile(fileName)
		if err != nil {
			return "", maskAny(err)
		}
		return string(data), nil
	}
	return "", nil // This will ensure that the unit is considered different
}

func compareUnitContent(unitName, a, b string, ui *stateUI) bool {
	linesA := normalizeUnitContent(a)
	linesB := normalizeUnitContent(b)

	if len(linesA) != len(linesB) {
		ui.Verbosef("Length differs in %s\n", unitName)
		return false
	}
	for i, la := range linesA {
		lb := linesB[i]
		if la != lb {
			ui.Verbosef("Line %d in %s differs\n>>>> %s\n<<<< %s\n", i, unitName, la, lb)
			return false
		}
	}
	return true
}

func normalizeUnitContent(content string) []string {
	lines := strings.Split(content, "\n")
	result := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" {
			result = append(result, line)
		}
	}
	return result
}

func launchUnits(f fleet.FleetTunnel, files []string, ui *stateUI) error {
	ui.Verbosef("Starting %#v\n", files)

	if err := f.Start(ui.EventSink, files...); err != nil {
		return maskAny(err)
	}

	return nil
}

func formatChanges(prefix string, unitNames []string, action string) []string {
	result := []string{}
	for _, x := range unitNames {
		result = append(result, fmt.Sprintf("%s%s | %s", prefix, x, action))
	}
	sort.Strings(result)
	return result
}
<commit_msg>Minor UI state update<commit_after>// Copyright (c) 2016 Pulcy.
//
// 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 deployment

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strings"

	"github.com/ryanuber/columnize"

	"github.com/pulcy/j2/fleet"
	"github.com/pulcy/j2/jobs"
)

// Run creates all applicable unit files and deploys them onto the configured cluster.
func (d *Deployment) Run() error {
	// Fetch all current units
	f, err := d.newFleetTunnel()
	if err != nil {
		return maskAny(err)
	}
	allUnits, err := f.List()
	if err != nil {
		return maskAny(err)
	}

	// Prepare UI
	ui := newStateUI(d.verbose)
	defer ui.Close()

	// Find out which current units belong to the configured job
	remainingLoadedJobUnitNames := selectUnitNames(allUnits, d.createUnitNamePredicate())

	// Create scaling group units
	defer d.cleanup()
	if err := d.generateScalingGroups(); err != nil {
		return maskAny(err)
	}

	// Ask for confirmation
	maxScale := d.scalingGroups[len(d.scalingGroups)-1].scalingGroup

	// Go over every scale
	step := 1
	totalModifications := 0
	for sgIndex, sg := range d.scalingGroups {
		// Select the loaded units that belong to this scaling group
		correctScalingGroupPredicate := func(unitName string) bool {
			return jobs.IsUnitForScalingGroup(unitName, d.job.Name, sg.scalingGroup)
		}
		loadedScalingGroupUnitNames := selectUnitNames(remainingLoadedJobUnitNames, correctScalingGroupPredicate)
		// Update remainingLoadedJobUnitNames
		remainingLoadedJobUnitNames = selectUnitNames(remainingLoadedJobUnitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Select the loaded unit name that have become obsolete
		obsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, notPredicate(containsPredicate(sg.unitNames)))
		notObsoleteUnitNames := selectUnitNames(loadedScalingGroupUnitNames, containsPredicate(sg.unitNames))

		// Select the unit names that are modified and need an update
		statusMap, err := f.Status()
		if err != nil {
			return maskAny(err)
		}
		isModifiedPredicate := d.isModifiedPredicate(sg, statusMap, f, ui)
		modifiedUnitNames := selectUnitNames(notObsoleteUnitNames, isModifiedPredicate)
		isFailedPredicate := d.isFailedPredicate(sg, statusMap, f, ui)
		failedUnitNames := selectUnitNames(notObsoleteUnitNames, isFailedPredicate)
		unitNamesToDestroy := append(append(obsoleteUnitNames, modifiedUnitNames...), failedUnitNames...)
		newUnitNames := selectUnitNames(sg.unitNames, notPredicate(containsPredicate(loadedScalingGroupUnitNames)))

		// Are there any changes?
		anyModifications := (len(loadedScalingGroupUnitNames) != len(sg.fileNames)) || (len(unitNamesToDestroy) > 0)

		// Confirm modifications
		if anyModifications && !d.force {
			curScale := sg.scalingGroup
			changes := []string{"# Unit | Action"}
			changes = append(changes, formatChanges("# ", obsoleteUnitNames, "Remove (is obsolete) !!!")...)
			changes = append(changes, formatChanges("# ", modifiedUnitNames, "Update")...)
			changes = append(changes, formatChanges("# ", failedUnitNames, "Failed state")...)
			changes = append(changes, formatChanges("# ", newUnitNames, "Create")...)
			sort.Strings(changes[1:])
			formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
			ui.HeaderSink <- fmt.Sprintf("Step %d: Update scaling group %d of %d on '%s'.\n%s\n", step, curScale, maxScale, d.cluster.Stack, formattedChanges)
			if !d.autoContinue {
				if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
					return maskAny(err)
				}
			}
		}

		// Destroy the obsolete & modified units
		if len(unitNamesToDestroy) > 0 {
			if err := d.destroyUnits(f, unitNamesToDestroy, ui); err != nil {
				return maskAny(err)
			}

			InterruptibleSleep(ui.MessageSink, d.DestroyDelay, "Waiting for %s...")
		}

		// Now launch everything
		if err := launchUnits(f, sg.fileNames, ui); err != nil {
			return maskAny(err)
		}

		// Wait a bit and ask for confirmation before continuing (only when more groups will follow)
		if anyModifications && sgIndex+1 < len(d.scalingGroups) {
			nextScale := d.scalingGroups[sgIndex+1].scalingGroup
			InterruptibleSleep(ui.MessageSink, d.SliceDelay, fmt.Sprintf("Waiting %s before continuing with scaling group %d of %d...", "%s", nextScale, maxScale))
		}

		// Update counters
		if anyModifications {
			totalModifications++
		}
		step++
		ui.Clear()
	}

	// Destroy remaining units
	if len(remainingLoadedJobUnitNames) > 0 {
		changes := []string{"# Unit | Action"}
		changes = append(changes, formatChanges("# ", remainingLoadedJobUnitNames, "Remove (is obsolete) !!!")...)
		sort.Strings(changes[1:])
		formattedChanges := strings.Replace(columnize.SimpleFormat(changes), "#", " ", -1)
		ui.HeaderSink <- fmt.Sprintf("Step %d: Cleanup of obsolete units on '%s'.\n%s\n", step, d.cluster.Stack, formattedChanges)
		if err := ui.Confirm("Are you sure you want to continue?"); err != nil {
			return maskAny(err)
		}

		if err := d.destroyUnits(f, remainingLoadedJobUnitNames, ui); err != nil {
			return maskAny(err)
		}

		totalModifications++
	}

	// Notify in case we did nothing
	if totalModifications == 0 {
		ui.MessageSink <- "No modifications needed."
	} else {
		ui.MessageSink <- "Done."
	}

	return nil
}

// isFailedPredicate creates a predicate that returns true when the given unit file is in the failed status.
func (d *Deployment) isFailedPredicate(sg scalingGroupUnits, status fleet.StatusMap, f fleet.FleetTunnel, ui *stateUI) func(string) bool {
	return func(unitName string) bool {
		ui.MessageSink <- fmt.Sprintf("Checking state of %s", unitName)
		unitState, found := status.Get(unitName)
		if !found {
			ui.Verbosef("Unit '%s' is not found\n", unitName)
			return true
		}
		if unitState == "failed" {
			ui.Verbosef("Unit '%s' is in failed state\n", unitName)
			return true
		}
		return false
	}
}

// isModifiedPredicate creates a predicate that returns true when the given unit file is modified
func (d *Deployment) isModifiedPredicate(sg scalingGroupUnits, status fleet.StatusMap, f fleet.FleetTunnel, ui *stateUI) func(string) bool {
	return func(unitName string) bool {
		if d.force {
			return true
		}
		ui.MessageSink <- fmt.Sprintf("Checking %s for modifications", unitName)
		cat, err := f.Cat(unitName)
		if err != nil {
			ui.Verbosef("Failed to cat '%s': %#v\n", unitName, err)
			return true // Assume it is modified
		}
		newCat, err := readUnit(unitName, sg.fileNames)
		if err != nil {
			ui.Verbosef("Failed to read new '%s' unit: %#v\n", unitName, err)
			return true // Assume it is modified
		}
		if !compareUnitContent(unitName, cat, newCat, ui) {
			return true
		}
		ui.Verbosef("Unit '%s' has not changed\n", unitName)
		return false
	}
}

func readUnit(unitName string, files []string) (string, error) {
	for _, fileName := range files {
		if unitName != filepath.Base(fileName) {
			continue
		}
		data, err := ioutil.ReadFile(fileName)
		if err != nil {
			return "", maskAny(err)
		}
		return string(data), nil
	}
	return "", nil // This will ensure that the unit is considered different
}

func compareUnitContent(unitName, a, b string, ui *stateUI) bool {
	linesA := normalizeUnitContent(a)
	linesB := normalizeUnitContent(b)

	if len(linesA) != len(linesB) {
		ui.Verbosef("Length differs in %s\n", unitName)
		return false
	}
	for i, la := range linesA {
		lb := linesB[i]
		if la != lb {
			ui.Verbosef("Line %d in %s differs\n>>>> %s\n<<<< %s\n", i, unitName, la, lb)
			return false
		}
	}
	return true
}

func normalizeUnitContent(content string) []string {
	lines := strings.Split(content, "\n")
	result := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" {
			result = append(result, line)
		}
	}
	return result
}

func launchUnits(f fleet.FleetTunnel, files []string, ui *stateUI) error {
	ui.Verbosef("Starting %#v\n", files)

	ui.MessageSink <- fmt.Sprintf("Starting %d units", len(files))
	if err := f.Start(ui.EventSink, files...); err != nil {
		return maskAny(err)
	}

	return nil
}

func formatChanges(prefix string, unitNames []string, action string) []string {
	result := []string{}
	for _, x := range unitNames {
		result = append(result, fmt.Sprintf("%s%s | %s", prefix, x, action))
	}
	sort.Strings(result)
	return result
}
<|endoftext|>


<commit_before>package content

import (
	"encoding/json"
	"regexp"
	"time"

	"github.com/Financial-Times/neo-utils-go/neoutils"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

var uuidExtractRegex = regexp.MustCompile(".*/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$")

// CypherDriver - CypherDriver
type service struct {
	conn neoutils.NeoConnection
}

//NewCypherDriver instantiate driver
func NewCypherContentService(cypherRunner neoutils.NeoConnection) service {
	return service{cypherRunner}
}

//Initialise ensure constraint on content uuid
func (cd service) Initialise() error {

	return cd.conn.EnsureConstraints(map[string]string{
		"Content": "uuid"})
}

// Check - Feeds into the Healthcheck and checks whether we can connect to Neo and that the datastore isn't empty
func (pcd service) Check() error {
	return neoutils.Check(pcd.conn)
}

// Read - reads a content given a UUID
func (pcd service) Read(uuid string) (interface{}, bool, error) {
	results := []struct {
		content
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Content {uuid:{uuid}})
			return n.uuid as uuid, n.title as title, n.publishedDate as publishedDate`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
		Result: &results,
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return content{}, false, err
	}

	if len(results) == 0 {
		return content{}, false, nil
	}

	result := results[0]

	contentItem := content{
		UUID:          result.UUID,
		Title:         result.Title,
		PublishedDate: result.PublishedDate,
	}
	return contentItem, true, nil
}

//Write - Writes a content node
func (pcd service) Write(thing interface{}) error {
	c := thing.(content)

	// Only Articles have a body
	if c.Body == "" {
		log.Infof("There is no body with this content item therefore assuming is it not an Article: %v", c.UUID)
		return nil
	}

	params := map[string]interface{}{
		"uuid": c.UUID,
	}

	if c.Title != "" {
		params["title"] = c.Title
		params["prefLabel"] = c.Title
	}

	if c.PublishedDate != "" {
		params["publishedDate"] = c.PublishedDate
		datetimeEpoch, err := time.Parse(time.RFC3339, c.PublishedDate)

		if err != nil {
			return err
		}

		params["publishedDateEpoch"] = datetimeEpoch.Unix()
	}

	statement := `MERGE (n:Thing {uuid: {uuid}})
		      set n={allprops}
		      set n :Content`

	writeContentQuery := &neoism.CypherQuery{
		Statement: statement,
		Parameters: map[string]interface{}{
			"uuid":     c.UUID,
			"allprops": params,
		},
	}
	queries := []*neoism.CypherQuery{writeContentQuery}

	return pcd.conn.CypherBatch(queries)
}

//Delete - Deletes a content
func (pcd service) Delete(uuid string) (bool, error) {
	clearNode := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			REMOVE p:Content
			SET p={props}
		`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
			"props": map[string]interface{}{
				"uuid": uuid,
			},
		},
		IncludeStats: true,
	}

	removeNodeIfUnused := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			OPTIONAL MATCH (p)-[a]-(x)
			WITH p, count(a) AS relCount
			WHERE relCount = 0
			DELETE p
		`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{clearNode, removeNodeIfUnused})

	s1, err := clearNode.Stats()
	if err != nil {
		return false, err
	}

	var deleted bool
	if s1.ContainsUpdates && s1.LabelsRemoved > 0 {
		deleted = true
	}

	return deleted, err
}

// DecodeJSON - Decodes JSON into content
func (pcd service) DecodeJSON(dec *json.Decoder) (interface{}, string, error) {
	c := content{}
	err := dec.Decode(&c)
	return c, c.UUID, err

}

// Count - Returns a count of the number of content in this Neo instance
func (pcd service) Count() (int, error) {

	results := []struct {
		Count int `json:"c"`
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Content) return count(n) as c`,
		Result:    &results,
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return 0, err
	}

	return results[0].Count, nil
}

<commit_msg>inlined CypherQuery creation statements<commit_after>package content

import (
	"encoding/json"
	"regexp"
	"time"

	"github.com/Financial-Times/neo-utils-go/neoutils"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

var uuidExtractRegex = regexp.MustCompile(".*/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$")

// CypherDriver - CypherDriver
type service struct {
	conn neoutils.NeoConnection
}

//NewCypherDriver instantiate driver
func NewCypherContentService(cypherRunner neoutils.NeoConnection) service {
	return service{cypherRunner}
}

//Initialise ensure constraint on content uuid
func (cd service) Initialise() error {

	return cd.conn.EnsureConstraints(map[string]string{
		"Content": "uuid"})
}

// Check - Feeds into the Healthcheck and checks whether we can connect to Neo and that the datastore isn't empty
func (pcd service) Check() error {
	return neoutils.Check(pcd.conn)
}

// Read - reads a content given a UUID
func (pcd service) Read(uuid string) (interface{}, bool, error) {
	results := []struct {
		content
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Content {uuid:{uuid}})
			return n.uuid as uuid, n.title as title, n.publishedDate as publishedDate`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
		Result: &results,
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return content{}, false, err
	}

	if len(results) == 0 {
		return content{}, false, nil
	}

	result := results[0]

	contentItem := content{
		UUID:          result.UUID,
		Title:         result.Title,
		PublishedDate: result.PublishedDate,
	}
	return contentItem, true, nil
}

//Write - Writes a content node
func (pcd service) Write(thing interface{}) error {
	c := thing.(content)

	// Only Articles have a body
	if c.Body == "" {
		log.Infof("There is no body with this content item therefore assuming is it not an Article: %v", c.UUID)
		return nil
	}

	params := map[string]interface{}{
		"uuid": c.UUID,
	}

	if c.Title != "" {
		params["title"] = c.Title
		params["prefLabel"] = c.Title
	}

	if c.PublishedDate != "" {
		params["publishedDate"] = c.PublishedDate
		datetimeEpoch, err := time.Parse(time.RFC3339, c.PublishedDate)

		if err != nil {
			return err
		}

		params["publishedDateEpoch"] = datetimeEpoch.Unix()
	}

	statement := `MERGE (n:Thing {uuid: {uuid}})
		      set n={allprops}
		      set n :Content`

	return pcd.conn.CypherBatch(
		[]*neoism.CypherQuery{
			{
				Statement: statement,
				Parameters: map[string]interface{}{
					"uuid":     c.UUID,
					"allprops": params,
				},
			},
		},
	)
}

//Delete - Deletes a content
func (pcd service) Delete(uuid string) (bool, error) {
	clearNode := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			REMOVE p:Content
			SET p={props}
		`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
			"props": map[string]interface{}{
				"uuid": uuid,
			},
		},
		IncludeStats: true,
	}

	removeNodeIfUnused := &neoism.CypherQuery{
		Statement: `
			MATCH (p:Thing {uuid: {uuid}})
			OPTIONAL MATCH (p)-[a]-(x)
			WITH p, count(a) AS relCount
			WHERE relCount = 0
			DELETE p
		`,
		Parameters: map[string]interface{}{
			"uuid": uuid,
		},
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{clearNode, removeNodeIfUnused})

	s1, err := clearNode.Stats()
	if err != nil {
		return false, err
	}

	var deleted bool
	if s1.ContainsUpdates && s1.LabelsRemoved > 0 {
		deleted = true
	}

	return deleted, err
}

// DecodeJSON - Decodes JSON into content
func (pcd service) DecodeJSON(dec *json.Decoder) (interface{}, string, error) {
	c := content{}
	err := dec.Decode(&c)
	return c, c.UUID, err

}

// Count - Returns a count of the number of content in this Neo instance
func (pcd service) Count() (int, error) {

	results := []struct {
		Count int `json:"c"`
	}{}

	query := &neoism.CypherQuery{
		Statement: `MATCH (n:Content) return count(n) as c`,
		Result:    &results,
	}

	err := pcd.conn.CypherBatch([]*neoism.CypherQuery{query})

	if err != nil {
		return 0, err
	}

	return results[0].Count, nil
}

<|endoftext|>


<commit_before>// Copyright 2021 The Oto 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 oto

import (
	"fmt"
	"sync"
	"time"
	"unsafe"

	"github.com/ebitengine/purego/objc"

	"github.com/hajimehoshi/oto/v2/internal/mux"
)

const (
	float32SizeInBytes = 4

	noErr = 0
)

func newAudioQueue(sampleRate, channelCount int) (_AudioQueueRef, []_AudioQueueBufferRef, error) {
	desc := _AudioStreamBasicDescription{
		mSampleRate:       float64(sampleRate),
		mFormatID:         uint32(kAudioFormatLinearPCM),
		mFormatFlags:      uint32(kAudioFormatFlagIsFloat),
		mBytesPerPacket:   uint32(channelCount * float32SizeInBytes),
		mFramesPerPacket:  1,
		mBytesPerFrame:    uint32(channelCount * float32SizeInBytes),
		mChannelsPerFrame: uint32(channelCount),
		mBitsPerChannel:   uint32(8 * float32SizeInBytes),
	}

	var audioQueue _AudioQueueRef
	if osstatus := _AudioQueueNewOutput(
		&desc,
		render,
		nil,
		0, //CFRunLoopRef
		0, //CFStringRef
		0,
		&audioQueue); osstatus != noErr {
		return 0, nil, fmt.Errorf("oto: AudioQueueNewFormat with StreamFormat failed: %d", osstatus)
	}

	bufs := make([]_AudioQueueBufferRef, 0, 4)
	for len(bufs) < cap(bufs) {
		var buf _AudioQueueBufferRef
		if osstatus := _AudioQueueAllocateBuffer(audioQueue, bufferSizeInBytes, &buf); osstatus != noErr {
			return 0, nil, fmt.Errorf("oto: AudioQueueAllocateBuffer failed: %d", osstatus)
		}
		buf.mAudioDataByteSize = bufferSizeInBytes
		bufs = append(bufs, buf)
	}

	return audioQueue, bufs, nil
}

type context struct {
	audioQueue      _AudioQueueRef
	unqueuedBuffers []_AudioQueueBufferRef

	cond *sync.Cond

	mux *mux.Mux
	err atomicError
}

// TODO: Convert the error code correctly.
// See https://stackoverflow.com/questions/2196869/how-do-you-convert-an-iphone-osstatus-code-to-something-useful

var theContext *context

func newContext(sampleRate int, channelCount int, format mux.Format) (*context, chan struct{}, error) {
	ready := make(chan struct{})

	c := &context{
		cond: sync.NewCond(&sync.Mutex{}),
		mux:  mux.New(sampleRate, channelCount, format),
	}
	theContext = c

	go func() {
		q, bs, err := newAudioQueue(sampleRate, channelCount)
		if err != nil {
			c.err.TryStore(err)
			return
		}
		c.audioQueue = q
		c.unqueuedBuffers = bs

		setNotificationHandler()

		var retryCount int
	try:
		if osstatus := _AudioQueueStart(c.audioQueue, nil); osstatus != noErr {
			if osstatus == avAudioSessionErrorCodeCannotStartPlaying && retryCount < 100 {
				// TODO: use sleepTime() after investigating when this error happens.
				time.Sleep(10 * time.Millisecond)
				retryCount++
				goto try
			}
			c.err.TryStore(fmt.Errorf("oto: AudioQueueStart failed at newContext: %d", osstatus))
			return
		}

		go c.loop()

		close(ready)
	}()

	return c, ready, nil
}

func (c *context) wait() bool {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	for len(c.unqueuedBuffers) == 0 && c.err.Load() == nil {
		c.cond.Wait()
	}
	return c.err.Load() == nil
}

func (c *context) loop() {
	buf32 := make([]float32, bufferSizeInBytes/4)
	for {
		if !c.wait() {
			return
		}
		c.appendBuffer(buf32)
	}
}

func (c *context) appendBuffer(buf32 []float32) {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if c.err.Load() != nil {
		return
	}

	buf := c.unqueuedBuffers[0]
	copy(c.unqueuedBuffers, c.unqueuedBuffers[1:])
	c.unqueuedBuffers = c.unqueuedBuffers[:len(c.unqueuedBuffers)-1]

	c.mux.ReadFloat32s(buf32)
	copy(unsafe.Slice((*float32)(unsafe.Pointer(buf.mAudioData)), buf.mAudioDataByteSize/float32SizeInBytes), buf32)

	if osstatus := _AudioQueueEnqueueBuffer(c.audioQueue, buf, 0, nil); osstatus != noErr {
		c.err.TryStore(fmt.Errorf("oto: AudioQueueEnqueueBuffer failed: %d", osstatus))
	}
}

func (c *context) Suspend() error {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if err := c.err.Load(); err != nil {
		return err.(error)
	}
	if osstatus := _AudioQueuePause(c.audioQueue); osstatus != noErr {
		return fmt.Errorf("oto: AudioQueuePause failed: %d", osstatus)
	}
	return nil
}

func (c *context) Resume() error {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if err := c.err.Load(); err != nil {
		return err.(error)
	}

	var retryCount int
try:
	if osstatus := _AudioQueueStart(c.audioQueue, nil); osstatus != noErr {
		if (osstatus == avAudioSessionErrorCodeCannotStartPlaying ||
			osstatus == avAudioSessionErrorCodeCannotInterruptOthers) &&
			retryCount < 30 {
			// It is uncertain that this error is temporary or not. Then let's use exponential-time sleeping.
			time.Sleep(sleepTime(retryCount))
			retryCount++
			goto try
		}
		if osstatus == avAudioSessionErrorCodeSiriIsRecording {
			// As this error should be temporary, it should be OK to use a short time for sleep anytime.
			time.Sleep(10 * time.Millisecond)
			goto try
		}
		return fmt.Errorf("oto: AudioQueueStart failed at Resume: %d", osstatus)
	}
	return nil
}

func (c *context) Err() error {
	if err := c.err.Load(); err != nil {
		return err.(error)
	}
	return nil
}

func render(inUserData unsafe.Pointer, inAQ _AudioQueueRef, inBuffer _AudioQueueBufferRef) {
	theContext.cond.L.Lock()
	defer theContext.cond.L.Unlock()
	theContext.unqueuedBuffers = append(theContext.unqueuedBuffers, inBuffer)
	theContext.cond.Signal()
}

func setGlobalPause(self objc.ID, _cmd objc.SEL, notification objc.ID) {
	theContext.Suspend()
}

func setGlobalResume(self objc.ID, _cmd objc.SEL, notification objc.ID) {
	theContext.Resume()
}

func sleepTime(count int) time.Duration {
	switch count {
	case 0:
		return 10 * time.Millisecond
	case 1:
		return 20 * time.Millisecond
	case 2:
		return 50 * time.Millisecond
	default:
		return 100 * time.Millisecond
	}
}
<commit_msg>oto: use defer to close the ready channel on macOS<commit_after>// Copyright 2021 The Oto 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 oto

import (
	"fmt"
	"sync"
	"time"
	"unsafe"

	"github.com/ebitengine/purego/objc"

	"github.com/hajimehoshi/oto/v2/internal/mux"
)

const (
	float32SizeInBytes = 4

	noErr = 0
)

func newAudioQueue(sampleRate, channelCount int) (_AudioQueueRef, []_AudioQueueBufferRef, error) {
	desc := _AudioStreamBasicDescription{
		mSampleRate:       float64(sampleRate),
		mFormatID:         uint32(kAudioFormatLinearPCM),
		mFormatFlags:      uint32(kAudioFormatFlagIsFloat),
		mBytesPerPacket:   uint32(channelCount * float32SizeInBytes),
		mFramesPerPacket:  1,
		mBytesPerFrame:    uint32(channelCount * float32SizeInBytes),
		mChannelsPerFrame: uint32(channelCount),
		mBitsPerChannel:   uint32(8 * float32SizeInBytes),
	}

	var audioQueue _AudioQueueRef
	if osstatus := _AudioQueueNewOutput(
		&desc,
		render,
		nil,
		0, //CFRunLoopRef
		0, //CFStringRef
		0,
		&audioQueue); osstatus != noErr {
		return 0, nil, fmt.Errorf("oto: AudioQueueNewFormat with StreamFormat failed: %d", osstatus)
	}

	bufs := make([]_AudioQueueBufferRef, 0, 4)
	for len(bufs) < cap(bufs) {
		var buf _AudioQueueBufferRef
		if osstatus := _AudioQueueAllocateBuffer(audioQueue, bufferSizeInBytes, &buf); osstatus != noErr {
			return 0, nil, fmt.Errorf("oto: AudioQueueAllocateBuffer failed: %d", osstatus)
		}
		buf.mAudioDataByteSize = bufferSizeInBytes
		bufs = append(bufs, buf)
	}

	return audioQueue, bufs, nil
}

type context struct {
	audioQueue      _AudioQueueRef
	unqueuedBuffers []_AudioQueueBufferRef

	cond *sync.Cond

	mux *mux.Mux
	err atomicError
}

// TODO: Convert the error code correctly.
// See https://stackoverflow.com/questions/2196869/how-do-you-convert-an-iphone-osstatus-code-to-something-useful

var theContext *context

func newContext(sampleRate int, channelCount int, format mux.Format) (*context, chan struct{}, error) {
	ready := make(chan struct{})

	c := &context{
		cond: sync.NewCond(&sync.Mutex{}),
		mux:  mux.New(sampleRate, channelCount, format),
	}
	theContext = c

	go func() {
		defer close(ready)

		q, bs, err := newAudioQueue(sampleRate, channelCount)
		if err != nil {
			c.err.TryStore(err)
			return
		}
		c.audioQueue = q
		c.unqueuedBuffers = bs

		setNotificationHandler()

		var retryCount int
	try:
		if osstatus := _AudioQueueStart(c.audioQueue, nil); osstatus != noErr {
			if osstatus == avAudioSessionErrorCodeCannotStartPlaying && retryCount < 100 {
				// TODO: use sleepTime() after investigating when this error happens.
				time.Sleep(10 * time.Millisecond)
				retryCount++
				goto try
			}
			c.err.TryStore(fmt.Errorf("oto: AudioQueueStart failed at newContext: %d", osstatus))
			return
		}

		go c.loop()
	}()

	return c, ready, nil
}

func (c *context) wait() bool {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	for len(c.unqueuedBuffers) == 0 && c.err.Load() == nil {
		c.cond.Wait()
	}
	return c.err.Load() == nil
}

func (c *context) loop() {
	buf32 := make([]float32, bufferSizeInBytes/4)
	for {
		if !c.wait() {
			return
		}
		c.appendBuffer(buf32)
	}
}

func (c *context) appendBuffer(buf32 []float32) {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if c.err.Load() != nil {
		return
	}

	buf := c.unqueuedBuffers[0]
	copy(c.unqueuedBuffers, c.unqueuedBuffers[1:])
	c.unqueuedBuffers = c.unqueuedBuffers[:len(c.unqueuedBuffers)-1]

	c.mux.ReadFloat32s(buf32)
	copy(unsafe.Slice((*float32)(unsafe.Pointer(buf.mAudioData)), buf.mAudioDataByteSize/float32SizeInBytes), buf32)

	if osstatus := _AudioQueueEnqueueBuffer(c.audioQueue, buf, 0, nil); osstatus != noErr {
		c.err.TryStore(fmt.Errorf("oto: AudioQueueEnqueueBuffer failed: %d", osstatus))
	}
}

func (c *context) Suspend() error {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if err := c.err.Load(); err != nil {
		return err.(error)
	}
	if osstatus := _AudioQueuePause(c.audioQueue); osstatus != noErr {
		return fmt.Errorf("oto: AudioQueuePause failed: %d", osstatus)
	}
	return nil
}

func (c *context) Resume() error {
	c.cond.L.Lock()
	defer c.cond.L.Unlock()

	if err := c.err.Load(); err != nil {
		return err.(error)
	}

	var retryCount int
try:
	if osstatus := _AudioQueueStart(c.audioQueue, nil); osstatus != noErr {
		if (osstatus == avAudioSessionErrorCodeCannotStartPlaying ||
			osstatus == avAudioSessionErrorCodeCannotInterruptOthers) &&
			retryCount < 30 {
			// It is uncertain that this error is temporary or not. Then let's use exponential-time sleeping.
			time.Sleep(sleepTime(retryCount))
			retryCount++
			goto try
		}
		if osstatus == avAudioSessionErrorCodeSiriIsRecording {
			// As this error should be temporary, it should be OK to use a short time for sleep anytime.
			time.Sleep(10 * time.Millisecond)
			goto try
		}
		return fmt.Errorf("oto: AudioQueueStart failed at Resume: %d", osstatus)
	}
	return nil
}

func (c *context) Err() error {
	if err := c.err.Load(); err != nil {
		return err.(error)
	}
	return nil
}

func render(inUserData unsafe.Pointer, inAQ _AudioQueueRef, inBuffer _AudioQueueBufferRef) {
	theContext.cond.L.Lock()
	defer theContext.cond.L.Unlock()
	theContext.unqueuedBuffers = append(theContext.unqueuedBuffers, inBuffer)
	theContext.cond.Signal()
}

func setGlobalPause(self objc.ID, _cmd objc.SEL, notification objc.ID) {
	theContext.Suspend()
}

func setGlobalResume(self objc.ID, _cmd objc.SEL, notification objc.ID) {
	theContext.Resume()
}

func sleepTime(count int) time.Duration {
	switch count {
	case 0:
		return 10 * time.Millisecond
	case 1:
		return 20 * time.Millisecond
	case 2:
		return 50 * time.Millisecond
	default:
		return 100 * time.Millisecond
	}
}
<|endoftext|>


<commit_before>package antenna

import (
	"bitbucket.org/ikeikeikeike/antenna/controllers"
	"bitbucket.org/ikeikeikeike/antenna/controllers/admin"
	"bitbucket.org/ikeikeikeike/antenna/controllers/public"
	_ "bitbucket.org/ikeikeikeike/antenna/routers"
	"github.com/astaxie/beego"
)

func init() {
	// Public

	beego.Router("/", &public.EntriesController{}, "get:Home")

	beego.Router("/news.html", &public.EntriesController{}, "get:News")
	beego.Router("/hots.html", &public.EntriesController{}, "get:Hots")

	beego.Router("/search.html", &public.EntriesController{}, "get:Search")

	beego.Router(`/elog/v:id([0-9]+)/`, &public.EntriesController{}, "get:Show")
	beego.Router(`/elog/v:id([0-9]+)/:title(.*)?`, &public.EntriesController{}, "get:Show")

	beego.Router("/blogs.html", &public.BlogsController{}, "get:Index")
	beego.Router(`/blog/v:id([0-9]+)/`, &public.BlogsController{}, "get:Show")
	beego.Router(`/blog/v:id([0-9]+)/:title(.*)?`, &public.BlogsController{}, "get:Show")

	beego.Router("/ranking/dayly", &public.RankingsController{}, "get:Dayly")
	beego.Router("/ranking/weekly", &public.RankingsController{}, "get:Weekly")
	beego.Router("/ranking/monthly", &public.RankingsController{}, "get:Monthly")
	beego.Router("/ranking/yearly", &public.RankingsController{}, "get:Yearly")

	beego.Router("/tags.html", &public.TagsController{}, "get:Index")
	beego.Router(`/tag/:name`, &public.TagsController{}, "get:Show")

	beego.Router("/divas.html", &public.DivasController{}, "get:Index")
	beego.Router(`/diva/:name`, &public.DivasController{}, "get,post:Show")

	beego.Router("/animes.html", &public.AnimesController{}, "get:Index")
	beego.Router(`/anime/:name`, &public.AnimesController{}, "get,post:Show")

	beego.Router("/characters.html", &public.CharactersController{}, "get:Index")
	beego.Router(`/character/:name`, &public.CharactersController{}, "get,post:Show")

	beego.Router(`/register.html`, &public.RegistersController{}, "get:Index")
	beego.Router(`/register/parts.html`, &public.RegistersController{}, "get:Parts")
	beego.Router(`/register/links.html`, &public.RegistersController{}, "get:Links")
	beego.Router(`/register/rss.html`, &public.RegistersController{}, "get:Rss")

	beego.Router(`/feed/rdf.xml`, &public.FeedsController{}, "get:Rdf")
	beego.Router(`/feed/rss.xml`, &public.FeedsController{}, "get:Rss")
	beego.Router(`/feed/atom.xml`, &public.FeedsController{}, "get:Atom")

	beego.Router(`/abouts.html`, &public.AboutsController{}, "get:Index")

	beego.Router(`/v1/parts.js`, &public.ApisController{}, "post:Parts")

	// Admin

	beego.Router("/admin/signup", &admin.LoginController{}, "get,post:Signup")
	beego.Router("/admin/signup_confirm", &admin.LoginController{}, "get:SignupConfirm")
	beego.Router("/admin/login", &admin.LoginController{}, "get,post:Login")
	beego.Router("/admin/logout", &admin.LoginController{}, "get:Logout")
	beego.Router("/admin/password_reset", &admin.LoginController{}, "get,post:PasswordReset")
	beego.Router("/admin/reset_confirm", &admin.LoginController{}, "get,post:ResetConfirm")

	beego.Router(`/admin`, &admin.UsersController{}, "get:Index")
	beego.Router(`/admin/blog`, &admin.UsersController{}, "get,post:BlogRegister")
	beego.Router(`/admin/blog/:id([0-9]+)`, &admin.UsersController{}, "get,post:Blog")
	beego.Router(`/admin/blogs`, &admin.UsersController{}, "get:Blogs")
	beego.Router(`/admin/change_email`, &admin.UsersController{}, "get,post:ChangeMail")
	beego.Router("/admin/mail_confirm", &admin.UsersController{}, "get:MailConfirm")

	beego.Router("/admin/blog_remove", &admin.UsersController{}, "delete:BlogRemove")
	beego.Router("/admin/account_remove", &admin.UsersController{}, "delete:AccountRemove")
	// beego.Router(`/admin/change_password`, &admin.UsersController{}, "get,post:ChangePassword")

	beego.Router(`/admin/terms.html`, &admin.LicensesController{}, "get:Terms")
	beego.Router(`/admin/privacy.html`, &admin.LicensesController{}, "get:Privacy")
	beego.Router(`/admin/guideline.html`, &admin.LicensesController{}, "get:Guideline")

	// ext
	beego.Router(`/ok.ico`, &controllers.OkController{}, "get:Helthcheck")
}
<commit_msg>rankings<commit_after>package antenna

import (
	"bitbucket.org/ikeikeikeike/antenna/controllers"
	"bitbucket.org/ikeikeikeike/antenna/controllers/admin"
	"bitbucket.org/ikeikeikeike/antenna/controllers/public"
	_ "bitbucket.org/ikeikeikeike/antenna/routers"
	"github.com/astaxie/beego"
)

func init() {
	// Public

	beego.Router("/", &public.EntriesController{}, "get:Home")

	beego.Router("/news.html", &public.EntriesController{}, "get:News")
	beego.Router("/hots.html", &public.EntriesController{}, "get:Hots")

	beego.Router("/search.html", &public.EntriesController{}, "get:Search")

	beego.Router(`/elog/v:id([0-9]+)/`, &public.EntriesController{}, "get:Show")
	beego.Router(`/elog/v:id([0-9]+)/:title(.*)?`, &public.EntriesController{}, "get:Show")

	beego.Router("/blogs.html", &public.BlogsController{}, "get:Index")
	beego.Router(`/blog/v:id([0-9]+)/`, &public.BlogsController{}, "get:Show")
	beego.Router(`/blog/v:id([0-9]+)/:title(.*)?`, &public.BlogsController{}, "get:Show")

	beego.Router("/ranking/dayly", &public.RankingsController{}, "get:Dayly")
	beego.Router("/ranking/weekly", &public.RankingsController{}, "get:Weekly")
	beego.Router("/ranking/monthly", &public.RankingsController{}, "get:Monthly")
	beego.Router("/ranking/yearly", &public.RankingsController{}, "get:Yearly")
	beego.Router("/ranking/calendar", &public.RankingsController{}, "get:Calendar")

	beego.Router("/tags.html", &public.TagsController{}, "get:Index")
	beego.Router(`/tag/:name`, &public.TagsController{}, "get:Show")

	beego.Router("/divas.html", &public.DivasController{}, "get:Index")
	beego.Router(`/diva/:name`, &public.DivasController{}, "get,post:Show")

	beego.Router("/animes.html", &public.AnimesController{}, "get:Index")
	beego.Router(`/anime/:name`, &public.AnimesController{}, "get,post:Show")

	beego.Router("/characters.html", &public.CharactersController{}, "get:Index")
	beego.Router(`/character/:name`, &public.CharactersController{}, "get,post:Show")

	beego.Router(`/register.html`, &public.RegistersController{}, "get:Index")
	beego.Router(`/register/parts.html`, &public.RegistersController{}, "get:Parts")
	beego.Router(`/register/links.html`, &public.RegistersController{}, "get:Links")
	beego.Router(`/register/rss.html`, &public.RegistersController{}, "get:Rss")

	beego.Router(`/feed/rdf.xml`, &public.FeedsController{}, "get:Rdf")
	beego.Router(`/feed/rss.xml`, &public.FeedsController{}, "get:Rss")
	beego.Router(`/feed/atom.xml`, &public.FeedsController{}, "get:Atom")

	beego.Router(`/abouts.html`, &public.AboutsController{}, "get:Index")

	beego.Router(`/v1/parts.js`, &public.ApisController{}, "post:Parts")

	// Admin

	beego.Router("/admin/signup", &admin.LoginController{}, "get,post:Signup")
	beego.Router("/admin/signup_confirm", &admin.LoginController{}, "get:SignupConfirm")
	beego.Router("/admin/login", &admin.LoginController{}, "get,post:Login")
	beego.Router("/admin/logout", &admin.LoginController{}, "get:Logout")
	beego.Router("/admin/password_reset", &admin.LoginController{}, "get,post:PasswordReset")
	beego.Router("/admin/reset_confirm", &admin.LoginController{}, "get,post:ResetConfirm")

	beego.Router(`/admin`, &admin.UsersController{}, "get:Index")
	beego.Router(`/admin/blog`, &admin.UsersController{}, "get,post:BlogRegister")
	beego.Router(`/admin/blog/:id([0-9]+)`, &admin.UsersController{}, "get,post:Blog")
	beego.Router(`/admin/blogs`, &admin.UsersController{}, "get:Blogs")
	beego.Router(`/admin/change_email`, &admin.UsersController{}, "get,post:ChangeMail")
	beego.Router("/admin/mail_confirm", &admin.UsersController{}, "get:MailConfirm")

	beego.Router("/admin/blog_remove", &admin.UsersController{}, "delete:BlogRemove")
	beego.Router("/admin/account_remove", &admin.UsersController{}, "delete:AccountRemove")
	// beego.Router(`/admin/change_password`, &admin.UsersController{}, "get,post:ChangePassword")

	beego.Router(`/admin/terms.html`, &admin.LicensesController{}, "get:Terms")
	beego.Router(`/admin/privacy.html`, &admin.LicensesController{}, "get:Privacy")
	beego.Router(`/admin/guideline.html`, &admin.LicensesController{}, "get:Guideline")

	// ext
	beego.Router(`/ok.ico`, &controllers.OkController{}, "get:Helthcheck")
}
<|endoftext|>


<commit_before>package lib

import (
    "fmt"
    "os"
    "strconv"
    "time"

    . "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) rawSetBucketACL(bucket, acl string, force bool) (bool, error) {
    args := []string{CloudURLToString(bucket, ""), acl}
    showElapse, err := s.rawSetACLWithArgs(args, false, true, force)
    return showElapse, err
}

func (s *OssutilCommandSuite) rawSetObjectACL(bucket, object, acl string, recursive, force bool) (bool, error) {
    args := []string{CloudURLToString(bucket, object), acl}
    showElapse, err := s.rawSetACLWithArgs(args, recursive, false, force)
    return showElapse, err
}

func (s *OssutilCommandSuite) rawSetACLWithArgs(args []string, recursive, bucket, force bool) (bool, error) {
    command := "set-acl"
    str := ""
    routines := strconv.Itoa(Routines)
    options := OptionMapType{
        "endpoint": &str,
        "accessKeyID": &str,
        "accessKeySecret": &str,
        "stsToken": &str,
        "configFile": &configFile,
        "routines": &routines,
        "recursive": &recursive,
        "bucket": &bucket,
        "force": &force,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    time.Sleep(sleepTime)
    return showElapse, err
}

func (s *OssutilCommandSuite) TestSetBucketACL(c *C) {
    bucket := bucketNameExist

    // set acl
    for _, acl := range []string{"private", "public-read", "public-read-write"} {
        s.setBucketACL(bucket, acl, c)
        bucketStat := s.getStat(bucket, "", c)
        c.Assert(bucketStat[StatACL], Equals, acl)
    }
}

func (s *OssutilCommandSuite) TestSetBucketErrorACL(c *C) {
    bucket := bucketNameDest

    for _, acl := range []string{"default", "def", "erracl", "私有"} {
        showElapse, err := s.rawSetBucketACL(bucket, acl, false)
        c.Assert(err, NotNil)
        c.Assert(showElapse, Equals, false)

        showElapse, err = s.rawSetBucketACL(bucket, acl, true)
        c.Assert(err, NotNil)
        c.Assert(showElapse, Equals, false)

        bucketStat := s.getStat(bucket, "", c)
        c.Assert(bucketStat[StatACL], Equals, "private")
    }
}

func (s *OssutilCommandSuite) TestSetNotExistBucketACL(c *C) {
    bucket := bucketNamePrefix + "noexistsetacl"

    showElapse, err := s.rawGetStat(bucket, "")
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // set acl and create bucket
    showElapse, err = s.rawSetBucketACL(bucket, "public-read", true)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    time.Sleep(sleepTime)
    bucketStat := s.getStat(bucket, "", c)
    c.Assert(bucketStat[StatACL], Equals, "public-read")

    s.removeBucket(bucket, true, c)
    time.Sleep(3*sleepTime)

    // invalid bucket name
    bucket = "a"
    showElapse, err = s.rawSetBucketACL(bucket, "public-read", true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawGetStat(bucket, "")
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestSetBucketEmptyACL(c *C) {
    bucket := bucketNamePrefix + "acl3"
    s.putBucket(bucket, c)
    time.Sleep(sleepTime)

    object := "test"
    s.putObject(bucket, object, uploadFileName, c)

    showElapse, err := s.rawSetObjectACL(bucket, object, "", false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    s.removeBucket(bucket, true, c)
    time.Sleep(sleepTime)
}

func (s *OssutilCommandSuite) TestSetObjectACL(c *C) {
    bucket := bucketNameSetACL

    object := "TestSetObjectACL"

    // set acl to not exist object
    showElapse, err := s.rawSetObjectACL(bucket, object, "default", false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    object = "setacl-oldobject"
    s.putObject(bucket, object, uploadFileName, c)

    //get object acl
    objectStat := s.getStat(bucket, object, c)
    c.Assert(objectStat[StatACL], Equals, "default")

    object = "setacl-newobject"
    s.putObject(bucket, object, uploadFileName, c)

    // set acl
    for _, acl := range []string{"default", "private", "public-read", "public-read-write"} {
        s.setObjectACL(bucket, object, acl, false, true, c)
        objectStat = s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, acl)
    }

    s.setObjectACL(bucket, object, "private", false, true, c)

    // set error acl
    for _, acl := range []string{"public_read", "erracl", "私有"} {
        showElapse, err = s.rawSetObjectACL(bucket, object, acl, false, false)
        c.Assert(showElapse, Equals, false)
        c.Assert(err, NotNil)

        objectStat = s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "private")
    }
}

func (s *OssutilCommandSuite) TestBatchSetObjectACL(c *C) {
    bucket := bucketNameSetACL1

    // put objects
    num := 3
    objectNames := []string{}
    for i := 0; i < num; i++ {
        object := fmt.Sprintf("TestBatchSetObjectACL_setacl:%d", i)
        s.putObject(bucket, object, uploadFileName, c)
        objectNames = append(objectNames, object)
    }
    time.Sleep(time.Second)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }

    // without --force option
    s.setObjectACL(bucket, "", "public-read-write", true, false, c)
    time.Sleep(2*sleepTime)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }

    for _, acl := range []string{"public-read", "private", "default", "public-read-write"} {
        s.setObjectACL(bucket, "TestBatchSetObjectACL_setacl", acl, true, true, c)
        time.Sleep(2*sleepTime)

        for _, object := range objectNames {
            objectStat := s.getStat(bucket, object, c)
            fmt.Println(objectStat)
            c.Assert(objectStat[StatACL], Equals, acl)
        }
    }

    showElapse, err := s.rawSetObjectACL(bucket, "TestBatchSetObjectACL_setacl", "erracl", true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestErrSetACL(c *C) {
    acl := "private"
    args := []string{"os://", acl}
    showElapse, err := s.rawSetACLWithArgs(args, false, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{"oss://", acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, false, true)

    // error set bucket acl
    bucket := bucketNamePrefix + "set-acl"
    object := "testobject"
    args = []string{CloudURLToString(bucket, object), acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, ""), acl}
    showElapse, err = s.rawSetACLWithArgs(args, true, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // miss acl
    args = []string{CloudURLToString(bucket, "")}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, object)}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, object)}
    showElapse, err = s.rawSetACLWithArgs(args, true, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // miss object
    args = []string{CloudURLToString(bucket, ""), acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // bad prefix
    showElapse, err = s.rawSetObjectACL(bucket, "/object", acl, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestErrBatchSetACL(c *C) {
    bucket := bucketNameExist

    // put objects
    num := 10
    objectNames := []string{}
    for i := 0; i < num; i++ {
        object := fmt.Sprintf("TestErrBatchSetACL_setacl:%d", i)
        s.putObject(bucket, object, uploadFileName, c)
        objectNames = append(objectNames, object)
    }

    command := "set-acl"
    str := ""
    str1 := "abc"
    args := []string{CloudURLToString(bucket, ""), "public-read-write"}
    routines := strconv.Itoa(Routines)
    ok := true
    options := OptionMapType{
        "endpoint": &str1,
        "accessKeyID": &str1,
        "accessKeySecret": &str1,
        "stsToken": &str,
        "routines": &routines,
        "recursive": &ok,
        "force": &ok,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }
}

func (s *OssutilCommandSuite) TestSetACLIDKey(c *C) {
    bucket := bucketNameExist

    cfile := "ossutil_test.config_boto"
    data := fmt.Sprintf("[Credentials]\nendpoint=%s\naccessKeyID=%s\naccessKeySecret=%s\n[Bucket-Endpoint]\n%s=%s[Bucket-Cname]\n%s=%s", "abc", "def", "ghi", bucket, "abc", bucket, "abc")
    s.createFile(cfile, data, c)

    command := "set-acl"
    str := ""
    args := []string{CloudURLToString(bucket, ""), "public-read"}
    routines := strconv.Itoa(Routines)
    ok := true
    options := OptionMapType{
        "endpoint": &str,
        "accessKeyID": &str,
        "accessKeySecret": &str,
        "stsToken": &str,
        "configFile": &cfile,
        "routines": &routines,
        "bucket": &ok,
        "force": &ok,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    c.Assert(err, NotNil)

    options = OptionMapType{
        "endpoint": &endpoint,
        "accessKeyID": &accessKeyID,
        "accessKeySecret": &accessKeySecret,
        "stsToken": &str,
        "configFile": &cfile,
        "routines": &routines,
        "bucket": &ok,
        "force": &ok,
    }
    showElapse, err = cm.RunCommand(command, args, options)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    _ = os.Remove(cfile)
}
<commit_msg>modify case<commit_after>package lib

import (
    "fmt"
    "os"
    "strconv"
    "time"

    . "gopkg.in/check.v1"
)

func (s *OssutilCommandSuite) rawSetBucketACL(bucket, acl string, force bool) (bool, error) {
    args := []string{CloudURLToString(bucket, ""), acl}
    showElapse, err := s.rawSetACLWithArgs(args, false, true, force)
    return showElapse, err
}

func (s *OssutilCommandSuite) rawSetObjectACL(bucket, object, acl string, recursive, force bool) (bool, error) {
    args := []string{CloudURLToString(bucket, object), acl}
    showElapse, err := s.rawSetACLWithArgs(args, recursive, false, force)
    return showElapse, err
}

func (s *OssutilCommandSuite) rawSetACLWithArgs(args []string, recursive, bucket, force bool) (bool, error) {
    command := "set-acl"
    str := ""
    routines := strconv.Itoa(Routines)
    options := OptionMapType{
        "endpoint": &str,
        "accessKeyID": &str,
        "accessKeySecret": &str,
        "stsToken": &str,
        "configFile": &configFile,
        "routines": &routines,
        "recursive": &recursive,
        "bucket": &bucket,
        "force": &force,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    time.Sleep(sleepTime)
    return showElapse, err
}

func (s *OssutilCommandSuite) TestSetBucketACL(c *C) {
    bucket := bucketNameExist

    // set acl
    for _, acl := range []string{"private", "public-read", "public-read-write"} {
        s.setBucketACL(bucket, acl, c)
        bucketStat := s.getStat(bucket, "", c)
        c.Assert(bucketStat[StatACL], Equals, acl)
    }
}

func (s *OssutilCommandSuite) TestSetBucketErrorACL(c *C) {
    bucket := bucketNameDest

    for _, acl := range []string{"default", "def", "erracl", "私有"} {
        showElapse, err := s.rawSetBucketACL(bucket, acl, false)
        c.Assert(err, NotNil)
        c.Assert(showElapse, Equals, false)

        showElapse, err = s.rawSetBucketACL(bucket, acl, true)
        c.Assert(err, NotNil)
        c.Assert(showElapse, Equals, false)

        bucketStat := s.getStat(bucket, "", c)
        c.Assert(bucketStat[StatACL], Equals, "private")
    }
}

func (s *OssutilCommandSuite) TestSetNotExistBucketACL(c *C) {
    bucket := bucketNamePrefix + "noexistsetacl"

    showElapse, err := s.rawGetStat(bucket, "")
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // set acl and create bucket
    showElapse, err = s.rawSetBucketACL(bucket, "public-read", true)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    time.Sleep(sleepTime)
    bucketStat := s.getStat(bucket, "", c)
    c.Assert(bucketStat[StatACL], Equals, "public-read")

    s.removeBucket(bucket, true, c)
    time.Sleep(3*sleepTime)

    // invalid bucket name
    bucket = "a"
    showElapse, err = s.rawSetBucketACL(bucket, "public-read", true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    showElapse, err = s.rawGetStat(bucket, "")
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestSetBucketEmptyACL(c *C) {
    bucket := bucketNamePrefix + "acl3"
    s.putBucket(bucket, c)
    time.Sleep(sleepTime)

    object := "test"
    s.putObject(bucket, object, uploadFileName, c)

    showElapse, err := s.rawSetObjectACL(bucket, object, "", false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    s.removeBucket(bucket, true, c)
    time.Sleep(sleepTime)
}

func (s *OssutilCommandSuite) TestSetObjectACL(c *C) {
    bucket := bucketNameSetACL

    object := "TestSetObjectACL"

    // set acl to not exist object
    showElapse, err := s.rawSetObjectACL(bucket, object, "default", false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    object = "setacl-oldobject"
    s.putObject(bucket, object, uploadFileName, c)

    //get object acl
    objectStat := s.getStat(bucket, object, c)
    c.Assert(objectStat[StatACL], Equals, "default")

    object = "setacl-newobject"
    s.putObject(bucket, object, uploadFileName, c)

    // set acl
    for _, acl := range []string{"default", "private", "public-read", "public-read-write"} {
        s.setObjectACL(bucket, object, acl, false, true, c)
        objectStat = s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, acl)
    }

    s.setObjectACL(bucket, object, "private", false, true, c)

    // set error acl
    for _, acl := range []string{"public_read", "erracl", "私有"} {
        showElapse, err = s.rawSetObjectACL(bucket, object, acl, false, false)
        c.Assert(showElapse, Equals, false)
        c.Assert(err, NotNil)

        objectStat = s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "private")
    }
}

func (s *OssutilCommandSuite) TestBatchSetObjectACL(c *C) {
    bucket := bucketNameSetACL1

    // put objects
    num := 2
    objectNames := []string{}
    for i := 0; i < num; i++ {
        object := fmt.Sprintf("TestBatchSetObjectACL_setacl%d", i)
        s.putObject(bucket, object, uploadFileName, c)
        objectNames = append(objectNames, object)
    }
    time.Sleep(time.Second)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }

    // without --force option
    s.setObjectACL(bucket, "", "public-read-write", true, false, c)
    time.Sleep(2*sleepTime)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }

    for _, acl := range []string{"public-read", "private", "public-read-write", "default"} {
        s.setObjectACL(bucket, "TestBatchSetObjectACL_setacl", acl, true, true, c)
        time.Sleep(2*sleepTime)

        for _, object := range objectNames {
            objectStat := s.getStat(bucket, object, c)
            c.Assert(objectStat[StatACL], Equals, acl)
        }
    }

    showElapse, err := s.rawSetObjectACL(bucket, "TestBatchSetObjectACL_setacl", "erracl", true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestErrSetACL(c *C) {
    acl := "private"
    args := []string{"os://", acl}
    showElapse, err := s.rawSetACLWithArgs(args, false, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{"oss://", acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, false, true)

    // error set bucket acl
    bucket := bucketNamePrefix + "set-acl"
    object := "testobject"
    args = []string{CloudURLToString(bucket, object), acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, ""), acl}
    showElapse, err = s.rawSetACLWithArgs(args, true, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // miss acl
    args = []string{CloudURLToString(bucket, "")}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, object)}
    showElapse, err = s.rawSetACLWithArgs(args, false, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    args = []string{CloudURLToString(bucket, object)}
    showElapse, err = s.rawSetACLWithArgs(args, true, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // miss object
    args = []string{CloudURLToString(bucket, ""), acl}
    showElapse, err = s.rawSetACLWithArgs(args, false, false, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    // bad prefix
    showElapse, err = s.rawSetObjectACL(bucket, "/object", acl, true, true)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)
}

func (s *OssutilCommandSuite) TestErrBatchSetACL(c *C) {
    bucket := bucketNameExist

    // put objects
    num := 10
    objectNames := []string{}
    for i := 0; i < num; i++ {
        object := fmt.Sprintf("TestErrBatchSetACL_setacl:%d", i)
        s.putObject(bucket, object, uploadFileName, c)
        objectNames = append(objectNames, object)
    }

    command := "set-acl"
    str := ""
    str1 := "abc"
    args := []string{CloudURLToString(bucket, ""), "public-read-write"}
    routines := strconv.Itoa(Routines)
    ok := true
    options := OptionMapType{
        "endpoint": &str1,
        "accessKeyID": &str1,
        "accessKeySecret": &str1,
        "stsToken": &str,
        "routines": &routines,
        "recursive": &ok,
        "force": &ok,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    c.Assert(err, NotNil)
    c.Assert(showElapse, Equals, false)

    for _, object := range objectNames {
        objectStat := s.getStat(bucket, object, c)
        c.Assert(objectStat[StatACL], Equals, "default")
    }
}

func (s *OssutilCommandSuite) TestSetACLIDKey(c *C) {
    bucket := bucketNameExist

    cfile := "ossutil_test.config_boto"
    data := fmt.Sprintf("[Credentials]\nendpoint=%s\naccessKeyID=%s\naccessKeySecret=%s\n[Bucket-Endpoint]\n%s=%s[Bucket-Cname]\n%s=%s", "abc", "def", "ghi", bucket, "abc", bucket, "abc")
    s.createFile(cfile, data, c)

    command := "set-acl"
    str := ""
    args := []string{CloudURLToString(bucket, ""), "public-read"}
    routines := strconv.Itoa(Routines)
    ok := true
    options := OptionMapType{
        "endpoint": &str,
        "accessKeyID": &str,
        "accessKeySecret": &str,
        "stsToken": &str,
        "configFile": &cfile,
        "routines": &routines,
        "bucket": &ok,
        "force": &ok,
    }
    showElapse, err := cm.RunCommand(command, args, options)
    c.Assert(err, NotNil)

    options = OptionMapType{
        "endpoint": &endpoint,
        "accessKeyID": &accessKeyID,
        "accessKeySecret": &accessKeySecret,
        "stsToken": &str,
        "configFile": &cfile,
        "routines": &routines,
        "bucket": &ok,
        "force": &ok,
    }
    showElapse, err = cm.RunCommand(command, args, options)
    c.Assert(err, IsNil)
    c.Assert(showElapse, Equals, true)

    _ = os.Remove(cfile)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"lib/flannel"
	"lib/marshal"
	"lib/policy_client"
	"lib/poller"
	"lib/rules"
	"net/http"
	"os"
	"time"
	"vxlan-policy-agent/config"
	"vxlan-policy-agent/planner"

	"code.cloudfoundry.org/garden/client"
	"code.cloudfoundry.org/garden/client/connection"

	"code.cloudfoundry.org/lager"
	"github.com/coreos/go-iptables/iptables"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
)

func main() {
	conf := &config.VxlanPolicyAgent{}

	configFilePath := flag.String("config-file", "", "path to config file")
	flag.Parse()

	logger := lager.NewLogger("vxlan-policy-agent")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	configBytes, err := ioutil.ReadFile(*configFilePath)
	if err != nil {
		logger.Fatal("error reading config", err)
	}

	err = json.Unmarshal(configBytes, conf)
	if err != nil {
		logger.Fatal("error unmarshalling config", err)
	}
	logger.Info("parsed-config", lager.Data{"config": conf})

	pollInterval := time.Duration(conf.PollInterval) * time.Second
	if pollInterval == 0 {
		pollInterval = time.Second
	}

	flannelInfoReader := &flannel.NetworkInfo{
		FlannelSubnetFilePath: conf.FlannelSubnetFile,
	}
	localSubnetCIDR, overlayNetwork, err := flannelInfoReader.DiscoverNetworkInfo()
	if err != nil {
		logger.Fatal("discovering network info", err)
	}

	policyClient := policy_client.New(
		logger.Session("policy-client"),
		http.DefaultClient,
		conf.PolicyServerURL,
		marshal.UnmarshalFunc(json.Unmarshal),
	)

	gardenClient := client.New(connection.New(conf.GardenProtocol, conf.GardenAddress))

	ipt, err := iptables.New()
	if err != nil {
		logger.Fatal("iptables-new", err)
	}

	dynamicPlanner := &planner.VxlanPolicyPlanner{
		GardenClient: gardenClient,
		PolicyClient: policyClient,
		Logger:       logger.Session("rules-updater"),
		VNI:          conf.VNI,
	}

	timestamper := &rules.Timestamper{}
	ruleEnforcer := rules.NewEnforcer(
		logger.Session("rules-enforcer"),
		timestamper,
		ipt,
	)

	defaultLocalChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--local-",
	}

	defaultRemoteChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--remote-",
	}

	defaultMasqueradeChain := rules.Chain{
		Table:       "nat",
		ParentChain: "POSTROUTING",
		Prefix:      "vpa--masq-",
	}

	dynamicChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--",
	}

	vxlanDefaultLocalPlanner := planner.VxlanDefaultLocalPlanner{
		Logger:      logger,
		LocalSubnet: localSubnetCIDR,
	}

	vxlanDefaultRemotePlanner := planner.VxlanDefaultRemotePlanner{
		Logger: logger,
		VNI:    conf.VNI,
	}

	vxlanDefaultMasqueradePlanner := planner.VxlanDefaultMasqueradePlanner{
		Logger:         logger,
		LocalSubnet:    localSubnetCIDR,
		OverlayNetwork: overlayNetwork,
	}

	defaultLocalRules, err := vxlanDefaultLocalPlanner.GetRules()
	if err != nil {
		logger.Fatal("default-local-rules.GetRules", err)
	}

	err = ruleEnforcer.EnforceOnChain(defaultLocalChain, defaultLocalRules)
	if err != nil {
		logger.Fatal("enforce-default-local", err)
	}

	defaultRemoteRules, err := vxlanDefaultRemotePlanner.GetRules()
	if err != nil {
		logger.Fatal("default-local-rules.GetRules", err)
	}
	err = ruleEnforcer.EnforceOnChain(defaultRemoteChain, defaultRemoteRules)
	if err != nil {
		logger.Fatal("enforce-default-remote", err)
	}

	defaultMasqueradeRules, err := vxlanDefaultMasqueradePlanner.GetRules()
	if err != nil {
		logger.Fatal("default-masquerade-rules.GetRules", err)
	}
	err = ruleEnforcer.EnforceOnChain(defaultMasqueradeChain, defaultMasqueradeRules)
	if err != nil {
		logger.Fatal("enforce-default-masquerade", err)
	}

	policyPoller := &poller.Poller{
		Logger:       logger,
		PollInterval: pollInterval,
		Planner:      dynamicPlanner,

		Chain:    dynamicChain,
		Enforcer: ruleEnforcer,
	}

	members := grouper.Members{
		{"policy_poller", policyPoller},
	}

	monitor := ifrit.Invoke(sigmon.New(grouper.NewOrdered(os.Interrupt, members)))
	logger.Info("starting")
	err = <-monitor.Wait()
	if err != nil {
		logger.Fatal("ifrit monitor", err)
	}
}
<commit_msg>vxlan agent exits 1 on errors in main<commit_after>package main

import (
	"encoding/json"
	"flag"
	"io/ioutil"
	"lib/flannel"
	"lib/marshal"
	"lib/policy_client"
	"lib/poller"
	"lib/rules"
	"net/http"
	"os"
	"time"
	"vxlan-policy-agent/config"
	"vxlan-policy-agent/planner"

	"code.cloudfoundry.org/garden/client"
	"code.cloudfoundry.org/garden/client/connection"

	"code.cloudfoundry.org/lager"
	"github.com/coreos/go-iptables/iptables"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/sigmon"
)

func die(logger lager.Logger, action string, err error) {
	logger.Error(action, err)
	os.Exit(1)
}

func main() {
	conf := &config.VxlanPolicyAgent{}

	configFilePath := flag.String("config-file", "", "path to config file")
	flag.Parse()

	logger := lager.NewLogger("vxlan-policy-agent")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.INFO))

	configBytes, err := ioutil.ReadFile(*configFilePath)
	if err != nil {
		die(logger, "error reading config", err)
	}

	err = json.Unmarshal(configBytes, conf)
	if err != nil {
		die(logger, "error unmarshalling config", err)
	}
	logger.Info("parsed-config", lager.Data{"config": conf})

	pollInterval := time.Duration(conf.PollInterval) * time.Second
	if pollInterval == 0 {
		pollInterval = time.Second
	}

	flannelInfoReader := &flannel.NetworkInfo{
		FlannelSubnetFilePath: conf.FlannelSubnetFile,
	}
	localSubnetCIDR, overlayNetwork, err := flannelInfoReader.DiscoverNetworkInfo()
	if err != nil {
		die(logger, "discovering network info", err)
	}

	policyClient := policy_client.New(
		logger.Session("policy-client"),
		http.DefaultClient,
		conf.PolicyServerURL,
		marshal.UnmarshalFunc(json.Unmarshal),
	)

	gardenClient := client.New(connection.New(conf.GardenProtocol, conf.GardenAddress))

	ipt, err := iptables.New()
	if err != nil {
		die(logger, "iptables-new", err)
	}

	dynamicPlanner := &planner.VxlanPolicyPlanner{
		GardenClient: gardenClient,
		PolicyClient: policyClient,
		Logger:       logger.Session("rules-updater"),
		VNI:          conf.VNI,
	}

	timestamper := &rules.Timestamper{}
	ruleEnforcer := rules.NewEnforcer(
		logger.Session("rules-enforcer"),
		timestamper,
		ipt,
	)

	defaultLocalChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--local-",
	}

	defaultRemoteChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--remote-",
	}

	defaultMasqueradeChain := rules.Chain{
		Table:       "nat",
		ParentChain: "POSTROUTING",
		Prefix:      "vpa--masq-",
	}

	dynamicChain := rules.Chain{
		Table:       "filter",
		ParentChain: "FORWARD",
		Prefix:      "vpa--",
	}

	vxlanDefaultLocalPlanner := planner.VxlanDefaultLocalPlanner{
		Logger:      logger,
		LocalSubnet: localSubnetCIDR,
	}

	vxlanDefaultRemotePlanner := planner.VxlanDefaultRemotePlanner{
		Logger: logger,
		VNI:    conf.VNI,
	}

	vxlanDefaultMasqueradePlanner := planner.VxlanDefaultMasqueradePlanner{
		Logger:         logger,
		LocalSubnet:    localSubnetCIDR,
		OverlayNetwork: overlayNetwork,
	}

	defaultLocalRules, err := vxlanDefaultLocalPlanner.GetRules()
	if err != nil {
		die(logger, "default-local-rules.GetRules", err)
	}

	err = ruleEnforcer.EnforceOnChain(defaultLocalChain, defaultLocalRules)
	if err != nil {
		die(logger, "enforce-default-local", err)
	}

	defaultRemoteRules, err := vxlanDefaultRemotePlanner.GetRules()
	if err != nil {
		die(logger, "default-local-rules.GetRules", err)
	}
	err = ruleEnforcer.EnforceOnChain(defaultRemoteChain, defaultRemoteRules)
	if err != nil {
		die(logger, "enforce-default-remote", err)
	}

	defaultMasqueradeRules, err := vxlanDefaultMasqueradePlanner.GetRules()
	if err != nil {
		die(logger, "default-masquerade-rules.GetRules", err)
	}
	err = ruleEnforcer.EnforceOnChain(defaultMasqueradeChain, defaultMasqueradeRules)
	if err != nil {
		die(logger, "enforce-default-masquerade", err)
	}

	policyPoller := &poller.Poller{
		Logger:       logger,
		PollInterval: pollInterval,
		Planner:      dynamicPlanner,

		Chain:    dynamicChain,
		Enforcer: ruleEnforcer,
	}

	members := grouper.Members{
		{"policy_poller", policyPoller},
	}

	monitor := ifrit.Invoke(sigmon.New(grouper.NewOrdered(os.Interrupt, members)))
	logger.Info("starting")
	err = <-monitor.Wait()
	if err != nil {
		die(logger, "ifrit monitor", err)
	}
}
<|endoftext|>


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

// Package remote implements an inprocess directory server that uses RPC to
// connect to a remote directory server.
package remote

import (
	gContext "golang.org/x/net/context"

	"upspin.io/auth/grpcauth"
	"upspin.io/bind"
	"upspin.io/errors"
	"upspin.io/upspin"
	"upspin.io/upspin/proto"
)

// requireAuthentication specifies whether the connection demands TLS.
const requireAuthentication = true

// dialContext contains the destination and authenticated user of the dial.
type dialContext struct {
	endpoint upspin.Endpoint
	userName upspin.UserName
}

// remote implements upspin.DirServer.
type remote struct {
	upspin.NoConfiguration
	*grpcauth.AuthClientService // For handling Authenticate, Ping and Close.
	ctx                         dialContext
	dirClient                   proto.DirClient
}

var _ upspin.DirServer = (*remote)(nil)

// Glob implements upspin.DirServer.Glob.
func (r *remote) Glob(pattern string) ([]*upspin.DirEntry, error) {
	const op = "dir/remote.Glob"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirGlobRequest{
		Pattern: pattern,
	}
	resp, err := r.dirClient.Glob(gCtx, req)
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	r.LastActivity()

	if len(resp.Error) != 0 {
		err = unmarshalError(resp.Error)
	}
	if err != nil && err != upspin.ErrFollowLink {
		return nil, errors.E(op, err)
	}
	var entries []*upspin.DirEntry
	if len(resp.Entries) == 0 {
		var pErr error
		entries, pErr = proto.UpspinDirEntries(resp.Entries)
		if pErr != nil {
			return nil, errors.E(op, errors.IO, pErr)
		}
	}
	return entries, err
}

// MakeDirectory implements upspin.DirServer.MakeDirectory.
func (r *remote) MakeDirectory(directoryName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.MakeDirectory"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirMakeDirectoryRequest{
		Name: string(directoryName),
	}
	resp, err := r.dirClient.MakeDirectory(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Put implements upspin.DirServer.Put.
// Directories are created with MakeDirectory. Roots are anyway. TODO?.
func (r *remote) Put(entry *upspin.DirEntry) (*upspin.DirEntry, error) {
	const op = "dir/remote.Put"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	b, err := entry.Marshal()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirPutRequest{
		Entry: b,
	}
	resp, err := r.dirClient.Put(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// WhichAccess implements upspin.DirServer.WhichAccess.
func (r *remote) WhichAccess(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.WhichAccess"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirWhichAccessRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.WhichAccess(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Delete implements upspin.DirServer.Delete.
func (r *remote) Delete(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.Delete"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirDeleteRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.Delete(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Lookup implements upspin.DirServer.Lookup.
func (r *remote) Lookup(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.Lookup"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirLookupRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.Lookup(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Endpoint implements upspin.StoreServer.Endpoint.
func (r *remote) Endpoint() upspin.Endpoint {
	return r.ctx.endpoint
}

// Configure implements upspin.Service.
func (r *remote) Configure(options ...string) error {
	req := &proto.ConfigureRequest{
		Options: options,
	}
	resp, err := r.dirClient.Configure(gContext.Background(), req)
	if err != nil {
		return errors.E("dir/remote.Configure", errors.IO, err)
	}
	return errors.UnmarshalError(resp.Error)
}

// Dial implements upspin.Service.
func (*remote) Dial(context upspin.Context, e upspin.Endpoint) (upspin.Service, error) {
	const op = "dir/remote.Dial"
	if e.Transport != upspin.Remote {
		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
	}

	authClient, err := grpcauth.NewGRPCClient(context, e.NetAddr, grpcauth.KeepAliveInterval, grpcauth.Secure)
	if err != nil {
		return nil, errors.E(op, errors.IO, e, err)
	}

	// The connection is closed when this service is released (see Bind.Release)
	dirClient := proto.NewDirClient(authClient.GRPCConn())
	authClient.SetService(dirClient)
	r := &remote{
		AuthClientService: authClient,
		ctx: dialContext{
			endpoint: e,
			userName: context.UserName(),
		},
		dirClient: dirClient,
	}

	return r, nil
}

const transport = upspin.Remote

func init() {
	r := &remote{} // uninitialized until Dial time.
	bind.RegisterDirServer(transport, r)
}

// unmarshalError calls proto.UnmarshalError, but if the error
// matches upspin.ErrFollowLink, it returns that exact value so
// the caller can do == to test for links.
func unmarshalError(b []byte) error {
	err := errors.UnmarshalError(b)
	if err != nil && err.Error() == upspin.ErrFollowLink.Error() {
		return upspin.ErrFollowLink
	}
	return err
}

// entryError performs the common operation of converting an EntryError
// protocol buffer into a directory entry and error pair.
func entryError(op string, p *proto.EntryError, err error) (*upspin.DirEntry, error) {
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	if len(p.Error) != 0 {
		err = unmarshalError(p.Error)
	}
	if err != nil && err != upspin.ErrFollowLink {
		return nil, errors.E(op, err)
	}
	entry, unmarshalErr := proto.UpspinDirEntry(p.Entry)
	if unmarshalErr != nil {
		return nil, errors.E(op, unmarshalErr)
	}
	return entry, err
}
<commit_msg>dir/remote: fix unmarshaling of DirEntries in Glob<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package remote implements an inprocess directory server that uses RPC to
// connect to a remote directory server.
package remote

import (
	gContext "golang.org/x/net/context"

	"upspin.io/auth/grpcauth"
	"upspin.io/bind"
	"upspin.io/errors"
	"upspin.io/upspin"
	"upspin.io/upspin/proto"
)

// requireAuthentication specifies whether the connection demands TLS.
const requireAuthentication = true

// dialContext contains the destination and authenticated user of the dial.
type dialContext struct {
	endpoint upspin.Endpoint
	userName upspin.UserName
}

// remote implements upspin.DirServer.
type remote struct {
	upspin.NoConfiguration
	*grpcauth.AuthClientService // For handling Authenticate, Ping and Close.
	ctx                         dialContext
	dirClient                   proto.DirClient
}

var _ upspin.DirServer = (*remote)(nil)

// Glob implements upspin.DirServer.Glob.
func (r *remote) Glob(pattern string) ([]*upspin.DirEntry, error) {
	const op = "dir/remote.Glob"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirGlobRequest{
		Pattern: pattern,
	}
	resp, err := r.dirClient.Glob(gCtx, req)
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	r.LastActivity()

	if len(resp.Error) != 0 {
		err = unmarshalError(resp.Error)
	}
	if err != nil && err != upspin.ErrFollowLink {
		return nil, errors.E(op, err)
	}
	entries, pErr := proto.UpspinDirEntries(resp.Entries)
	if pErr != nil {
		return nil, errors.E(op, errors.IO, pErr)
	}
	return entries, err
}

// MakeDirectory implements upspin.DirServer.MakeDirectory.
func (r *remote) MakeDirectory(directoryName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.MakeDirectory"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirMakeDirectoryRequest{
		Name: string(directoryName),
	}
	resp, err := r.dirClient.MakeDirectory(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Put implements upspin.DirServer.Put.
// Directories are created with MakeDirectory. Roots are anyway. TODO?.
func (r *remote) Put(entry *upspin.DirEntry) (*upspin.DirEntry, error) {
	const op = "dir/remote.Put"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	b, err := entry.Marshal()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirPutRequest{
		Entry: b,
	}
	resp, err := r.dirClient.Put(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// WhichAccess implements upspin.DirServer.WhichAccess.
func (r *remote) WhichAccess(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.WhichAccess"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirWhichAccessRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.WhichAccess(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Delete implements upspin.DirServer.Delete.
func (r *remote) Delete(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.Delete"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirDeleteRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.Delete(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Lookup implements upspin.DirServer.Lookup.
func (r *remote) Lookup(pathName upspin.PathName) (*upspin.DirEntry, error) {
	const op = "dir/remote.Lookup"
	gCtx, err := r.NewAuthContext()
	if err != nil {
		return nil, errors.E(op, err)
	}
	req := &proto.DirLookupRequest{
		Name: string(pathName),
	}
	resp, err := r.dirClient.Lookup(gCtx, req)
	r.LastActivity()
	return entryError(op, resp, err)
}

// Endpoint implements upspin.StoreServer.Endpoint.
func (r *remote) Endpoint() upspin.Endpoint {
	return r.ctx.endpoint
}

// Configure implements upspin.Service.
func (r *remote) Configure(options ...string) error {
	req := &proto.ConfigureRequest{
		Options: options,
	}
	resp, err := r.dirClient.Configure(gContext.Background(), req)
	if err != nil {
		return errors.E("dir/remote.Configure", errors.IO, err)
	}
	return errors.UnmarshalError(resp.Error)
}

// Dial implements upspin.Service.
func (*remote) Dial(context upspin.Context, e upspin.Endpoint) (upspin.Service, error) {
	const op = "dir/remote.Dial"
	if e.Transport != upspin.Remote {
		return nil, errors.E(op, errors.Invalid, errors.Str("unrecognized transport"))
	}

	authClient, err := grpcauth.NewGRPCClient(context, e.NetAddr, grpcauth.KeepAliveInterval, grpcauth.Secure)
	if err != nil {
		return nil, errors.E(op, errors.IO, e, err)
	}

	// The connection is closed when this service is released (see Bind.Release)
	dirClient := proto.NewDirClient(authClient.GRPCConn())
	authClient.SetService(dirClient)
	r := &remote{
		AuthClientService: authClient,
		ctx: dialContext{
			endpoint: e,
			userName: context.UserName(),
		},
		dirClient: dirClient,
	}

	return r, nil
}

const transport = upspin.Remote

func init() {
	r := &remote{} // uninitialized until Dial time.
	bind.RegisterDirServer(transport, r)
}

// unmarshalError calls proto.UnmarshalError, but if the error
// matches upspin.ErrFollowLink, it returns that exact value so
// the caller can do == to test for links.
func unmarshalError(b []byte) error {
	err := errors.UnmarshalError(b)
	if err != nil && err.Error() == upspin.ErrFollowLink.Error() {
		return upspin.ErrFollowLink
	}
	return err
}

// entryError performs the common operation of converting an EntryError
// protocol buffer into a directory entry and error pair.
func entryError(op string, p *proto.EntryError, err error) (*upspin.DirEntry, error) {
	if err != nil {
		return nil, errors.E(op, errors.IO, err)
	}
	if len(p.Error) != 0 {
		err = unmarshalError(p.Error)
	}
	if err != nil && err != upspin.ErrFollowLink {
		return nil, errors.E(op, err)
	}
	entry, unmarshalErr := proto.UpspinDirEntry(p.Entry)
	if unmarshalErr != nil {
		return nil, errors.E(op, unmarshalErr)
	}
	return entry, err
}
<|endoftext|>


<commit_before>package diff

import (
	"errors"
	"testing"
)

func TestWalk(t *testing.T) {
	for _, test := range []struct {
		LHS  interface{}
		RHS  interface{}
		Want int
	}{
		{42, 42, 1},
		{[]int{42}, []int{42}, 2},
		{map[int]int{1: 2}, map[int]int{1: 2}, 2},
		{
			LHS: map[string][]int{
				"abc": {1, 2},
			},
			RHS: map[string][]int{
				"abc": {1, 4, 5},
			},
			Want: 5,
		},
	} {
		var nCalls int

		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		_, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			nCalls++
			return nil, nil
		})
		if err != nil {
			t.Errorf("Walk(Diff(%+v, %+v)): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		if nCalls != test.Want {
			t.Errorf(
				"Walk(Diff(%+v, %+v)): expected walk function to be called %d times, not %d",
				test.LHS, test.RHS, test.Want, nCalls,
			)
		}
	}
}

func TestWalkError(t *testing.T) {
	var expectedErr = errors.New("forbidden 42")
	for _, test := range []struct {
		LHS interface{}
		RHS interface{}
	}{
		{42, 43},
		{[]int{42}, []int{44}},
		{map[string]int{"ha": 42}, map[string]int{"ha": 45}},
	} {
		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		_, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			if _, ok := diff.(scalar); ok {
				return nil, expectedErr
			}

			return nil, nil
		})
		if err != expectedErr {
			t.Errorf("Walk(Diff(%+v, %+v)): expected error %q, got %q", test.LHS, test.RHS, expectedErr, err)
			continue
		}
	}
}
<commit_msg>Adding tests for IsMissing and IsExcess<commit_after>package diff

import (
	"errors"
	"testing"
)

func TestWalk(t *testing.T) {
	for _, test := range []struct {
		LHS  interface{}
		RHS  interface{}
		Want int
	}{
		{42, 42, 1},
		{[]int{42}, []int{42}, 2},
		{map[int]int{1: 2}, map[int]int{1: 2}, 2},
		{
			LHS: map[string][]int{
				"abc": {1, 2},
			},
			RHS: map[string][]int{
				"abc": {1, 4, 5},
			},
			Want: 5,
		},
	} {
		var nCalls int

		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		_, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			nCalls++
			return nil, nil
		})
		if err != nil {
			t.Errorf("Walk(Diff(%+v, %+v)): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		if nCalls != test.Want {
			t.Errorf(
				"Walk(Diff(%+v, %+v)): expected walk function to be called %d times, not %d",
				test.LHS, test.RHS, test.Want, nCalls,
			)
		}
	}
}

func TestWalkError(t *testing.T) {
	var expectedErr = errors.New("forbidden 42")
	for _, test := range []struct {
		LHS interface{}
		RHS interface{}
	}{
		{42, 43},
		{[]int{42}, []int{44}},
		{map[string]int{"ha": 42}, map[string]int{"ha": 45}},
	} {
		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}

		_, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			if _, ok := diff.(scalar); ok {
				return nil, expectedErr
			}

			return nil, nil
		})
		if err != expectedErr {
			t.Errorf("Walk(Diff(%+v, %+v)): expected error %q, got %q", test.LHS, test.RHS, expectedErr, err)
			continue
		}
	}
}

func TestIsExcess(t *testing.T) {
	for _, test := range []struct {
		LHS interface{}
		RHS interface{}
	}{
		{[]int{1, 2}, []int{1, 2, 3}},
		{map[int]int{1: 2, 3: 4}, map[int]int{1: 2, 3: 4, 5: 6}},
	} {
		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}
		if d.Diff() != ContentDiffer {
			t.Errorf("Diff(%+v, %+v).Diff() = %s, expected %s", test.LHS, test.RHS, d.Diff(), ContentDiffer)
		}

		d, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			if IsExcess(diff) {
				return Ignore()
			}
			return nil, nil
		})
		if err != nil {
			t.Errorf("Walk(...): unexpected error: %s", err)
			continue
		}
		if d.Diff() != Identical {
			t.Errorf("Walk(...)).Diff() = %s, expected %s", d.Diff(), Identical)
		}
	}
}

func TestIsMissing(t *testing.T) {
	for _, test := range []struct {
		LHS interface{}
		RHS interface{}
	}{
		{[]int{1, 2, 3}, []int{1, 2}},
		{map[int]int{1: 2, 3: 4, 5: 6}, map[int]int{1: 2, 3: 4}},
	} {
		d, err := Diff(test.LHS, test.RHS)
		if err != nil {
			t.Errorf("Diff(%+v, %+v): unexpected error: %s", test.LHS, test.RHS, err)
			continue
		}
		if d.Diff() != ContentDiffer {
			t.Errorf("Diff(%+v, %+v).Diff() = %s, expected %s", test.LHS, test.RHS, d.Diff(), ContentDiffer)
		}

		d, err = Walk(d, func(_, diff Differ, _ string) (Differ, error) {
			if IsMissing(diff) {
				return Ignore()
			}
			return nil, nil
		})
		if err != nil {
			t.Errorf("Walk(...): unexpected error: %s", err)
			continue
		}
		if d.Diff() != Identical {
			t.Errorf("Walk(...)).Diff() = %s, expected %s", d.Diff(), Identical)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2020-2022 Buf Technologies, 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 repositoryundeprecate

import (
	"context"
	"fmt"

	"github.com/bufbuild/buf/private/buf/bufcli"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref"
	"github.com/bufbuild/buf/private/pkg/app/appcmd"
	"github.com/bufbuild/buf/private/pkg/app/appflag"
	"github.com/bufbuild/buf/private/pkg/rpc"
	"github.com/spf13/cobra"
)

// NewCommand returns a new Command
func NewCommand(name string, builder appflag.Builder) *appcmd.Command {
	return &appcmd.Command{
		Use:   name + " <buf.build/owner/repository>",
		Short: "Undeprecate a repository.",
		Args:  cobra.ExactArgs(1),
		Run:   builder.NewRunFunc(run),
	}
}

func run(ctx context.Context, container appflag.Container) error {
	bufcli.WarnBetaCommand(ctx, container)
	moduleIdentity, err := bufmoduleref.ModuleIdentityForString(container.Arg(0))
	if err != nil {
		return appcmd.NewInvalidArgumentError(err.Error())
	}
	apiProvider, err := bufcli.NewRegistryProvider(ctx, container)
	if err != nil {
		return err
	}
	service, err := apiProvider.NewRepositoryService(ctx, moduleIdentity.Remote())
	if err != nil {
		return err
	}
	if _, err = service.UndeprecateRepositoryByName(
		ctx,
		moduleIdentity.Owner(),
		moduleIdentity.Repository(),
	); err != nil {
		if rpc.GetErrorCode(err) == rpc.ErrorCodeNotFound {
			return bufcli.NewRepositoryNotFoundError(container.Arg(0))
		}
		return err
	}
	if _, err := fmt.Fprintln(container.Stdout(), "Repository undeprecated."); err != nil {
		return bufcli.NewInternalError(err)
	}
	return nil
}
<commit_msg>add missing NewErrorInterceptor to buf beta registry repository undeprecate (#837)<commit_after>// Copyright 2020-2022 Buf Technologies, 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 repositoryundeprecate

import (
	"context"
	"fmt"

	"github.com/bufbuild/buf/private/buf/bufcli"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref"
	"github.com/bufbuild/buf/private/pkg/app/appcmd"
	"github.com/bufbuild/buf/private/pkg/app/appflag"
	"github.com/bufbuild/buf/private/pkg/rpc"
	"github.com/spf13/cobra"
)

// NewCommand returns a new Command
func NewCommand(name string, builder appflag.Builder) *appcmd.Command {
	return &appcmd.Command{
		Use:   name + " <buf.build/owner/repository>",
		Short: "Undeprecate a repository.",
		Args:  cobra.ExactArgs(1),
		Run:   builder.NewRunFunc(run, bufcli.NewErrorInterceptor()),
	}
}

func run(ctx context.Context, container appflag.Container) error {
	bufcli.WarnBetaCommand(ctx, container)
	moduleIdentity, err := bufmoduleref.ModuleIdentityForString(container.Arg(0))
	if err != nil {
		return appcmd.NewInvalidArgumentError(err.Error())
	}
	apiProvider, err := bufcli.NewRegistryProvider(ctx, container)
	if err != nil {
		return err
	}
	service, err := apiProvider.NewRepositoryService(ctx, moduleIdentity.Remote())
	if err != nil {
		return err
	}
	if _, err = service.UndeprecateRepositoryByName(
		ctx,
		moduleIdentity.Owner(),
		moduleIdentity.Repository(),
	); err != nil {
		if rpc.GetErrorCode(err) == rpc.ErrorCodeNotFound {
			return bufcli.NewRepositoryNotFoundError(container.Arg(0))
		}
		return err
	}
	if _, err := fmt.Fprintln(container.Stdout(), "Repository undeprecated."); err != nil {
		return bufcli.NewInternalError(err)
	}
	return nil
}
<|endoftext|>