<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package window

import (
	"time"

	"github.com/richardwilkes/toolbox/xmath/geom"
	"github.com/richardwilkes/ui"
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/cursor"
	"github.com/richardwilkes/ui/draw"
	"github.com/richardwilkes/ui/internal/x11"
)

// Window represents a window on the display.
type Window struct {
	commonWindow
	surface   *draw.Surface
	wasMapped bool
}

type platformWindow x11.Window

var (
	blankCursor *cursor.Cursor
)

func platformGetKeyWindow() platformWindow {
	return platformWindow(uintptr(x11.InputFocus()))
}

func platformBringAllWindowsToFront() {
	list := Windows()
	for i := len(list) - 1; i >= 0; i-- {
		list[i].ToFront()
	}
}

func platformHideCursorUntilMouseMoves() {
	if window := KeyWindow(); window != nil {
		if blankCursor == nil {
			blankCursor = cursor.NewCursor(&draw.ImageData{Width: 1, Height: 1, Pixels: make([]color.Color, 1)}, geom.Point{})
		}
		window.SetCursor(blankCursor)
	}
}

func platformNewWindow(bounds geom.Rect, styleMask StyleMask) *Window {
	wnd := x11.NewWindow(bounds)
	return &Window{
		commonWindow: commonWindow{window: platformWindow(uintptr(wnd))},
		surface: wnd.NewSurface(bounds.Size),
	}
}

func platformNewPopupWindow(parent ui.Window, bounds geom.Rect) *Window {
	wnd := x11.NewPopupWindow(x11.Window(uintptr(parent.PlatformPtr())), bounds)
	return &Window{
		commonWindow: commonWindow{window: platformWindow(uintptr(wnd))},
		surface: wnd.NewSurface(bounds.Size),
	}
}

func (window *Window) toXWindow() x11.Window {
	return x11.Window(uintptr(window.window))
}

func (window *Window) platformClose() {
	window.surface.Destroy()
	window.toXWindow().Destroy()
	window.Dispose()
}

func (window *Window) platformTitle() string {
	return window.toXWindow().Title()
}

func (window *Window) platformSetTitle(title string) {
	window.toXWindow().SetTitle(title)
}

func (window *Window) frameDecorationSpace() (top, left, bottom, right float64) {
	if window.Valid() {
		return window.toXWindow().FrameDecorationSpace()
	}
	return
}

func (window *Window) platformFrame() geom.Rect {
	bounds := window.platformContentFrame()
	top, left, bottom, right := window.frameDecorationSpace()
	bounds.X -= left
	bounds.Y -= top
	bounds.Width += left + right
	bounds.Height += top + bottom
	return bounds
}

func (window *Window) platformSetFrame(bounds geom.Rect) {
	window.toXWindow().SetFrame(bounds)
}

func (window *Window) platformContentFrame() geom.Rect {
	if window.Valid() {
		return window.toXWindow().ContentFrame()
	}
	return geom.Rect{}
}

func (window *Window) platformToFront() {
	wnd := window.toXWindow()
	if window.wasMapped {
		wnd.Raise()
	} else {
		wnd.Show()
		// Wait for window to be mapped
		for {
			if event := wnd.NextEventOfType(x11.MapNotifyType); event != nil {
				window.wasMapped = true
				wnd.Move(window.initialLocationRequest)
				if window.owner == nil {
					// Wait for window to be configured so that we have correct placement information
					for {
						if event = wnd.NextEventOfType(x11.ConfigureNotifyType); event != nil {
							processConfigureEvent(event.ToConfigureEvent())
							break
						}
						time.Sleep(time.Millisecond * 10)
					}
				}
				// This is here so that menu windows behave properly
				wnd.RequestFocus()
				break
			}
			time.Sleep(time.Millisecond * 10)
		}
	}
}

func (window *Window) platformRepaint(bounds geom.Rect) {
	window.toXWindow().Repaint(bounds)
}

func (window *Window) draw(bounds geom.Rect) {
	buffer := window.surface.CreateSimilar(draw.ColorContent, window.surface.Size())
	gc := draw.NewGraphics(buffer.NewCairoContext(bounds))
	gc.Rect(bounds)
	gc.Clip()
	window.paint(gc, bounds)
	gc.Dispose()

	gc = draw.NewGraphics(window.surface.NewCairoContext(bounds))
	gc.Rect(bounds)
	gc.Clip()
	gc.SetSurface(buffer, 0, 0)
	gc.FillClip()
	gc.Dispose()

	buffer.Destroy()
}

func (window *Window) platformFlushPainting() {
	x11.Flush()
}

func (window *Window) platformMinimize() {
	window.toXWindow().Minimize()
}

func (window *Window) platformZoom() {
	window.toXWindow().Zoom()
}

func (window *Window) platformSetCursor(c *cursor.Cursor) {
	window.toXWindow().SetCursor(x11.Cursor(uintptr(c.PlatformPtr())))
}

func (window *Window) platformInvoke(id uint64) {
	if window.Valid() {
		window.toXWindow().InvokeTask(id)
	}
}

func (window *Window) platformInvokeAfter(id uint64, after time.Duration) {
	time.AfterFunc(after, func() {
		window.platformInvoke(id)
	})
}
<commit_msg>Cleanup for linter<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package window

import (
	"time"

	"github.com/richardwilkes/toolbox/xmath/geom"
	"github.com/richardwilkes/ui"
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/cursor"
	"github.com/richardwilkes/ui/draw"
	"github.com/richardwilkes/ui/internal/x11"
)

// Window represents a window on the display.
type Window struct {
	commonWindow
	surface   *draw.Surface
	wasMapped bool
}

type platformWindow x11.Window

var (
	blankCursor *cursor.Cursor
)

func platformGetKeyWindow() platformWindow {
	return platformWindow(uintptr(x11.InputFocus()))
}

func platformBringAllWindowsToFront() {
	list := Windows()
	for i := len(list) - 1; i >= 0; i-- {
		list[i].ToFront()
	}
}

func platformHideCursorUntilMouseMoves() {
	if window := KeyWindow(); window != nil {
		if blankCursor == nil {
			blankCursor = cursor.NewCursor(&draw.ImageData{Width: 1, Height: 1, Pixels: make([]color.Color, 1)}, geom.Point{})
		}
		window.SetCursor(blankCursor)
	}
}

func platformNewWindow(bounds geom.Rect, styleMask StyleMask) *Window {
	wnd := x11.NewWindow(bounds)
	return &Window{
		commonWindow: commonWindow{window: platformWindow(uintptr(wnd))},
		surface:      wnd.NewSurface(bounds.Size),
	}
}

func platformNewPopupWindow(parent ui.Window, bounds geom.Rect) *Window {
	wnd := x11.NewPopupWindow(x11.Window(uintptr(parent.PlatformPtr())), bounds)
	return &Window{
		commonWindow: commonWindow{window: platformWindow(uintptr(wnd))},
		surface:      wnd.NewSurface(bounds.Size),
	}
}

func (window *Window) toXWindow() x11.Window {
	return x11.Window(uintptr(window.window))
}

func (window *Window) platformClose() {
	window.surface.Destroy()
	window.toXWindow().Destroy()
	window.Dispose()
}

func (window *Window) platformTitle() string {
	return window.toXWindow().Title()
}

func (window *Window) platformSetTitle(title string) {
	window.toXWindow().SetTitle(title)
}

func (window *Window) frameDecorationSpace() (top, left, bottom, right float64) {
	if window.Valid() {
		return window.toXWindow().FrameDecorationSpace()
	}
	return
}

func (window *Window) platformFrame() geom.Rect {
	bounds := window.platformContentFrame()
	top, left, bottom, right := window.frameDecorationSpace()
	bounds.X -= left
	bounds.Y -= top
	bounds.Width += left + right
	bounds.Height += top + bottom
	return bounds
}

func (window *Window) platformSetFrame(bounds geom.Rect) {
	window.toXWindow().SetFrame(bounds)
}

func (window *Window) platformContentFrame() geom.Rect {
	if window.Valid() {
		return window.toXWindow().ContentFrame()
	}
	return geom.Rect{}
}

func (window *Window) platformToFront() {
	wnd := window.toXWindow()
	if window.wasMapped {
		wnd.Raise()
	} else {
		wnd.Show()
		// Wait for window to be mapped
		for {
			if event := wnd.NextEventOfType(x11.MapNotifyType); event != nil {
				window.wasMapped = true
				wnd.Move(window.initialLocationRequest)
				if window.owner == nil {
					// Wait for window to be configured so that we have correct placement information
					for {
						if event = wnd.NextEventOfType(x11.ConfigureNotifyType); event != nil {
							processConfigureEvent(event.ToConfigureEvent())
							break
						}
						time.Sleep(time.Millisecond * 10)
					}
				}
				// This is here so that menu windows behave properly
				wnd.RequestFocus()
				break
			}
			time.Sleep(time.Millisecond * 10)
		}
	}
}

func (window *Window) platformRepaint(bounds geom.Rect) {
	window.toXWindow().Repaint(bounds)
}

func (window *Window) draw(bounds geom.Rect) {
	buffer := window.surface.CreateSimilar(draw.ColorContent, window.surface.Size())
	gc := draw.NewGraphics(buffer.NewCairoContext(bounds))
	gc.Rect(bounds)
	gc.Clip()
	window.paint(gc, bounds)
	gc.Dispose()

	gc = draw.NewGraphics(window.surface.NewCairoContext(bounds))
	gc.Rect(bounds)
	gc.Clip()
	gc.SetSurface(buffer, 0, 0)
	gc.FillClip()
	gc.Dispose()

	buffer.Destroy()
}

func (window *Window) platformFlushPainting() {
	x11.Flush()
}

func (window *Window) platformMinimize() {
	window.toXWindow().Minimize()
}

func (window *Window) platformZoom() {
	window.toXWindow().Zoom()
}

func (window *Window) platformSetCursor(c *cursor.Cursor) {
	window.toXWindow().SetCursor(x11.Cursor(uintptr(c.PlatformPtr())))
}

func (window *Window) platformInvoke(id uint64) {
	if window.Valid() {
		window.toXWindow().InvokeTask(id)
	}
}

func (window *Window) platformInvokeAfter(id uint64, after time.Duration) {
	time.AfterFunc(after, func() {
		window.platformInvoke(id)
	})
}
<|endoftext|>


<commit_before>package orm

import "gopkg.in/mgo.v2/bson"

func transformKey(schema *Schema, className, key string) string {
	// TODO
	return ""
}

// transformCreate ...
func transformCreate(schema *Schema, className string, create bson.M) bson.M {
	// TODO
	return nil
}

func transformWhere(schema *Schema, className string, where bson.M) bson.M {
	// TODO
	return nil
}

func transformUpdate(schema *Schema, className string, update bson.M) bson.M {
	// TODO
	return nil
}

func untransformObjectT(schema *Schema, className string, mongoObject interface{}, isNestedObject bool) interface{} {
	return nil
}
<commit_msg>完成 transformKeyValue<commit_after>package orm

import "gopkg.in/mgo.v2/bson"
import "github.com/lfq7413/tomato/utils"
import "regexp"
import "strings"

// transformKey 把 key 转换为数据库中保存的格式
func transformKey(schema *Schema, className, key string) string {
	k, _ := transformKeyValue(schema, className, key, nil, nil)
	return k
}

// transformKeyValue 把传入的键值对转换为数据库中保存的格式
func transformKeyValue(schema *Schema, className, restKey string, restValue interface{}, options bson.M) (string, interface{}) {
	if options == nil {
		options = bson.M{}
	}

	// 检测 key 是否为 内置字段
	key := restKey
	timeField := false
	switch key {
	case "objectId", "_id":
		key = "_id"
	case "createdAt", "_created_at":
		key = "_created_at"
		timeField = true
	case "updatedAt", "_updated_at":
		key = "_updated_at"
		timeField = true
	case "_email_verify_token":
		key = "_email_verify_token"
	case "_perishable_token":
		key = "_perishable_token"
	case "sessionToken", "_session_token":
		key = "_session_token"
	case "expiresAt", "_expiresAt":
		key = "_expiresAt"
		timeField = true
	case "_rperm", "_wperm":
		return key, restValue
	case "$or":
		if options["query"] == nil {
			// TODO 只有查询时才能使用 or
			return "", nil
		}
		querys := utils.SliceInterface(restValue)
		if querys == nil {
			// TODO 待转换值必须为数组类型
			return "", nil
		}
		mongoSubqueries := []interface{}{}
		for _, v := range querys {
			query := transformWhere(schema, className, utils.MapInterface(v))
			mongoSubqueries = append(mongoSubqueries, query)
		}
		return "$or", mongoSubqueries
	case "$and":
		if options["query"] == nil {
			// TODO 只有查询时才能使用 and
			return "", nil
		}
		querys := utils.SliceInterface(restValue)
		if querys == nil {
			// TODO 待转换值必须为数组类型
			return "", nil
		}
		mongoSubqueries := []interface{}{}
		for _, v := range querys {
			query := transformWhere(schema, className, utils.MapInterface(v))
			mongoSubqueries = append(mongoSubqueries, query)
		}
		return "$and", mongoSubqueries
	default:
		// 处理第三方 auth 数据
		authDataMatch, _ := regexp.MatchString(`^authData\.([a-zA-Z0-9_]+)\.id$`, key)
		if authDataMatch {
			if options["query"] != nil {
				provider := key[len("authData."):(len(key) - len(".id"))]
				return "_auth_data_" + provider + ".id", restKey
			}
			// TODO 只能将其应用查询操作
			return "", nil
		}
		// 默认处理
		if options["validate"] != nil {
			keyMatch, _ := regexp.MatchString(`^[a-zA-Z][a-zA-Z0-9_\.]*$`, key)
			if keyMatch == false {
				// TODO 无效的键名
				return "", nil
			}
		}
	}

	// 处理特殊键值
	expected := ""
	if schema != nil {
		expected = schema.getExpectedType(className, key)
	}
	// 处理指向其他对象的字段
	if expected != "" && strings.HasPrefix(expected, "*") {
		key = "_p_" + key
	}
	if expected == "" && restValue != nil {
		op := utils.MapInterface(restValue)
		if op != nil && op["__type"] != nil {
			if utils.String(op["__type"]) == "Pointer" {
				key = "_p_" + key
			}
		}
	}

	inArray := false
	if expected == "array" {
		inArray = true
	}
	// 处理查询操作
	if options["query"] != nil {
		value := transformConstraint(restValue, inArray)
		if value != cannotTransform() {
			return key, value
		}
	}
	if inArray && options["query"] != nil && utils.SliceInterface(restValue) == nil {
		return key, bson.M{"$all": []interface{}{restValue}}
	}

	// 处理原子数据
	value := transformAtom(restValue, false, options)
	if value != cannotTransform() {
		if timeField && utils.String(value) != "" {
			value, _ = utils.StringtoTime(utils.String(value))
		}
		return key, value
	}

	// ACL 在此之前处理，如果依然出现，则返回错误
	if key == "ACL" {
		// TODO 不能在此转换 ACL
		return "", nil
	}

	// 处理数组类型
	if valueArray, ok := restValue.([]interface{}); ok {
		if options["query"] != nil {
			// TODO 查询时不能为数组
			return "", nil
		}
		outValue := []interface{}{}
		for _, restObj := range valueArray {
			_, v := transformKeyValue(schema, className, restKey, restObj, bson.M{"inArray": true})
			outValue = append(outValue, v)
		}
		return key, outValue
	}

	// 处理更新操作
	var flatten bool
	if options["update"] == nil {
		flatten = true
	} else {
		flatten = false
	}
	value = transformUpdateOperator(restValue, flatten)
	if value != cannotTransform() {
		return key, value
	}

	// 处理正常的对象
	normalValue := bson.M{}
	for subRestKey, subRestValue := range utils.MapInterface(restValue) {
		k, v := transformKeyValue(schema, className, subRestKey, subRestValue, bson.M{"inObject": true})
		normalValue[k] = v
	}
	return key, normalValue
}

func transformConstraint(constraint interface{}, inArray bool) interface{} {
	// TODO
	return nil
}

func transformAtom(atom interface{}, force bool, options bson.M) interface{} {
	// TODO
	return nil
}

func transformUpdateOperator(operator interface{}, flatten bool) interface{} {
	// TODO
	return nil
}

// transformCreate ...
func transformCreate(schema *Schema, className string, create bson.M) bson.M {
	// TODO
	return nil
}

func transformWhere(schema *Schema, className string, where bson.M) bson.M {
	// TODO
	return nil
}

func transformUpdate(schema *Schema, className string, update bson.M) bson.M {
	// TODO
	return nil
}

func untransformObjectT(schema *Schema, className string, mongoObject interface{}, isNestedObject bool) interface{} {
	// TODO
	return nil
}

func cannotTransform() interface{} {
	return nil
}
<|endoftext|>


<commit_before>package atccmd

import (
	"fmt"
	"regexp"
	"sort"
	"strings"
)

type PostgresConfig struct {
	DataSource string `long:"data-source" description:"PostgreSQL connection string. (Deprecated; set the following flags instead.)"`

	Host string `long:"host" description:"The host to connect to." default:"127.0.0.1"`
	Port uint16 `long:"port" description:"The port to connect to." default:"5432"`

	Socket string `long:"socket" description:"Path to a UNIX domain socket to connect to."`

	User     string `long:"user"     description:"The user to sign in as."`
	Password string `long:"password" description:"The user's password."`

	SSLMode    string   `long:"sslmode"     description:"Whether or not to use SSL." default:"disable" choice:"disable" choice:"require" choice:"verify-ca" choice:"verify-full"`
	CACert     FileFlag `long:"ca-cert"     description:"CA cert file location, to verify when connecting with SSL."`
	ClientCert FileFlag `long:"client-cert" description:"Client cert file location."`
	ClientKey  FileFlag `long:"client-key"  description:"Client key file location."`

	Database string `long:"database" description:"The name of the database to use." default:"atc"`
}

func (config PostgresConfig) ConnectionString() string {
	if config.DataSource != "" {
		return config.DataSource
	}

	properties := map[string]interface{}{
		"dbname":  config.Database,
		"sslmode": config.SSLMode,
	}

	if config.User != "" {
		properties["user"] = config.User
	}

	if config.Password != "" {
		properties["password"] = config.Password
	}

	if config.Socket != "" {
		properties["host"] = config.Socket
	} else {
		properties["host"] = config.Host
		properties["port"] = config.Port
	}

	if config.CACert != "" {
		properties["sslrootcert"] = config.CACert.Path()
	}

	if config.ClientCert != "" {
		properties["sslcert"] = config.ClientCert.Path()
	}

	if config.ClientKey != "" {
		properties["sslkey"] = config.ClientKey.Path()
	}

	var pairs []string
	for k, v := range properties {
		var escV string
		switch x := v.(type) {
		case string:
			escV = fmt.Sprintf("'%s'", strEsc.ReplaceAllString(x, `\$1`))
		case uint16:
			escV = fmt.Sprintf("%d", x)
		default:
			panic(fmt.Sprintf("handle %T please", v))
		}

		pairs = append(
			pairs,
			fmt.Sprintf("%s=%s", k, escV),
		)
	}

	sort.Strings(pairs)

	return strings.Join(pairs, " ")
}

var strEsc = regexp.MustCompile(`([\\'])`)
<commit_msg>set dial timeout in postgres connections<commit_after>package atccmd

import (
	"fmt"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type PostgresConfig struct {
	DataSource string `long:"data-source" description:"PostgreSQL connection string. (Deprecated; set the following flags instead.)"`

	Host string `long:"host" description:"The host to connect to." default:"127.0.0.1"`
	Port uint16 `long:"port" description:"The port to connect to." default:"5432"`

	Socket string `long:"socket" description:"Path to a UNIX domain socket to connect to."`

	User     string `long:"user"     description:"The user to sign in as."`
	Password string `long:"password" description:"The user's password."`

	SSLMode    string   `long:"sslmode"     description:"Whether or not to use SSL." default:"disable" choice:"disable" choice:"require" choice:"verify-ca" choice:"verify-full"`
	CACert     FileFlag `long:"ca-cert"     description:"CA cert file location, to verify when connecting with SSL."`
	ClientCert FileFlag `long:"client-cert" description:"Client cert file location."`
	ClientKey  FileFlag `long:"client-key"  description:"Client key file location."`

	ConnectTimeout time.Duration `long:"connect-timeout" description:"Dialing timeout. (0 means wait indefinitely)" default:"5m"`

	Database string `long:"database" description:"The name of the database to use." default:"atc"`
}

func (config PostgresConfig) ConnectionString() string {
	if config.DataSource != "" {
		return config.DataSource
	}

	properties := map[string]interface{}{
		"dbname":  config.Database,
		"sslmode": config.SSLMode,
	}

	if config.User != "" {
		properties["user"] = config.User
	}

	if config.Password != "" {
		properties["password"] = config.Password
	}

	if config.Socket != "" {
		properties["host"] = config.Socket
	} else {
		properties["host"] = config.Host
		properties["port"] = config.Port
	}

	if config.CACert != "" {
		properties["sslrootcert"] = config.CACert.Path()
	}

	if config.ClientCert != "" {
		properties["sslcert"] = config.ClientCert.Path()
	}

	if config.ClientKey != "" {
		properties["sslkey"] = config.ClientKey.Path()
	}

	if config.ConnectTimeout != 0 {
		properties["connect_timeout"] = strconv.Itoa(int(config.ConnectTimeout.Seconds()))
	}

	var pairs []string
	for k, v := range properties {
		var escV string
		switch x := v.(type) {
		case string:
			escV = fmt.Sprintf("'%s'", strEsc.ReplaceAllString(x, `\$1`))
		case uint16:
			escV = fmt.Sprintf("%d", x)
		default:
			panic(fmt.Sprintf("handle %T please", v))
		}

		pairs = append(
			pairs,
			fmt.Sprintf("%s=%s", k, escV),
		)
	}

	sort.Strings(pairs)

	return strings.Join(pairs, " ")
}

var strEsc = regexp.MustCompile(`([\\'])`)
<|endoftext|>


<commit_before>package qotd

import (
	"fmt"

	"github.com/jesselucas/slackcmd/slack"
)

// Command struct is only defined to add the Request method
type Command struct {
}

// Request is used to send back to slackcmd
func (cmd *Command) Request(sc *slack.SlashCommand) (*slack.CommandPayload, error) {
	// create payload
	cp := &slack.CommandPayload{
		Channel:       fmt.Sprintf("@%v", sc.UserName),
		Username:      "QOTD",
		Emoji:         ":question:",
		SlashResponse: true,
		SendPayload:   false,
	}

	cp.Text = "What is your favorite star?"

	return cp, nil
}
<commit_msg>Adding SLACK_API_QOTD key<commit_after>package qotd

import (
	"errors"
	"fmt"
	"os"

	"github.com/jesselucas/slackcmd/slack"
)

// Command struct is only defined to add the Request method
type Command struct {
}

// Request is used to send back to slackcmd
func (cmd *Command) Request(sc *slack.SlashCommand) (*slack.CommandPayload, error) {
	// read credentials from environment variables
	slackAPIKey := os.Getenv("SLACK_KEY_QOTD")

	// Verify the request is coming from Slack
	if sc.Token != slackAPIKey {
		err := errors.New("Unauthorized Slack")
		return nil, err
	}

	// create payload
	cp := &slack.CommandPayload{
		Channel:       fmt.Sprintf("@%v", sc.UserName),
		Username:      "QOTD",
		Emoji:         ":question:",
		SlashResponse: true,
		SendPayload:   false,
	}

	cp.Text = "What is your favorite star?"

	return cp, nil
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func TestChooseString(t *testing.T) {
	cases := []struct {
		Input  []string
		Output string
	}{
		{
			[]string{"", "foo", ""},
			"foo",
		},
		{
			[]string{"", "foo", "bar"},
			"foo",
		},
		{
			[]string{"", "", ""},
			"",
		},
	}

	for _, tc := range cases {
		result := ChooseString(tc.Input...)
		if result != tc.Output {
			t.Fatalf("bad: %#v", tc.Input)
		}
	}
}

func TestDownloadableURL(t *testing.T) {
	// Invalid URL: has hex code in host
	_, err := DownloadableURL("http://what%20.com")
	if err == nil {
		t.Fatal("expected err")
	}

	// Invalid: unsupported scheme
	_, err = DownloadableURL("ftp://host.com/path")
	if err == nil {
		t.Fatal("expected err")
	}

	// Valid: http
	u, err := DownloadableURL("HTTP://packer.io/path")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if u != "http://packer.io/path" {
		t.Fatalf("bad: %s", u)
	}

	// No path
	u, err = DownloadableURL("HTTP://packer.io")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if u != "http://packer.io" {
		t.Fatalf("bad: %s", u)
	}
}

func TestDownloadableURL_WindowsFiles(t *testing.T) {
	if runtime.GOOS == "windows" {
		dirCases := []struct {
			InputString string
			OutputURL   string
			ErrExpected bool
		}{ // TODO: add different directories
			{
				"C:\\Temp\\SomeDir\\myfile.txt",
				"file:///C:/Temp/SomeDir/myfile.txt",
				false,
			},
			{ // need windows drive
				"\\Temp\\SomeDir\\myfile.txt",
				"",
				true,
			},
			{ // need windows drive
				"/Temp/SomeDir/myfile.txt",
				"",
				true,
			},
			{ // UNC paths; why not?
				"\\\\?\\c:\\Temp\\SomeDir\\myfile.txt",
				"",
				true,
			},
			{
				"file:///C:\\Temp\\SomeDir\\myfile.txt",
				"file:///c:/Temp/SomeDir/myfile.txt",
				false,
			},
			{
				"file:///c:/Temp/Somedir/myfile.txt",
				"file:///c:/Temp/SomeDir/myfile.txt",
				false,
			},
		}
		// create absolute-pathed tempfile to play with
		err := os.Mkdir("C:\\Temp\\SomeDir", 0755)
		if err != nil {
			t.Fatalf("err creating test dir: %s", err)
		}
		fi, err := os.Create("C:\\Temp\\SomeDir\\myfile.txt")
		if err != nil {
			t.Fatalf("err creating test file: %s", err)
		}
		fi.Close()
		defer os.Remove("C:\\Temp\\SomeDir\\myfile.txt")
		defer os.Remove("C:\\Temp\\SomeDir")

		// Run through test cases to make sure they all parse correctly
		for _, tc := range dirCases {
			u, err := DownloadableURL(tc.InputString)
			if (err != nil) != tc.ErrExpected {
				t.Fatalf("Test Case failed: Expected err = %#v, err = %#v, input = %s",
					tc.ErrExpected, err, tc.InputString)
			}
			if u != tc.OutputURL {
				t.Fatalf("Test Case failed: Expected %s but received %s from input %s",
					tc.OutputURL, u, tc.InputString)
			}
		}
	}
}

func TestDownloadableURL_FilePaths(t *testing.T) {
	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("tempfile err: %s", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	tfPath, err := filepath.EvalSymlinks(tf.Name())
	if err != nil {
		t.Fatalf("tempfile err: %s", err)
	}

	tfPath = filepath.Clean(tfPath)

	filePrefix := "file://"
	if runtime.GOOS == "windows" {
		filePrefix += "/"
	}

	// Relative filepath. We run this test in a func so that
	// the defers run right away.
	func() {
		wd, err := os.Getwd()
		if err != nil {
			t.Fatalf("getwd err: %s", err)
		}

		err = os.Chdir(filepath.Dir(tfPath))
		if err != nil {
			t.Fatalf("chdir err: %s", err)
		}
		defer os.Chdir(wd)

		filename := filepath.Base(tfPath)
		u, err := DownloadableURL(filename)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		expected := fmt.Sprintf("%s%s",
			filePrefix,
			strings.Replace(tfPath, `\`, `/`, -1))
		if u != expected {
			t.Fatalf("unexpected: %#v != %#v", u, expected)
		}
	}()

	// Test some cases with and without a schema prefix
	for _, prefix := range []string{"", filePrefix} {
		// Nonexistent file
		_, err = DownloadableURL(prefix + "i/dont/exist")
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		// Good file
		u, err := DownloadableURL(prefix + tfPath)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		expected := fmt.Sprintf("%s%s",
			filePrefix,
			strings.Replace(tfPath, `\`, `/`, -1))
		if u != expected {
			t.Fatalf("unexpected: %s != %s", u, expected)
		}
	}
}

func TestScrubConfig(t *testing.T) {
	type Inner struct {
		Baz string
	}
	type Local struct {
		Foo string
		Bar string
		Inner
	}
	c := Local{"foo", "bar", Inner{"bar"}}
	expect := "Config: {Foo:foo Bar:<Filtered> Inner:{Baz:<Filtered>}}"
	conf := ScrubConfig(c, c.Bar)
	if conf != expect {
		t.Fatalf("got %s, expected %s", conf, expect)
	}
}
<commit_msg>add tests for fileexistslocally helper function<commit_after>package common

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func TestChooseString(t *testing.T) {
	cases := []struct {
		Input  []string
		Output string
	}{
		{
			[]string{"", "foo", ""},
			"foo",
		},
		{
			[]string{"", "foo", "bar"},
			"foo",
		},
		{
			[]string{"", "", ""},
			"",
		},
	}

	for _, tc := range cases {
		result := ChooseString(tc.Input...)
		if result != tc.Output {
			t.Fatalf("bad: %#v", tc.Input)
		}
	}
}

func TestDownloadableURL(t *testing.T) {
	// Invalid URL: has hex code in host
	_, err := DownloadableURL("http://what%20.com")
	if err == nil {
		t.Fatal("expected err")
	}

	// Invalid: unsupported scheme
	_, err = DownloadableURL("ftp://host.com/path")
	if err == nil {
		t.Fatal("expected err")
	}

	// Valid: http
	u, err := DownloadableURL("HTTP://packer.io/path")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if u != "http://packer.io/path" {
		t.Fatalf("bad: %s", u)
	}

	// No path
	u, err = DownloadableURL("HTTP://packer.io")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if u != "http://packer.io" {
		t.Fatalf("bad: %s", u)
	}
}

func TestDownloadableURL_WindowsFiles(t *testing.T) {
	if runtime.GOOS == "windows" {
		dirCases := []struct {
			InputString string
			OutputURL   string
			ErrExpected bool
		}{ // TODO: add different directories
			{
				"C:\\Temp\\SomeDir\\myfile.txt",
				"file:///C:/Temp/SomeDir/myfile.txt",
				false,
			},
			{ // need windows drive
				"\\Temp\\SomeDir\\myfile.txt",
				"",
				true,
			},
			{ // need windows drive
				"/Temp/SomeDir/myfile.txt",
				"",
				true,
			},
			{ // UNC paths; why not?
				"\\\\?\\c:\\Temp\\SomeDir\\myfile.txt",
				"",
				true,
			},
			{
				"file:///C:\\Temp\\SomeDir\\myfile.txt",
				"file:///c:/Temp/SomeDir/myfile.txt",
				false,
			},
			{
				"file:///c:/Temp/Somedir/myfile.txt",
				"file:///c:/Temp/SomeDir/myfile.txt",
				false,
			},
		}
		// create absolute-pathed tempfile to play with
		err := os.Mkdir("C:\\Temp\\SomeDir", 0755)
		if err != nil {
			t.Fatalf("err creating test dir: %s", err)
		}
		fi, err := os.Create("C:\\Temp\\SomeDir\\myfile.txt")
		if err != nil {
			t.Fatalf("err creating test file: %s", err)
		}
		fi.Close()
		defer os.Remove("C:\\Temp\\SomeDir\\myfile.txt")
		defer os.Remove("C:\\Temp\\SomeDir")

		// Run through test cases to make sure they all parse correctly
		for _, tc := range dirCases {
			u, err := DownloadableURL(tc.InputString)
			if (err != nil) != tc.ErrExpected {
				t.Fatalf("Test Case failed: Expected err = %#v, err = %#v, input = %s",
					tc.ErrExpected, err, tc.InputString)
			}
			if u != tc.OutputURL {
				t.Fatalf("Test Case failed: Expected %s but received %s from input %s",
					tc.OutputURL, u, tc.InputString)
			}
		}
	}
}

func TestDownloadableURL_FilePaths(t *testing.T) {
	tf, err := ioutil.TempFile("", "packer")
	if err != nil {
		t.Fatalf("tempfile err: %s", err)
	}
	defer os.Remove(tf.Name())
	tf.Close()

	tfPath, err := filepath.EvalSymlinks(tf.Name())
	if err != nil {
		t.Fatalf("tempfile err: %s", err)
	}

	tfPath = filepath.Clean(tfPath)

	filePrefix := "file://"
	if runtime.GOOS == "windows" {
		filePrefix += "/"
	}

	// Relative filepath. We run this test in a func so that
	// the defers run right away.
	func() {
		wd, err := os.Getwd()
		if err != nil {
			t.Fatalf("getwd err: %s", err)
		}

		err = os.Chdir(filepath.Dir(tfPath))
		if err != nil {
			t.Fatalf("chdir err: %s", err)
		}
		defer os.Chdir(wd)

		filename := filepath.Base(tfPath)
		u, err := DownloadableURL(filename)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		expected := fmt.Sprintf("%s%s",
			filePrefix,
			strings.Replace(tfPath, `\`, `/`, -1))
		if u != expected {
			t.Fatalf("unexpected: %#v != %#v", u, expected)
		}
	}()

	// Test some cases with and without a schema prefix
	for _, prefix := range []string{"", filePrefix} {
		// Nonexistent file
		_, err = DownloadableURL(prefix + "i/dont/exist")
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		// Good file
		u, err := DownloadableURL(prefix + tfPath)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		expected := fmt.Sprintf("%s%s",
			filePrefix,
			strings.Replace(tfPath, `\`, `/`, -1))
		if u != expected {
			t.Fatalf("unexpected: %s != %s", u, expected)
		}
	}
}

func test_FileExistsLocally(t *testing.T) {
	if runtime.GOOS == "windows" {
		dirCases := []struct {
			Input  string
			Output bool
		}{
			// file exists locally
			{"file:///C:/Temp/SomeDir/myfile.txt", true},
			// file is not supposed to exist locally
			{"https://myfile.iso", true},
			// file does not exist locally
			{"file:///C/i/dont/exist", false},
		}
		// create absolute-pathed tempfile to play with
		err := os.Mkdir("C:\\Temp\\SomeDir", 0755)
		if err != nil {
			t.Fatalf("err creating test dir: %s", err)
		}
		fi, err := os.Create("C:\\Temp\\SomeDir\\myfile.txt")
		if err != nil {
			t.Fatalf("err creating test file: %s", err)
		}
		fi.Close()
		defer os.Remove("C:\\Temp\\SomeDir\\myfile.txt")
		defer os.Remove("C:\\Temp\\SomeDir")

		// Run through test cases to make sure they all parse correctly
		for _, tc := range dirCases {
			fileOK := FileExistsLocally(tc.Input)
			if !fileOK {
				t.Fatalf("Test Case failed: Expected %#v, received = %#v, input = %s",
					tc.Output, fileOK, tc.Input)
			}
		}
	}
}

func TestScrubConfig(t *testing.T) {
	type Inner struct {
		Baz string
	}
	type Local struct {
		Foo string
		Bar string
		Inner
	}
	c := Local{"foo", "bar", Inner{"bar"}}
	expect := "Config: {Foo:foo Bar:<Filtered> Inner:{Baz:<Filtered>}}"
	conf := ScrubConfig(c, c.Bar)
	if conf != expect {
		t.Fatalf("got %s, expected %s", conf, expect)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"crypto/sha256"
	"crypto/hmac"
	"fmt"
	"net/http/httptest"
	"net/http"
	"strings"
	"testing"
)

func init() {
	key := "secret"
	secretKey = &key
}

func TestValidateSig(t *testing.T) {
	url := "http://mozilla.org/en-US/"
	s1 := sha1.New()
	s1.Write([]byte("secret"+ url))
	sig1 := fmt.Sprintf("%x", s1.Sum(nil))

	if !validateSig(url, sig1) {
		t.Errorf("url hash: %s did not match.", sig1)
	}

	s1 = sha1.New()
	s1.Write([]byte("badsecret"+ url))
	sig1 = fmt.Sprintf("%x", s1.Sum(nil))

	if validateSig(url, sig1) {
		t.Errorf("bad url hash: %s matched.", sig1)
	}

	h := hmac.New(sha256.New, []byte("secret"))
	h.Write([]byte(url))
	hSig := fmt.Sprintf("%x", h.Sum(nil))

	if !validateSig(url, hSig) {
		t.Errorf("url hash: %s did not match.", hSig)
	}

	h = hmac.New(sha256.New, []byte("badsecret"))
	h.Write([]byte(url))
	hSig = fmt.Sprintf("%x", h.Sum(nil))

	if validateSig(url, hSig) {
		t.Errorf("bad url hash: %s did not match.", hSig)
	}
}

func TestReq(t *testing.T) {
	h := hmac.New(sha256.New, []byte("secret"))
	h.Write([]byte("http://www.mywot.com/"))
	hSig := fmt.Sprintf("%x", h.Sum(nil))

	rec := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/v1/" + hSig + "/http%3A//www.mywot.com/", nil)
	if err != nil {
		t.Fatal(err)
	}
	readReq(rec, req)
	if rec.Code != 200 {
		t.Errorf("Expected %d, returned %d.", 200, rec.Code)
	}
	if !strings.Contains(rec.Body.String(), "http://www.mywot.com/") {
		t.Errorf("http://www.mywot.com/ is not in %s.", rec.Body.String())
	}

	h = hmac.New(sha256.New, []byte("badsecret"))
	h.Write([]byte("http://www.mywot.com/"))
	hSig = fmt.Sprintf("%x", h.Sum(nil))

	rec = httptest.NewRecorder()
	req, err = http.NewRequest("GET", "/v1/" + hSig + "/http%3A//www.mywot.com/", nil)
	if err != nil {
		t.Fatal(err)
	}
	readReq(rec, req)
	if rec.Code != 400 {
		t.Errorf("Expected %d, returned %d.", 200, rec.Code)
	}
}
<commit_msg>Add javascript: test.<commit_after>package main

import (
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func init() {
	key := "secret"
	secretKey = &key
}

func TestValidateSig(t *testing.T) {
	url := "http://mozilla.org/en-US/"
	s1 := sha1.New()
	s1.Write([]byte("secret" + url))
	sig1 := fmt.Sprintf("%x", s1.Sum(nil))

	if !validateSig(url, sig1) {
		t.Errorf("url hash: %s did not match.", sig1)
	}

	s1 = sha1.New()
	s1.Write([]byte("badsecret" + url))
	sig1 = fmt.Sprintf("%x", s1.Sum(nil))

	if validateSig(url, sig1) {
		t.Errorf("bad url hash: %s matched.", sig1)
	}

	hSig := getHmac(url, "secret")

	if !validateSig(url, hSig) {
		t.Errorf("url hash: %s did not match.", hSig)
	}

	hSig = getHmac(url, "badsecret")

	if validateSig(url, hSig) {
		t.Errorf("bad url hash: %s matched.", hSig)
	}
}

func getHmac(url, key string) string {
	h := hmac.New(sha256.New, []byte(key))
	h.Write([]byte(url))
	return fmt.Sprintf("%x", h.Sum(nil))
}

func TestReq(t *testing.T) {
	hSig := getHmac("http://www.mywot.com/", "secret")

	rec := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "/v1/"+hSig+"/http%3A//www.mywot.com/", nil)
	if err != nil {
		t.Fatal(err)
	}
	readReq(rec, req)
	if rec.Code != 200 {
		t.Errorf("Expected %d, returned %d.", 200, rec.Code)
	}
	if !strings.Contains(rec.Body.String(), "http://www.mywot.com/") {
		t.Errorf("http://www.mywot.com/ is not in %s.", rec.Body.String())
	}

	hSig = getHmac("http://www.mywot.com/", "badsecret")

	rec = httptest.NewRecorder()
	req, err = http.NewRequest("GET", "/v1/"+hSig+"/http%3A//www.mywot.com/", nil)
	if err != nil {
		t.Fatal(err)
	}
	readReq(rec, req)
	if rec.Code != 400 {
		t.Errorf("Expected %d, returned %d.", 400, rec.Code)
	}

	hSig = getHmac("javascript:alert()", "badsecret")

	rec = httptest.NewRecorder()
	req, err = http.NewRequest("GET", "/v1/"+hSig+"/javascript:alert()", nil)
	if err != nil {
		t.Fatal(err)
	}
	readReq(rec, req)
	if rec.Code != 400 {
		t.Errorf("Expected %d, returned %d.", 400, rec.Code)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 proc

import (
	"errors"

	"github.com/zenoss/glog"

	"bufio"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strings"
)

var ErrMountPointNotFound = errors.New("mount point not found")

var procNFSFSServersFile = "servers"
var procNFSFSVolumesFile = "volumes"
var procFindmntCommand = "/bin/findmnt --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS %s | awk '{n=split($NF,fields,\"=\"); print $1, $2, $3, $4, fields[n]}'"

// NFSVolumeInfo is merged from mountinfo and volumes
type NFSMountInfo struct {
	// from findmnt
	MountInfo

	// from /proc/fs/nfsfs/volumes
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// MountInfo is retrieved from mountinfo
type MountInfo struct {
	DeviceID   string // device id: 0:137
	FSType     string // filesystem type: btrfs, nfs4, ext4
	RemotePath string // path to the server: 10.87.209.168:/serviced_var
	LocalPath  string // path on the client: /tmp/serviced/var
	ServerIP   string // server ip address: 10.87.209.168
}

// ProcNFSFSServer is a parsed representation of /proc/fs/nfsfs/servers information.
type ProcNFSFSServer struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	Hostname string // hostname of server: 10.87.209.168
}

// ProcNFSFSVolume is a parsed representation of /proc/fs/nfsfs/volumes information.
type ProcNFSFSVolume struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	DeviceID string // device id: 0:137
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// GetProcNFSFSServers gets a map to the /proc/fs/nfsfs/servers
func GetProcNFSFSServers() (map[string]ProcNFSFSServer, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSServersFile))
	if err != nil {
		return nil, err
	}

	servers := make(map[string]ProcNFSFSServer)
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 5:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSServer{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			Hostname: fields[4],
		}
		key := fmt.Sprintf("%s:%s:%s", svr.Version, svr.ServerID, svr.Port)
		servers[key] = svr
	}
	glog.V(4).Infof("nfsfs servers: %+v", servers)
	return servers, nil
}

// GetProcNFSFSVolumes gets a map to the /proc/fs/nfsfs/volumes
func GetProcNFSFSVolumes() ([]ProcNFSFSVolume, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSVolumesFile))
	if err != nil {
		return nil, err
	}

	var volumes []ProcNFSFSVolume
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 6:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 6 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSVolume{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			DeviceID: fields[3],
			FSID:     fields[4],
			FSCache:  fields[5],
		}
		volumes = append(volumes, svr)
	}
	glog.V(4).Infof("nfsfs volumes: %+v", volumes)
	return volumes, nil
}

// GetProcNFSFSVolume gets the ProcNFSFSVolume of a deviceid from /proc/fs/nfsfs/volumes
func GetProcNFSFSVolume(deviceid string) (*ProcNFSFSVolume, error) {
	volumes, err := GetProcNFSFSVolumes()
	if err != nil {
		return nil, err
	}

	for idx := range volumes {
		glog.V(4).Infof("volume: %+v", volumes[idx])
		if deviceid == volumes[idx].DeviceID {
			return &volumes[idx], nil
		}
	}

	return nil, fmt.Errorf("unable to find volume for deviceid %s", deviceid)
}

// GetMountInfo gets the mount info of the mountpoint
func GetMountInfo(mountpoint string) (*MountInfo, error) {
	command := []string{"bash", "-c", fmt.Sprintf(procFindmntCommand, mountpoint)}

	thecmd := exec.Command(command[0], command[1:]...)
	glog.V(1).Infof("command: %+v", command)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	// [root@jrivera-tb1 ~]# /bin/findmnt --noheading -o MAJ:MIN,SOURCE,TARGET,OPTIONS /tmp/serviced/var
	//   0:137 10.87.209.168:/serviced_var /tmp/serviced/var rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=10.87.209.168,local_lock=none,addr=10.87.209.168
	line := strings.TrimSpace(string(output))

	glog.V(4).Infof("line: %s", line)

	fields := strings.Fields(line)
	switch len(fields) {
	case 5:
		break
	case 0:
		return nil, ErrMountPointNotFound
	default:
		glog.Infof("command: %+v", command)
		return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
	}
	info := MountInfo{
		DeviceID:   fields[0],
		FSType:     fields[1],
		RemotePath: fields[2],
		LocalPath:  fields[3],
		ServerIP:   fields[4],
	}
	glog.V(4).Infof("mount info: %+v", info)
	return &info, nil
}

// GetNFSVolumeInfo gets the NFSMountInfo of the mountpoint
func GetNFSVolumeInfo(mountpoint string) (*NFSMountInfo, error) {
	minfo, err := GetMountInfo(mountpoint)
	if err != nil {
		return nil, err
	}

	volume, err := GetProcNFSFSVolume(minfo.DeviceID)
	if err != nil {
		return nil, err
	}

	info := NFSMountInfo{
		MountInfo: *minfo,

		Version:  volume.Version,
		ServerID: volume.ServerID,
		Port:     volume.Port,
		FSID:     volume.FSID,
		FSCache:  volume.FSCache,
	}

	return &info, nil
}
<commit_msg>use findmnt --raw to make sure output is not truncated<commit_after>// Copyright 2014 The Serviced 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 proc

import (
	"errors"

	"github.com/zenoss/glog"

	"bufio"
	"fmt"
	"io/ioutil"
	"os/exec"
	"strings"
)

var ErrMountPointNotFound = errors.New("mount point not found")

var procNFSFSServersFile = "servers"
var procNFSFSVolumesFile = "volumes"
var procFindmntCommand = "/bin/findmnt --raw --noheading -o MAJ:MIN,FSTYPE,SOURCE,TARGET,OPTIONS %s | awk '{n=split($NF,fields,\"=\"); print $1, $2, $3, $4, fields[n]}'"

// NFSVolumeInfo is merged from mountinfo and volumes
type NFSMountInfo struct {
	// from findmnt
	MountInfo

	// from /proc/fs/nfsfs/volumes
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// MountInfo is retrieved from mountinfo
type MountInfo struct {
	DeviceID   string // device id: 0:137
	FSType     string // filesystem type: btrfs, nfs4, ext4
	RemotePath string // path to the server: 10.87.209.168:/serviced_var
	LocalPath  string // path on the client: /tmp/serviced/var
	ServerIP   string // server ip address: 10.87.209.168
}

// ProcNFSFSServer is a parsed representation of /proc/fs/nfsfs/servers information.
type ProcNFSFSServer struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	Hostname string // hostname of server: 10.87.209.168
}

// ProcNFSFSVolume is a parsed representation of /proc/fs/nfsfs/volumes information.
type ProcNFSFSVolume struct {
	Version  string // nfsversion: v4, v3, ...
	ServerID string // id of server: 0a57d1a8
	Port     string // port on server: 801
	DeviceID string // device id: 0:137
	FSID     string // filesystem id: 45a148e989326106
	FSCache  string // whether fscache is used (yes/no)
}

// GetProcNFSFSServers gets a map to the /proc/fs/nfsfs/servers
func GetProcNFSFSServers() (map[string]ProcNFSFSServer, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSServersFile))
	if err != nil {
		return nil, err
	}

	servers := make(map[string]ProcNFSFSServer)
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 5:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSServer{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			Hostname: fields[4],
		}
		key := fmt.Sprintf("%s:%s:%s", svr.Version, svr.ServerID, svr.Port)
		servers[key] = svr
	}
	glog.V(4).Infof("nfsfs servers: %+v", servers)
	return servers, nil
}

// GetProcNFSFSVolumes gets a map to the /proc/fs/nfsfs/volumes
func GetProcNFSFSVolumes() ([]ProcNFSFSVolume, error) {
	// read in the file
	data, err := ioutil.ReadFile(fmt.Sprintf(procDir+"fs/nfsfs/%s", procNFSFSVolumesFile))
	if err != nil {
		return nil, err
	}

	var volumes []ProcNFSFSVolume
	scanner := bufio.NewScanner(strings.NewReader(string(data)))
	linenum := 0
	for scanner.Scan() {
		line := scanner.Text()

		linenum++
		glog.V(4).Infof("%d: %s", linenum, line)
		if linenum < 2 {
			continue
		} else if strings.HasPrefix(line, "#") {
			continue
		}

		fields := strings.Fields(line)
		switch len(fields) {
		case 6:
			break
		case 0:
			continue
		default:
			return nil, fmt.Errorf("expected 6 fields, got %d: %s", len(fields), line)
		}
		svr := ProcNFSFSVolume{
			Version:  fields[0],
			ServerID: fields[1],
			Port:     fields[2],
			DeviceID: fields[3],
			FSID:     fields[4],
			FSCache:  fields[5],
		}
		volumes = append(volumes, svr)
	}
	glog.V(4).Infof("nfsfs volumes: %+v", volumes)
	return volumes, nil
}

// GetProcNFSFSVolume gets the ProcNFSFSVolume of a deviceid from /proc/fs/nfsfs/volumes
func GetProcNFSFSVolume(deviceid string) (*ProcNFSFSVolume, error) {
	volumes, err := GetProcNFSFSVolumes()
	if err != nil {
		return nil, err
	}

	for idx := range volumes {
		glog.V(4).Infof("volume: %+v", volumes[idx])
		if deviceid == volumes[idx].DeviceID {
			return &volumes[idx], nil
		}
	}

	return nil, fmt.Errorf("unable to find volume for deviceid %s", deviceid)
}

// GetMountInfo gets the mount info of the mountpoint
func GetMountInfo(mountpoint string) (*MountInfo, error) {
	command := []string{"bash", "-c", fmt.Sprintf(procFindmntCommand, mountpoint)}

	thecmd := exec.Command(command[0], command[1:]...)
	glog.V(1).Infof("command: %+v", command)
	output, err := thecmd.CombinedOutput()
	if err != nil {
		return nil, err
	}

	// [root@jrivera-tb1 ~]# /bin/findmnt --noheading -o MAJ:MIN,SOURCE,TARGET,OPTIONS /tmp/serviced/var
	//   0:137 10.87.209.168:/serviced_var /tmp/serviced/var rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=10.87.209.168,local_lock=none,addr=10.87.209.168
	line := strings.TrimSpace(string(output))

	glog.V(4).Infof("line: %s", line)

	fields := strings.Fields(line)
	switch len(fields) {
	case 5:
		break
	case 0:
		return nil, ErrMountPointNotFound
	default:
		glog.Infof("command: %+v", command)
		return nil, fmt.Errorf("expected 5 fields, got %d: %s", len(fields), line)
	}
	info := MountInfo{
		DeviceID:   fields[0],
		FSType:     fields[1],
		RemotePath: fields[2],
		LocalPath:  fields[3],
		ServerIP:   fields[4],
	}
	glog.V(4).Infof("mount info: %+v", info)
	return &info, nil
}

// GetNFSVolumeInfo gets the NFSMountInfo of the mountpoint
func GetNFSVolumeInfo(mountpoint string) (*NFSMountInfo, error) {
	minfo, err := GetMountInfo(mountpoint)
	if err != nil {
		return nil, err
	}

	volume, err := GetProcNFSFSVolume(minfo.DeviceID)
	if err != nil {
		return nil, err
	}

	info := NFSMountInfo{
		MountInfo: *minfo,

		Version:  volume.Version,
		ServerID: volume.ServerID,
		Port:     volume.Port,
		FSID:     volume.FSID,
		FSCache:  volume.FSCache,
	}

	return &info, nil
}
<|endoftext|>


<commit_before>package completion

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

	"../cpath"
)

func isExecutable(path string) bool {
	return cpath.IsExecutableSuffix(filepath.Ext(path))
}

func listUpAllExecutableOnPath() []string {
	list := make([]string, 0, 100)
	pathEnv := os.Getenv("PATH")
	dirList := filepath.SplitList(pathEnv)
	for _, dir1 := range dirList {
		dirHandle, dirErr := os.Open(dir1)
		if dirErr != nil {
			continue
		}
		defer dirHandle.Close()
		files, filesErr := dirHandle.Readdir(0)
		if filesErr != nil {
			continue
		}
		for _, file1 := range files {
			if file1.IsDir() {
				continue
			}
			name := file1.Name()
			if isExecutable(name) {
				list = append(list, path.Base(name))
			}
		}
	}
	return list
}

func listUpCurrentAllExecutable(str string) ([]string, error) {
	listTmp, listErr := listUpFiles(str)
	if listErr != nil {
		return nil, listErr
	}
	list := make([]string, 0)
	for _, fname := range listTmp {
		if strings.HasSuffix(fname, "/") || strings.HasSuffix(fname, "\\") || isExecutable(fname) {
			list = append(list, fname)
		}
	}
	return list, nil
}

func removeDup(list []string) []string {
	found := map[string]bool{}
	result := make([]string, 0, len(list))

	for _, value := range list {
		if _, ok := found[value]; !ok {
			result = append(result, value)
			found[value] = true
		}
	}
	return result
}

var command_listupper = []func() []string{
	listUpAllExecutableOnPath,
}

func AppendCommandLister(f func() []string) {
	command_listupper = append(command_listupper, f)
}

func listUpCommands(str string) ([]string, error) {
	list, listErr := listUpCurrentAllExecutable(str)
	if listErr != nil {
		return nil, listErr
	}
	strUpr := strings.ToUpper(str)
	for _, f := range command_listupper {
		for _, name := range f() {
			name1Upr := strings.ToUpper(name)
			if strings.HasPrefix(name1Upr, strUpr) {
				list = append(list, name)
			}
		}
	}
	return removeDup(list), nil
}
<commit_msg>Commandname Completion supports %NYAGOSPATH%<commit_after>package completion

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

	"../cpath"
)

func isExecutable(path string) bool {
	return cpath.IsExecutableSuffix(filepath.Ext(path))
}

func listUpAllExecutableOnEnv(envName string) []string {
	list := make([]string, 0, 100)
	pathEnv := os.Getenv(envName)
	dirList := filepath.SplitList(pathEnv)
	for _, dir1 := range dirList {
		dirHandle, dirErr := os.Open(dir1)
		if dirErr != nil {
			continue
		}
		defer dirHandle.Close()
		files, filesErr := dirHandle.Readdir(0)
		if filesErr != nil {
			continue
		}
		for _, file1 := range files {
			if file1.IsDir() {
				continue
			}
			name := file1.Name()
			if isExecutable(name) {
				list = append(list, path.Base(name))
			}
		}
	}
	return list
}

func listUpCurrentAllExecutable(str string) ([]string, error) {
	listTmp, listErr := listUpFiles(str)
	if listErr != nil {
		return nil, listErr
	}
	list := make([]string, 0)
	for _, fname := range listTmp {
		if strings.HasSuffix(fname, "/") || strings.HasSuffix(fname, "\\") || isExecutable(fname) {
			list = append(list, fname)
		}
	}
	return list, nil
}

func removeDup(list []string) []string {
	found := map[string]bool{}
	result := make([]string, 0, len(list))

	for _, value := range list {
		if _, ok := found[value]; !ok {
			result = append(result, value)
			found[value] = true
		}
	}
	return result
}

var command_listupper = []func() []string{
	func() []string { return listUpAllExecutableOnEnv("PATH") },
	func() []string { return listUpAllExecutableOnEnv("NYAGOSPATH") },
}

func AppendCommandLister(f func() []string) {
	command_listupper = append(command_listupper, f)
}

func listUpCommands(str string) ([]string, error) {
	list, listErr := listUpCurrentAllExecutable(str)
	if listErr != nil {
		return nil, listErr
	}
	strUpr := strings.ToUpper(str)
	for _, f := range command_listupper {
		for _, name := range f() {
			name1Upr := strings.ToUpper(name)
			if strings.HasPrefix(name1Upr, strUpr) {
				list = append(list, name)
			}
		}
	}
	return removeDup(list), nil
}
<|endoftext|>


<commit_before>package parser

import "../lexer"

type Todo []TaskDecl

type TaskDecl struct {
	MainTask Task
	Subtasks []Subtask
}

type Task struct {
	TaskName string
	TaskDeps Dependencies
}

type Subtask struct {
	TaskName string
}

type Dependencies []string

func consume() {
	lookAhead = <-tokenChan
	return
}

func consumeTaskName() string {
	if lookAhead.Type != lexer.NAME {
		panic("name expected")
	}
	taskName := lookAhead.Text
	consume()
	return taskName
}

func parse() Todo {
	todo := parseTodo()
	if lookAhead.Type != lexer.EOF {
		panic("EOF expected")
	}
	return todo
}

func parseTodo() Todo {
	var taskDecls []TaskDecl
	taskDecls = append(taskDecls, parseTaskDecl())
	for lookAhead.Type == lexer.NAME {
		taskDecls = append(taskDecls, parseTaskDecl())
	}
	return taskDecls
}

func parseTaskDecl() TaskDecl {
	mainTask := parseMainTask()
	var subs []Subtask
	if lookAhead.Type == lexer.HYPHEN {
		subs = parseSubtasks()
	}
	return TaskDecl{mainTask, subs}
}

func parseMainTask() Task {
	taskName := consumeTaskName()
	var deps Dependencies
	if lookAhead.Type == lexer.COLON {
		consume()
		deps = parseDependencies()
	}
	return Task{taskName, deps}
}

func parseSubtasks() []Subtask {
	var subs []Subtask
	for lookAhead.Type == lexer.HYPHEN {
		consume()
		subs = append(subs, Subtask{consumeTaskName()})
	}
	return subs
}

func parseDependencies() Dependencies {
	var taskNames []string
	taskNames = append(taskNames, consumeTaskName())
	for lookAhead.Type == lexer.COMMA {
		consume()
		taskNames = append(taskNames, consumeTaskName())
	}
	return taskNames
}

var tokenChan chan lexer.Token
var lookAhead lexer.Token

func Run(nodeChan chan Todo, lexerTokenChan chan lexer.Token) {
	tokenChan = lexerTokenChan
	nodeChan <- parse()
}
<commit_msg>Add log for debugging.<commit_after>package parser

import (
	"os"
	"../lexer"

	"github.com/Sirupsen/logrus"
)

var log = logrus.New()

func init() {
	if os.Getenv("DEBUG") == "1" {
		log.Level = logrus.DebugLevel
	}
}

type Todo []TaskDecl

type TaskDecl struct {
	MainTask Task
	Subtasks []Subtask
}

type Task struct {
	TaskName string
	TaskDeps Dependencies
}

type Subtask struct {
	TaskName string
}

type Dependencies []string

func consume() {
	lookAhead = <-tokenChan
	log.Debugf("Got token %s, %s", lookAhead.Type, lookAhead.Text)
	return
}

func consumeTaskName() string {
	if lookAhead.Type != lexer.NAME {
		panic("name expected")
	}
	taskName := lookAhead.Text
	consume()
	return taskName
}

func parse() Todo {
	todo := parseTodo()
	if lookAhead.Type != lexer.EOF {
		panic("EOF expected")
	}
	return todo
}

func parseTodo() Todo {
	var taskDecls []TaskDecl
	taskDecls = append(taskDecls, parseTaskDecl())
	for lookAhead.Type == lexer.NAME {
		taskDecls = append(taskDecls, parseTaskDecl())
	}
	log.Debugf("parsed todo: %s", taskDecls)
	return taskDecls
}

func parseTaskDecl() TaskDecl {
	mainTask := parseMainTask()
	var subs []Subtask
	if lookAhead.Type == lexer.HYPHEN {
		subs = parseSubtasks()
	}
	log.Debugf("parsed task decl: %s, %s", mainTask, subs)
	return TaskDecl{mainTask, subs}
}

func parseMainTask() Task {
	taskName := consumeTaskName()
	var deps Dependencies
	if lookAhead.Type == lexer.COLON {
		consume()
		deps = parseDependencies()
	}
	log.Debugf("parsed main task: %s, %s", taskName, deps)
	return Task{taskName, deps}
}

func parseSubtasks() []Subtask {
	var subs []Subtask
	for lookAhead.Type == lexer.HYPHEN {
		consume()
		subs = append(subs, Subtask{consumeTaskName()})
	}
	log.Debugf("parsed subtasks: %s", subs)
	return subs
}

func parseDependencies() Dependencies {
	var taskNames []string
	taskNames = append(taskNames, consumeTaskName())
	for lookAhead.Type == lexer.COMMA {
		consume()
		taskNames = append(taskNames, consumeTaskName())
	}
	log.Debugf("parsed dependencies: %s", taskNames)
	return taskNames
}

var tokenChan chan lexer.Token
var lookAhead lexer.Token

func Run(nodeChan chan Todo, lexerTokenChan chan lexer.Token) {
	tokenChan = lexerTokenChan
	nodeChan <- parse()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/ninibe/netlog/biglog"
)

func main() {
	usage := `Usage: go run example.go [step1] [step2] ...`

	if len(os.Args) == 1 {
		println(usage)
		return
	}

	switch os.Args[1] {
	case "step1":
		step1()
	case "step2":
		step2()
	case "step3":
		step3()
	case "step4":
		step4()
	case "step5":
		step5()
	default:
		println(usage)
	}
}

// Creating a writing demo
func step1() {
	// Create a BigLog called demo, with a preallocated index size of 10 entries per segments
	// 10 is for demo purposes, is should be 10k-10M depending on your use cases
	bl, err := biglog.Create("demo", 10)
	panicOn(err)

	// Write one entry, could be any blob of bytes
	_, err = bl.Write([]byte("some data"))
	panicOn(err)

	println("inspect your segment:")
	println("xxd demo/00000000000000000000.index")
	println("xxd demo/00000000000000000000.data")
}

// Split segment demo
func step2() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)

	// Write more data
	_, err = bl.Write([]byte("some more data"))
	panicOn(err)

	// Create a new segment
	err = bl.Split()
	panicOn(err)

	// Writes go the the new segment
	_, err = bl.Write([]byte("new segment data"))
	panicOn(err)

	println("inspect your segments:")
	println("ls demo")
	println("xxd demo/00000000000000000002.index")
	println("xxd demo/00000000000000000002.data")
}

// readers demo
func step3() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)

	// Create a new index reader
	ir, _, err := biglog.NewIndexReader(bl, 0)
	panicOn(err)

	// Read the entries stored
	entries, err := ir.ReadEntries(10)
	println("Entries:")
	for _, entry := range entries {
		fmt.Printf("%+v\n", entry)
	}

	// Create a new data reader
	r, _, err := biglog.NewReader(bl, 0)
	panicOn(err)

	data, err := ioutil.ReadAll(r)
	panicOn(err)
	fmt.Printf("Data:\n%s\n", data)
}

// scanner demo
func step4() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)

	// WriteN means the written data contains 5 offsets
	_, err = bl.WriteN([]byte("this is data for 5 offsets"), 5)
	panicOn(err)

	_, err = bl.Write([]byte("another single message"))
	panicOn(err)

	// Create an scanner from the beginning of the log
	sc, err := biglog.NewScanner(bl, 0)
	panicOn(err)

	for {
		if !sc.Scan() {
			break
		}
		fmt.Printf("offset = %d n = %d data = %s\n", sc.Offset(), sc.ODelta(), sc.Bytes())
	}
}

// watcher demo
func step5() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)

	wc := biglog.NewWatcher(bl)
	go func() {
		for {
			<-wc.Watch()
			println("write detected")
		}
	}()

	for i := 0; i < 5; i++ {
		_, _ = bl.Write([]byte("foo"))
		time.Sleep(time.Second)
	}
}

func panicOn(err error) {
	if err != nil && err != io.EOF {
		panic(err)
	}
}
<commit_msg>biglog: close resources on example<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"time"

	"github.com/ninibe/netlog/biglog"
)

func main() {
	usage := `Usage: go run example.go [step1] [step2] ...`

	if len(os.Args) == 1 {
		println(usage)
		return
	}

	switch os.Args[1] {
	case "step1":
		step1()
	case "step2":
		step2()
	case "step3":
		step3()
	case "step4":
		step4()
	case "step5":
		step5()
	default:
		println(usage)
	}
}

// Creating a writing demo
func step1() {
	// Create a BigLog called demo, with a preallocated index size of 10 entries per segments
	// 10 is for demo purposes, is should be 10k-10M depending on your use cases
	bl, err := biglog.Create("demo", 10)
	panicOn(err)
	defer bl.Close()

	// Write one entry, could be any blob of bytes
	_, err = bl.Write([]byte("some data"))
	panicOn(err)

	println("inspect your segment:")
	println("xxd demo/00000000000000000000.index")
	println("xxd demo/00000000000000000000.data")
}

// Split segment demo
func step2() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)
	defer bl.Close()

	// Write more data
	_, err = bl.Write([]byte("some more data"))
	panicOn(err)

	// Create a new segment
	err = bl.Split()
	panicOn(err)

	// Writes go the the new segment
	_, err = bl.Write([]byte("new segment data"))
	panicOn(err)

	println("inspect your segments:")
	println("ls demo")
	println("xxd demo/00000000000000000002.index")
	println("xxd demo/00000000000000000002.data")
}

// readers demo
func step3() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)
	defer bl.Close()

	// Create a new index reader
	ir, _, err := biglog.NewIndexReader(bl, 0)
	panicOn(err)
	defer ir.Close()

	// Read the entries stored
	entries, err := ir.ReadEntries(10)
	println("Entries:")
	for _, entry := range entries {
		fmt.Printf("%+v\n", entry)
	}

	// Create a new data reader
	r, _, err := biglog.NewReader(bl, 0)
	panicOn(err)
	defer r.Close()

	data, err := ioutil.ReadAll(r)
	panicOn(err)
	fmt.Printf("Data:\n%s\n", data)
}

// scanner demo
func step4() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)
	defer bl.Close()

	// WriteN means the written data contains 5 offsets
	_, err = bl.WriteN([]byte("this is data for 5 offsets"), 5)
	panicOn(err)

	_, err = bl.Write([]byte("another single message"))
	panicOn(err)

	// Create an scanner from the beginning of the log
	sc, err := biglog.NewScanner(bl, 0)
	panicOn(err)
	defer sc.Close()

	for {
		if !sc.Scan() {
			break
		}
		fmt.Printf("offset = %d n = %d data = %s\n", sc.Offset(), sc.ODelta(), sc.Bytes())
	}
}

// watcher demo
func step5() {
	// Open an existing BigLog
	bl, err := biglog.Open("demo")
	panicOn(err)
	defer bl.Close()

	wc := biglog.NewWatcher(bl)
	defer wc.Close()

	go func() {
		for {
			<-wc.Watch()
			println("write detected")
		}
	}()

	for i := 0; i < 5; i++ {
		_, _ = bl.Write([]byte("foo"))
		time.Sleep(time.Second)
	}
}

func panicOn(err error) {
	if err != nil && err != io.EOF {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package people

import (
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

// Driver interface
type Driver interface {
	Read(id string) (person Person, found bool, err error)
	CheckConnectivity() (ok bool, err error)
}

// CypherDriver struct
type CypherDriver struct {
	db *neoism.Database
}

//NewCypherDriver instanciate driver
func NewCypherDriver(db *neoism.Database) CypherDriver {
	return CypherDriver{db}
}

// CheckConnectivity tests neo4j by running a simple cypher query
func (pcw CypherDriver) CheckConnectivity() (bool, error) {
	results := []struct {
		ID int
	}{}
	query := &neoism.CypherQuery{
		Statement: "MATCH (p:Person) RETURN p.id LIMIT 1",
		Result:    &results,
	}
	err := pcw.db.Cypher(query)
	ok := len(results) == 1 && results[0].ID != 0
	log.Debugf("CheckConnectivity %t %+v", ok, err)
	return ok, err
}

type neoChangeEvent struct {
	StartedAt string
	EndedAt   string
}

type neoReadStruct struct {
	P struct {
		ID        string
		Types     []string
		PrefLabel string
		Labels    []string
	}
	M []struct {
		M struct {
			ID           string
			Types        []string
			PrefLabel    string
			Title        string
			ChangeEvents []neoChangeEvent
		}
		O struct {
			ID        string
			Types     []string
			PrefLabel string
			Labels    []string
		}
		R []struct {
			ID           string
			Types        []string
			PrefLabel    string
			ChangeEvents []neoChangeEvent
		}
	}
}

func (pcw CypherDriver) Read(uuid string) (person Person, found bool, err error) {
	person = Person{}
	results := []struct {
		Rs []neoReadStruct
	}{}
	query := &neoism.CypherQuery{
		Statement: `
                        MATCH (p:Person{uuid:{uuid}})<-[:HAS_MEMBER]-(m:Membership)
                        OPTIONAL MATCH (m)-[:HAS_ORGANISATION]->(o:Organisation)
                        OPTIONAL MATCH (m)-[rr:HAS_ROLE]->(r:Role)
                        WITH
                                { id:p.uuid, types:labels(p), prefLabel:p.prefLabel, labels:p.labels} as p,
                                { id:o.uuid, types:labels(o), prefLabel:o.prefLabel, labels:o.labels} as o,
                                { id:m.uuid, types:labels(m), prefLabel:m.prefLabel, title:m.title, changeEvents:[{startedAt:m.inceptionDate}, {endedAt:m.terminationDate}] } as m,
                                { id:r.uuid, types:labels(r), prefLabel:r.prefLabel, changeEvents:[{startedAt:m.inceptionDate}, {endedAt:m.terminationDate}] } as r
                        WITH p, m, o, collect(r) as r
                        WITH p, collect({m:m, o:o, r:r}) as m
                        RETURN collect ({p:p, m:m}) as rs
                `,
		Parameters: neoism.Props{"uuid": uuid},
		Result:     &results,
	}
	err = pcw.db.Cypher(query)
	if err != nil {
		log.Errorf("Error looking up uuid %s with query %s from neoism: %+v\n", uuid, query.Statement, err)
		return Person{}, false, fmt.Errorf("Error accessing datastore for uuid: %s", uuid)
	}
	log.Debugf("CypherResult ReadPeople for uuid: %s was: %+v", uuid, results[0].Rs[0])
	if (len(results)) == 0 {
		return Person{}, false, nil
	} else if len(results) != 1 && len(results[0].Rs) != 1 {
		errMsg := fmt.Sprintf("Multiple people found with the same uuid:%s !", uuid)
		log.Error(errMsg)
		return Person{}, true, errors.New(errMsg)
	}
	person = neoReadStructToPerson(results[0].Rs[0])
	log.Debugf("Returning %v", person)
	return person, true, nil
}

func neoReadStructToPerson(neo neoReadStruct) Person {
	public := Person{}
	public.Thing = &Thing{}
	public.ID = idURL(neo.P.ID)
	public.APIURL = apiURL(neo.P.ID, neo.P.Types)
	public.Types = typeURIs(neo.P.Types)
	public.PrefLabel = neo.P.PrefLabel
	if len(neo.P.Labels) > 0 {
		public.Labels = &neo.P.Labels
	}
	public.Memberships = make([]Membership, len(neo.M))
	for mIdx, neoMem := range neo.M {
		membership := Membership{}
		membership.Title = neoMem.M.PrefLabel
		membership.Organisation = Organisation{}
		membership.Organisation.Thing = &Thing{}
		membership.Organisation.ID = idURL(neoMem.O.ID)
		membership.Organisation.APIURL = apiURL(neoMem.O.ID, neoMem.O.Types)
		membership.Organisation.Types = typeURIs(neoMem.O.Types)
		membership.Organisation.PrefLabel = neoMem.O.PrefLabel
		if len(neoMem.O.Labels) > 0 {
			membership.Organisation.Labels = &neoMem.O.Labels
		}
		membership.ChangeEvents = changeEvent(neoMem.M.ChangeEvents)
		membership.Roles = make([]Role, len(neoMem.R))
		for rIdx, neoRole := range neoMem.R {
			role := Role{}
			role.Thing = &Thing{}
			role.ID = idURL(neoRole.ID)
			role.APIURL = apiURL(neoRole.ID, neoRole.Types)
			role.PrefLabel = neoRole.PrefLabel
			membership.ChangeEvents = changeEvent(neoRole.ChangeEvents)
			membership.Roles[rIdx] = role
		}
		public.Memberships[mIdx] = membership
	}
	log.Debugf("neoReadStructToPerson neo: %+v result: %+v", neo, public)
	return public
}

func changeEvent(neoChgEvts []neoChangeEvent) *[]ChangeEvent {
	if len(neoChgEvts) == 0 {
		return nil
	}
	var results []ChangeEvent
	for _, neoChgEvt := range neoChgEvts {
		if neoChgEvt.StartedAt != "" {
			results = append(results, ChangeEvent{StartedAt: neoChgEvt.StartedAt})
		}
		if neoChgEvt.EndedAt != "" {
			results = append(results, ChangeEvent{EndedAt: neoChgEvt.EndedAt})
		}
	}
	log.Debugf("changeEvent converted: %+v result:%+v", neoChgEvts, results)
	return &results
}

func apiURL(id string, types []string) string {
	base := "http://api.ft.com/"
	for _, t := range types {
		switch t {
		case "Person":
			return base + "people/" + id
		case "Organisation", "Company", "PublicCompany", "PrivateCompany":
			return base + "organisations/" + id
		case "Role":
			return base + "roles/" + id
		case "Membership":
			return base + "memberships/" + id
		}
	}
	return base + "things/" + id
}

func idURL(neoID string) string {
	return "http://api.ft.com/things/" + neoID
}

func typeURIs(neoTypes []string) []string {
	var results []string
	base := "http://www.ft.com/ontology/"
	for _, t := range neoTypes {
		switch t {
		case "Person":
			results = append(results, base+"person/Person")
		case "Organisation":
			results = append(results, base+"organisation/"+t)
		case "Company", "PublicCompany", "PrivateCompany":
			results = append(results, base+"company/"+t)
		}
	}
	log.Debugf("Converted types: %v to %v", neoTypes, results)
	return results
}
<commit_msg>API Parity - apiUrl and id are identical for Roles and Memberships<commit_after>package people

import (
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/jmcvetta/neoism"
)

// Driver interface
type Driver interface {
	Read(id string) (person Person, found bool, err error)
	CheckConnectivity() (ok bool, err error)
}

// CypherDriver struct
type CypherDriver struct {
	db *neoism.Database
}

//NewCypherDriver instanciate driver
func NewCypherDriver(db *neoism.Database) CypherDriver {
	return CypherDriver{db}
}

// CheckConnectivity tests neo4j by running a simple cypher query
func (pcw CypherDriver) CheckConnectivity() (bool, error) {
	results := []struct {
		ID int
	}{}
	query := &neoism.CypherQuery{
		Statement: "MATCH (p:Person) RETURN p.id LIMIT 1",
		Result:    &results,
	}
	err := pcw.db.Cypher(query)
	ok := len(results) == 1 && results[0].ID != 0
	log.Debugf("CheckConnectivity %t %+v", ok, err)
	return ok, err
}

type neoChangeEvent struct {
	StartedAt string
	EndedAt   string
}

type neoReadStruct struct {
	P struct {
		ID        string
		Types     []string
		PrefLabel string
		Labels    []string
	}
	M []struct {
		M struct {
			ID           string
			Types        []string
			PrefLabel    string
			Title        string
			ChangeEvents []neoChangeEvent
		}
		O struct {
			ID        string
			Types     []string
			PrefLabel string
			Labels    []string
		}
		R []struct {
			ID           string
			Types        []string
			PrefLabel    string
			ChangeEvents []neoChangeEvent
		}
	}
}

func (pcw CypherDriver) Read(uuid string) (person Person, found bool, err error) {
	person = Person{}
	results := []struct {
		Rs []neoReadStruct
	}{}
	query := &neoism.CypherQuery{
		Statement: `
                        MATCH (p:Person{uuid:{uuid}})<-[:HAS_MEMBER]-(m:Membership)
                        OPTIONAL MATCH (m)-[:HAS_ORGANISATION]->(o:Organisation)
                        OPTIONAL MATCH (m)-[rr:HAS_ROLE]->(r:Role)
                        WITH
                                { id:p.uuid, types:labels(p), prefLabel:p.prefLabel, labels:p.labels} as p,
                                { id:o.uuid, types:labels(o), prefLabel:o.prefLabel, labels:o.labels} as o,
                                { id:m.uuid, types:labels(m), prefLabel:m.prefLabel, title:m.title, changeEvents:[{startedAt:m.inceptionDate}, {endedAt:m.terminationDate}] } as m,
                                { id:r.uuid, types:labels(r), prefLabel:r.prefLabel, changeEvents:[{startedAt:m.inceptionDate}, {endedAt:m.terminationDate}] } as r
                        WITH p, m, o, collect(r) as r
                        WITH p, collect({m:m, o:o, r:r}) as m
                        RETURN collect ({p:p, m:m}) as rs
                `,
		Parameters: neoism.Props{"uuid": uuid},
		Result:     &results,
	}
	err = pcw.db.Cypher(query)
	if err != nil {
		log.Errorf("Error looking up uuid %s with query %s from neoism: %+v\n", uuid, query.Statement, err)
		return Person{}, false, fmt.Errorf("Error accessing datastore for uuid: %s", uuid)
	}
	log.Debugf("CypherResult ReadPeople for uuid: %s was: %+v", uuid, results[0].Rs[0])
	if (len(results)) == 0 {
		return Person{}, false, nil
	} else if len(results) != 1 && len(results[0].Rs) != 1 {
		errMsg := fmt.Sprintf("Multiple people found with the same uuid:%s !", uuid)
		log.Error(errMsg)
		return Person{}, true, errors.New(errMsg)
	}
	person = neoReadStructToPerson(results[0].Rs[0])
	log.Debugf("Returning %v", person)
	return person, true, nil
}

func neoReadStructToPerson(neo neoReadStruct) Person {
	public := Person{}
	public.Thing = &Thing{}
	public.ID = idURL(neo.P.ID)
	public.APIURL = apiURL(neo.P.ID, neo.P.Types)
	public.Types = typeURIs(neo.P.Types)
	public.PrefLabel = neo.P.PrefLabel
	if len(neo.P.Labels) > 0 {
		public.Labels = &neo.P.Labels
	}
	public.Memberships = make([]Membership, len(neo.M))
	for mIdx, neoMem := range neo.M {
		membership := Membership{}
		membership.Title = neoMem.M.PrefLabel
		membership.Organisation = Organisation{}
		membership.Organisation.Thing = &Thing{}
		membership.Organisation.ID = idURL(neoMem.O.ID)
		membership.Organisation.APIURL = apiURL(neoMem.O.ID, neoMem.O.Types)
		membership.Organisation.Types = typeURIs(neoMem.O.Types)
		membership.Organisation.PrefLabel = neoMem.O.PrefLabel
		if len(neoMem.O.Labels) > 0 {
			membership.Organisation.Labels = &neoMem.O.Labels
		}
		membership.ChangeEvents = changeEvent(neoMem.M.ChangeEvents)
		membership.Roles = make([]Role, len(neoMem.R))
		for rIdx, neoRole := range neoMem.R {
			role := Role{}
			role.Thing = &Thing{}
			role.ID = idURL(neoRole.ID)
			role.APIURL = apiURL(neoRole.ID, neoRole.Types)
			role.PrefLabel = neoRole.PrefLabel
			membership.ChangeEvents = changeEvent(neoRole.ChangeEvents)
			membership.Roles[rIdx] = role
		}
		public.Memberships[mIdx] = membership
	}
	log.Debugf("neoReadStructToPerson neo: %+v result: %+v", neo, public)
	return public
}

func changeEvent(neoChgEvts []neoChangeEvent) *[]ChangeEvent {
	if len(neoChgEvts) == 0 {
		return nil
	}
	var results []ChangeEvent
	for _, neoChgEvt := range neoChgEvts {
		if neoChgEvt.StartedAt != "" {
			results = append(results, ChangeEvent{StartedAt: neoChgEvt.StartedAt})
		}
		if neoChgEvt.EndedAt != "" {
			results = append(results, ChangeEvent{EndedAt: neoChgEvt.EndedAt})
		}
	}
	log.Debugf("changeEvent converted: %+v result:%+v", neoChgEvts, results)
	return &results
}

func apiURL(id string, types []string) string {
	base := "http://api.ft.com/"
	for _, t := range types {
		switch t {
		case "Person":
			return base + "people/" + id
		case "Organisation", "Company", "PublicCompany", "PrivateCompany":
			return base + "organisations/" + id
		}
	}
	return base + "things/" + id
}

func idURL(neoID string) string {
	return "http://api.ft.com/things/" + neoID
}

func typeURIs(neoTypes []string) []string {
	var results []string
	base := "http://www.ft.com/ontology/"
	for _, t := range neoTypes {
		switch t {
		case "Person":
			results = append(results, base+"person/Person")
		case "Organisation":
			results = append(results, base+"organisation/"+t)
		case "Company", "PublicCompany", "PrivateCompany":
			results = append(results, base+"company/"+t)
		}
	}
	log.Debugf("Converted types: %v to %v", neoTypes, results)
	return results
}
<|endoftext|>


<commit_before>/*
Overlay Action

Recursive copy of directory or file to target filesystem.

Yaml syntax:
 - action: overlay
   origin: name
   source: directory
   destination: directory

Mandatory properties:

- source -- relative path to the directory or file located in path referenced by `origin`.
In case if this property is absent then pure path referenced by 'origin' will be used.

Optional properties:

- origin -- reference to named file or directory.

- destination -- absolute path in the target rootfs where 'source' will be copied.
All existing files will be overwritten.
If destination isn't set '/' of the rootfs will be usedi.
*/
package actions

import (
	"fmt"
	"path"

	"github.com/go-debos/debos"
)

type OverlayAction struct {
	debos.BaseAction `yaml:",inline"`
	Origin           string // origin of overlay, here the export from other action may be used
	Source           string // external path there overlay is
	Destination      string // path inside of rootfs
}

func (overlay *OverlayAction) Verify(context *debos.DebosContext) error {
	if _, err := debos.RestrictedPath(context.Rootdir, overlay.Destination); err != nil {
		return err
	}
	return nil
}

func (overlay *OverlayAction) Run(context *debos.DebosContext) error {
	overlay.LogStart()
	origin := context.RecipeDir

	//Trying to get a filename from exports first
	if len(overlay.Origin) > 0 {
		var found bool
		if origin, found = context.Origins[overlay.Origin]; !found {
			return fmt.Errorf("Origin not found '%s'", overlay.Origin)
		}
	}

	sourcedir := path.Join(origin, overlay.Source)
	destination, err := debos.RestrictedPath(context.Rootdir, overlay.Destination)
	if err != nil {
		return err
	}

	return debos.CopyTree(sourcedir, destination)
}
<commit_msg>Fix tiny typo in the docs for the overlay action<commit_after>/*
Overlay Action

Recursive copy of directory or file to target filesystem.

Yaml syntax:
 - action: overlay
   origin: name
   source: directory
   destination: directory

Mandatory properties:

- source -- relative path to the directory or file located in path referenced by `origin`.
In case if this property is absent then pure path referenced by 'origin' will be used.

Optional properties:

- origin -- reference to named file or directory.

- destination -- absolute path in the target rootfs where 'source' will be copied.
All existing files will be overwritten.
If destination isn't set '/' of the rootfs will be used.
*/
package actions

import (
	"fmt"
	"path"

	"github.com/go-debos/debos"
)

type OverlayAction struct {
	debos.BaseAction `yaml:",inline"`
	Origin           string // origin of overlay, here the export from other action may be used
	Source           string // external path there overlay is
	Destination      string // path inside of rootfs
}

func (overlay *OverlayAction) Verify(context *debos.DebosContext) error {
	if _, err := debos.RestrictedPath(context.Rootdir, overlay.Destination); err != nil {
		return err
	}
	return nil
}

func (overlay *OverlayAction) Run(context *debos.DebosContext) error {
	overlay.LogStart()
	origin := context.RecipeDir

	//Trying to get a filename from exports first
	if len(overlay.Origin) > 0 {
		var found bool
		if origin, found = context.Origins[overlay.Origin]; !found {
			return fmt.Errorf("Origin not found '%s'", overlay.Origin)
		}
	}

	sourcedir := path.Join(origin, overlay.Source)
	destination, err := debos.RestrictedPath(context.Rootdir, overlay.Destination)
	if err != nil {
		return err
	}

	return debos.CopyTree(sourcedir, destination)
}
<|endoftext|>


<commit_before>package apps

import (
	"io"
	"net/url"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/prefixer"
)

const (
	// ManifestMaxSize is the manifest maximum size
	ManifestMaxSize = 2 << (2 * 10) // 2MB
	// WebappManifestName is the name of the manifest at the root of the
	// client-side application directory
	WebappManifestName = "manifest.webapp"
	// KonnectorManifestName is the name of the manifest at the root of the
	// konnector application directory
	KonnectorManifestName = "manifest.konnector"
)

// State is the state of the application
type State string

const (
	// Installing state
	Installing = "installing"
	// Upgrading state
	Upgrading = "upgrading"
	// Installed state, can be used to state that an application has been
	// installed but needs a user interaction to be activated and "ready".
	Installed = "installed"
	// Ready state
	Ready = "ready"
	// Errored state
	Errored = "errored"
)

// AppType is an enum to represent the type of application: webapp clientside
// or konnector serverside.
type AppType int

const (
	// Webapp is the clientside application type
	Webapp AppType = iota + 1
	// Konnector is the serverside application type
	Konnector
)

// KonnectorArchiveName is the name of the archive created to store the
// konnectors sources.
const KonnectorArchiveName = "app.tar"

// SubDomainer is an interface with a single method to build an URL from a slug
type SubDomainer interface {
	SubDomain(s string) *url.URL
}

// Manifest interface is used by installer to encapsulate the manifest metadata
// that can represent either a webapp or konnector manifest
type Manifest interface {
	couchdb.Doc
	Match(field, expected string) bool
	ReadManifest(i io.Reader, slug, sourceURL string) (Manifest, error)

	Create(db prefixer.Prefixer) error
	Update(db prefixer.Prefixer) error
	Delete(db prefixer.Prefixer) error

	AppType() AppType
	Permissions() permissions.Set
	Source() string
	Version() string
	SetAvailableVersion(version string)
	Slug() string
	State() State
	LastUpdate() time.Time
	Terms() Terms

	SetError(err error)
	Error() error

	SetSource(src *url.URL)
	SetState(state State)
	SetVersion(version string)
}

// GetBySlug returns an app manifest identified by its slug
func GetBySlug(db prefixer.Prefixer, slug string, appType AppType) (Manifest, error) {
	var man Manifest
	var err error
	switch appType {
	case Webapp:
		man, err = GetWebappBySlug(db, slug)
	case Konnector:
		man, err = GetKonnectorBySlug(db, slug)
	}
	if err != nil {
		return nil, err
	}
	return man, nil
}

func routeMatches(path, ctx []string) bool {
	for i, part := range ctx {
		if path[i] != part {
			return false
		}
	}
	return true
}
<commit_msg>Add NewAppType constructor and String() functions for appTypes<commit_after>package apps

import (
	"io"
	"net/url"
	"time"

	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/prefixer"
)

const (
	// ManifestMaxSize is the manifest maximum size
	ManifestMaxSize = 2 << (2 * 10) // 2MB
	// WebappManifestName is the name of the manifest at the root of the
	// client-side application directory
	WebappManifestName = "manifest.webapp"
	// KonnectorManifestName is the name of the manifest at the root of the
	// konnector application directory
	KonnectorManifestName = "manifest.konnector"
)

// State is the state of the application
type State string

const (
	// Installing state
	Installing = "installing"
	// Upgrading state
	Upgrading = "upgrading"
	// Installed state, can be used to state that an application has been
	// installed but needs a user interaction to be activated and "ready".
	Installed = "installed"
	// Ready state
	Ready = "ready"
	// Errored state
	Errored = "errored"
)

// AppType is an enum to represent the type of application: webapp clientside
// or konnector serverside.
type AppType int

const (
	// Webapp is the clientside application type
	Webapp AppType = iota + 1
	// Konnector is the serverside application type
	Konnector
)

// String returns the human-readable doctype from the AppType
func (at AppType) String() string {
	switch at {
	case Webapp:
		return "io.cozy.apps"
	case Konnector:
		return "io.cozy.konnectors"
	default:
		return "unknown"
	}
}

// NewAppType creates a new AppType from a string
func NewAppType(doctype string) AppType {
	switch doctype {
	case "io.cozy.konnectors":
		return Konnector
	case "io.cozy.apps":
		return Webapp
	default:
		return 0
	}
}

// KonnectorArchiveName is the name of the archive created to store the
// konnectors sources.
const KonnectorArchiveName = "app.tar"

// SubDomainer is an interface with a single method to build an URL from a slug
type SubDomainer interface {
	SubDomain(s string) *url.URL
}

// Manifest interface is used by installer to encapsulate the manifest metadata
// that can represent either a webapp or konnector manifest
type Manifest interface {
	couchdb.Doc
	Match(field, expected string) bool
	ReadManifest(i io.Reader, slug, sourceURL string) (Manifest, error)

	Create(db prefixer.Prefixer) error
	Update(db prefixer.Prefixer) error
	Delete(db prefixer.Prefixer) error

	AppType() AppType
	Permissions() permissions.Set
	Source() string
	Version() string
	SetAvailableVersion(version string)
	Slug() string
	State() State
	LastUpdate() time.Time
	Terms() Terms

	SetError(err error)
	Error() error

	SetSource(src *url.URL)
	SetState(state State)
	SetVersion(version string)
}

// GetBySlug returns an app manifest identified by its slug
func GetBySlug(db prefixer.Prefixer, slug string, appType AppType) (Manifest, error) {
	var man Manifest
	var err error
	switch appType {
	case Webapp:
		man, err = GetWebappBySlug(db, slug)
	case Konnector:
		man, err = GetKonnectorBySlug(db, slug)
	}
	if err != nil {
		return nil, err
	}
	return man, nil
}

func routeMatches(path, ctx []string) bool {
	for i, part := range ctx {
		if path[i] != part {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package ui

import (
	"net/http"
	"strings"

	"github.com/gorilla/mux"
	"github.com/rancher/apiserver/pkg/parse"
	"github.com/rancher/rancher/pkg/cacerts"
	v3 "github.com/rancher/rancher/pkg/generated/controllers/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/settings"
	"github.com/rancher/wrangler/pkg/slice"
	"k8s.io/apiserver/pkg/endpoints/request"
)

func New(prefs v3.PreferenceCache, clusterRegistrationTokenCache v3.ClusterRegistrationTokenCache) http.Handler {
	router := mux.NewRouter()
	router.UseEncodedPath()

	router.Handle("/", PreferredIndex(prefs))
	router.Handle("/cacerts", cacerts.Handler(clusterRegistrationTokenCache))
	router.Handle("/asset-manifest.json", ember.ServeAsset())
	router.Handle("/crossdomain.xml", ember.ServeAsset())
	router.Handle("/dashboard", http.RedirectHandler("/dashboard/", http.StatusFound))
	router.Handle("/dashboard/", vue.IndexFile())
	router.Handle("/humans.txt", ember.ServeAsset())
	router.Handle("/index.txt", ember.ServeAsset())
	router.Handle("/robots.txt", ember.ServeAsset())
	router.Handle("/VERSION.txt", ember.ServeAsset())
	router.Handle("/favicon.png", vue.ServeFaviconDashboard())
	router.Handle("/favicon.ico", vue.ServeFaviconDashboard())
	router.Path("/verify-auth-azure").Queries("state", "{state}").HandlerFunc(redirectAuth)
	router.Path("/verify-auth").Queries("state", "{state}").HandlerFunc(redirectAuth)
	router.PathPrefix("/api-ui").Handler(ember.ServeAsset())
	router.PathPrefix("/assets/rancher-ui-driver-linode").Handler(emberAlwaysOffline.ServeAsset())
	router.PathPrefix("/assets").Handler(ember.ServeAsset())
	router.PathPrefix("/dashboard/").Handler(vue.IndexFileOnNotFound())
	router.PathPrefix("/ember-fetch").Handler(ember.ServeAsset())
	router.PathPrefix("/engines-dist").Handler(ember.ServeAsset())
	router.PathPrefix("/static").Handler(ember.ServeAsset())
	router.PathPrefix("/translations").Handler(ember.ServeAsset())
	router.NotFoundHandler = emberIndexUnlessAPI()

	return router
}

func emberIndexUnlessAPI() http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		if parse.IsBrowser(req, true) {
			emberIndex.ServeHTTP(rw, req)
		} else {
			http.NotFound(rw, req)
		}
	})
}

func PreferredIndex(prefs v3.PreferenceCache) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		user, ok := request.UserFrom(req.Context())
		if !ok || !slice.ContainsString(user.GetGroups(), "system:authenticated") {
			serveIndexFromSetting(rw, req, settings.UIPreferred.Get())
			return
		}

		pref, err := prefs.Get(user.GetName(), "landing")
		if err == nil && pref.Value != "" {
			serveIndexFromSetting(rw, req, pref.Value)
			return
		}

		serveIndexFromSetting(rw, req, settings.UIDefaultLanding.Get())
	})
}

func serveIndexFromSetting(rw http.ResponseWriter, req *http.Request, setting string) {
	if strings.Contains(setting, "vue") {
		http.Redirect(rw, req, "/dashboard/", http.StatusFound)
	} else {
		emberIndex.ServeHTTP(rw, req)
	}
}
<commit_msg>Don't check user perference or settings for index anymore<commit_after>package ui

import (
	"net/http"

	"github.com/gorilla/mux"
	"github.com/rancher/apiserver/pkg/parse"
	"github.com/rancher/rancher/pkg/cacerts"
	v3 "github.com/rancher/rancher/pkg/generated/controllers/management.cattle.io/v3"
)

func New(_ v3.PreferenceCache, clusterRegistrationTokenCache v3.ClusterRegistrationTokenCache) http.Handler {
	router := mux.NewRouter()
	router.UseEncodedPath()

	router.Handle("/", PreferredIndex())
	router.Handle("/cacerts", cacerts.Handler(clusterRegistrationTokenCache))
	router.Handle("/asset-manifest.json", ember.ServeAsset())
	router.Handle("/crossdomain.xml", ember.ServeAsset())
	router.Handle("/dashboard", http.RedirectHandler("/dashboard/", http.StatusFound))
	router.Handle("/dashboard/", vue.IndexFile())
	router.Handle("/humans.txt", ember.ServeAsset())
	router.Handle("/index.txt", ember.ServeAsset())
	router.Handle("/robots.txt", ember.ServeAsset())
	router.Handle("/VERSION.txt", ember.ServeAsset())
	router.Handle("/favicon.png", vue.ServeFaviconDashboard())
	router.Handle("/favicon.ico", vue.ServeFaviconDashboard())
	router.Path("/verify-auth-azure").Queries("state", "{state}").HandlerFunc(redirectAuth)
	router.Path("/verify-auth").Queries("state", "{state}").HandlerFunc(redirectAuth)
	router.PathPrefix("/api-ui").Handler(ember.ServeAsset())
	router.PathPrefix("/assets/rancher-ui-driver-linode").Handler(emberAlwaysOffline.ServeAsset())
	router.PathPrefix("/assets").Handler(ember.ServeAsset())
	router.PathPrefix("/dashboard/").Handler(vue.IndexFileOnNotFound())
	router.PathPrefix("/ember-fetch").Handler(ember.ServeAsset())
	router.PathPrefix("/engines-dist").Handler(ember.ServeAsset())
	router.PathPrefix("/static").Handler(ember.ServeAsset())
	router.PathPrefix("/translations").Handler(ember.ServeAsset())
	router.NotFoundHandler = emberIndexUnlessAPI()

	return router
}

func emberIndexUnlessAPI() http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		if parse.IsBrowser(req, true) {
			emberIndex.ServeHTTP(rw, req)
		} else {
			http.NotFound(rw, req)
		}
	})
}

func PreferredIndex() http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		http.Redirect(rw, req, "/dashboard/", http.StatusFound)
	})
}
<|endoftext|>