<commit_before>package storage

import (
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
func ParseIDMapping(UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap string) (*IDMappingOptions, error) {
	options := IDMappingOptions{
		HostUIDMapping: true,
		HostGIDMapping: true,
	}
	if subGIDMap == "" && subUIDMap != "" {
		subGIDMap = subUIDMap
	}
	if subUIDMap == "" && subGIDMap != "" {
		subUIDMap = subGIDMap
	}
	if len(GIDMapSlice) == 0 && len(UIDMapSlice) != 0 {
		GIDMapSlice = UIDMapSlice
	}
	if len(UIDMapSlice) == 0 && len(GIDMapSlice) != 0 {
		UIDMapSlice = GIDMapSlice
	}
	if len(UIDMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 {
		UIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())}
	}
	if len(GIDMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 {
		GIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())}
	}

	if subUIDMap != "" && subGIDMap != "" {
		mappings, err := idtools.NewIDMappings(subUIDMap, subGIDMap)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to create NewIDMappings for uidmap=%s gidmap=%s", subUIDMap, subGIDMap)
		}
		options.UIDMap = mappings.UIDs()
		options.GIDMap = mappings.GIDs()
	}
	parsedUIDMap, err := idtools.ParseIDMap(UIDMapSlice, "UID")
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create ParseUIDMap UID=%s", UIDMapSlice)
	}
	parsedGIDMap, err := idtools.ParseIDMap(GIDMapSlice, "GID")
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create ParseGIDMap GID=%s", UIDMapSlice)
	}
	options.UIDMap = append(options.UIDMap, parsedUIDMap...)
	options.GIDMap = append(options.GIDMap, parsedGIDMap...)
	if len(options.UIDMap) > 0 {
		options.HostUIDMapping = false
	}
	if len(options.GIDMap) > 0 {
		options.HostGIDMapping = false
	}
	return &options, nil
}

// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir(rootlessUid int) (string, error) {
	runtimeDir := os.Getenv("XDG_RUNTIME_DIR")

	if runtimeDir != "" {
		return runtimeDir, nil
	}
	tmpDir := fmt.Sprintf("/run/user/%d", rootlessUid)
	st, err := system.Stat(tmpDir)
	if err == nil && int(st.UID()) == os.Getuid() && st.Mode()&0700 == 0700 && st.Mode()&0066 == 0000 {
		return tmpDir, nil
	}
	tmpDir = fmt.Sprintf("%s/%d", os.TempDir(), rootlessUid)
	if err := os.MkdirAll(tmpDir, 0700); err != nil {
		logrus.Errorf("failed to create %s: %v", tmpDir, err)
	} else {
		return tmpDir, nil
	}
	home, err := homeDir()
	if err != nil {
		return "", errors.Wrapf(err, "neither XDG_RUNTIME_DIR nor HOME was set non-empty")
	}
	resolvedHome, err := filepath.EvalSymlinks(home)
	if err != nil {
		return "", errors.Wrapf(err, "cannot resolve %s", home)
	}
	return filepath.Join(resolvedHome, "rundir"), nil
}

// getRootlessDirInfo returns the parent path of where the storage for containers and
// volumes will be in rootless mode
func getRootlessDirInfo(rootlessUid int) (string, string, error) {
	rootlessRuntime, err := GetRootlessRuntimeDir(rootlessUid)
	if err != nil {
		return "", "", err
	}

	dataDir := os.Getenv("XDG_DATA_HOME")
	if dataDir == "" {
		home, err := homeDir()
		if err != nil {
			return "", "", errors.Wrapf(err, "neither XDG_DATA_HOME nor HOME was set non-empty")
		}
		// runc doesn't like symlinks in the rootfs path, and at least
		// on CoreOS /home is a symlink to /var/home, so resolve any symlink.
		resolvedHome, err := filepath.EvalSymlinks(home)
		if err != nil {
			return "", "", errors.Wrapf(err, "cannot resolve %s", home)
		}
		dataDir = filepath.Join(resolvedHome, ".local", "share")
	}
	return dataDir, rootlessRuntime, nil
}

// getRootlessStorageOpts returns the storage opts for containers running as non root
func getRootlessStorageOpts(rootlessUid int) (StoreOptions, error) {
	var opts StoreOptions

	dataDir, rootlessRuntime, err := getRootlessDirInfo(rootlessUid)
	if err != nil {
		return opts, err
	}
	opts.RunRoot = rootlessRuntime
	opts.GraphRoot = filepath.Join(dataDir, "containers", "storage")
	if path, err := exec.LookPath("fuse-overlayfs"); err == nil {
		opts.GraphDriverName = "overlay"
		opts.GraphDriverOptions = []string{fmt.Sprintf("overlay.mount_program=%s", path)}
	} else {
		opts.GraphDriverName = "vfs"
	}
	return opts, nil
}

type tomlOptionsConfig struct {
	MountProgram string `toml:"mount_program"`
}

func getTomlStorage(storeOptions *StoreOptions) *tomlConfig {
	config := new(tomlConfig)

	config.Storage.Driver = storeOptions.GraphDriverName
	config.Storage.RunRoot = storeOptions.RunRoot
	config.Storage.GraphRoot = storeOptions.GraphRoot
	for _, i := range storeOptions.GraphDriverOptions {
		s := strings.Split(i, "=")
		if s[0] == "overlay.mount_program" {
			config.Storage.Options.MountProgram = s[1]
		}
	}

	return config
}

func getRootlessUID() int {
	uidEnv := os.Getenv("_CONTAINERS_ROOTLESS_UID")
	if uidEnv != "" {
		u, _ := strconv.Atoi(uidEnv)
		return u
	}
	return os.Geteuid()
}

// DefaultStoreOptionsAutoDetectUID returns the default storage ops for containers
func DefaultStoreOptionsAutoDetectUID() (StoreOptions, error) {
	uid := getRootlessUID()
	return DefaultStoreOptions(uid != 0, uid)
}

// DefaultStoreOptions returns the default storage ops for containers
func DefaultStoreOptions(rootless bool, rootlessUid int) (StoreOptions, error) {
	var (
		defaultRootlessRunRoot   string
		defaultRootlessGraphRoot string
		err                      error
	)
	storageOpts := defaultStoreOptions
	if rootless && rootlessUid != 0 {
		storageOpts, err = getRootlessStorageOpts(rootlessUid)
		if err != nil {
			return storageOpts, err
		}
	}

	storageConf, err := DefaultConfigFile(rootless && rootlessUid != 0)
	if err != nil {
		return storageOpts, err
	}
	if _, err = os.Stat(storageConf); err == nil {
		defaultRootlessRunRoot = storageOpts.RunRoot
		defaultRootlessGraphRoot = storageOpts.GraphRoot
		storageOpts = StoreOptions{}
		ReloadConfigurationFile(storageConf, &storageOpts)
	}

	if !os.IsNotExist(err) {
		return storageOpts, errors.Wrapf(err, "cannot stat %s", storageConf)
	}

	if rootless && rootlessUid != 0 {
		if err == nil {
			// If the file did not specify a graphroot or runroot,
			// set sane defaults so we don't try and use root-owned
			// directories
			if storageOpts.RunRoot == "" {
				storageOpts.RunRoot = defaultRootlessRunRoot
			}
			if storageOpts.GraphRoot == "" {
				storageOpts.GraphRoot = defaultRootlessGraphRoot
			}
		} else {
			if err := os.MkdirAll(filepath.Dir(storageConf), 0755); err != nil {
				return storageOpts, errors.Wrapf(err, "cannot make directory %s", filepath.Dir(storageConf))
			}
			file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
			if err != nil {
				return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf)
			}

			tomlConfiguration := getTomlStorage(&storageOpts)
			defer file.Close()
			enc := toml.NewEncoder(file)
			if err := enc.Encode(tomlConfiguration); err != nil {
				os.Remove(storageConf)

				return storageOpts, errors.Wrapf(err, "failed to encode %s", storageConf)
			}
		}
	}
	return storageOpts, nil
}

func homeDir() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		usr, err := user.Current()
		if err != nil {
			return "", errors.Wrapf(err, "neither XDG_RUNTIME_DIR nor HOME was set non-empty")
		}
		home = usr.HomeDir
	}
	return home, nil
}
<commit_msg>utils: fix check for missing conf file<commit_after>package storage

import (
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/containers/storage/pkg/idtools"
	"github.com/containers/storage/pkg/system"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping
func ParseIDMapping(UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap string) (*IDMappingOptions, error) {
	options := IDMappingOptions{
		HostUIDMapping: true,
		HostGIDMapping: true,
	}
	if subGIDMap == "" && subUIDMap != "" {
		subGIDMap = subUIDMap
	}
	if subUIDMap == "" && subGIDMap != "" {
		subUIDMap = subGIDMap
	}
	if len(GIDMapSlice) == 0 && len(UIDMapSlice) != 0 {
		GIDMapSlice = UIDMapSlice
	}
	if len(UIDMapSlice) == 0 && len(GIDMapSlice) != 0 {
		UIDMapSlice = GIDMapSlice
	}
	if len(UIDMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 {
		UIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())}
	}
	if len(GIDMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 {
		GIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())}
	}

	if subUIDMap != "" && subGIDMap != "" {
		mappings, err := idtools.NewIDMappings(subUIDMap, subGIDMap)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to create NewIDMappings for uidmap=%s gidmap=%s", subUIDMap, subGIDMap)
		}
		options.UIDMap = mappings.UIDs()
		options.GIDMap = mappings.GIDs()
	}
	parsedUIDMap, err := idtools.ParseIDMap(UIDMapSlice, "UID")
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create ParseUIDMap UID=%s", UIDMapSlice)
	}
	parsedGIDMap, err := idtools.ParseIDMap(GIDMapSlice, "GID")
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create ParseGIDMap GID=%s", UIDMapSlice)
	}
	options.UIDMap = append(options.UIDMap, parsedUIDMap...)
	options.GIDMap = append(options.GIDMap, parsedGIDMap...)
	if len(options.UIDMap) > 0 {
		options.HostUIDMapping = false
	}
	if len(options.GIDMap) > 0 {
		options.HostGIDMapping = false
	}
	return &options, nil
}

// GetRootlessRuntimeDir returns the runtime directory when running as non root
func GetRootlessRuntimeDir(rootlessUid int) (string, error) {
	runtimeDir := os.Getenv("XDG_RUNTIME_DIR")

	if runtimeDir != "" {
		return runtimeDir, nil
	}
	tmpDir := fmt.Sprintf("/run/user/%d", rootlessUid)
	st, err := system.Stat(tmpDir)
	if err == nil && int(st.UID()) == os.Getuid() && st.Mode()&0700 == 0700 && st.Mode()&0066 == 0000 {
		return tmpDir, nil
	}
	tmpDir = fmt.Sprintf("%s/%d", os.TempDir(), rootlessUid)
	if err := os.MkdirAll(tmpDir, 0700); err != nil {
		logrus.Errorf("failed to create %s: %v", tmpDir, err)
	} else {
		return tmpDir, nil
	}
	home, err := homeDir()
	if err != nil {
		return "", errors.Wrapf(err, "neither XDG_RUNTIME_DIR nor HOME was set non-empty")
	}
	resolvedHome, err := filepath.EvalSymlinks(home)
	if err != nil {
		return "", errors.Wrapf(err, "cannot resolve %s", home)
	}
	return filepath.Join(resolvedHome, "rundir"), nil
}

// getRootlessDirInfo returns the parent path of where the storage for containers and
// volumes will be in rootless mode
func getRootlessDirInfo(rootlessUid int) (string, string, error) {
	rootlessRuntime, err := GetRootlessRuntimeDir(rootlessUid)
	if err != nil {
		return "", "", err
	}

	dataDir := os.Getenv("XDG_DATA_HOME")
	if dataDir == "" {
		home, err := homeDir()
		if err != nil {
			return "", "", errors.Wrapf(err, "neither XDG_DATA_HOME nor HOME was set non-empty")
		}
		// runc doesn't like symlinks in the rootfs path, and at least
		// on CoreOS /home is a symlink to /var/home, so resolve any symlink.
		resolvedHome, err := filepath.EvalSymlinks(home)
		if err != nil {
			return "", "", errors.Wrapf(err, "cannot resolve %s", home)
		}
		dataDir = filepath.Join(resolvedHome, ".local", "share")
	}
	return dataDir, rootlessRuntime, nil
}

// getRootlessStorageOpts returns the storage opts for containers running as non root
func getRootlessStorageOpts(rootlessUid int) (StoreOptions, error) {
	var opts StoreOptions

	dataDir, rootlessRuntime, err := getRootlessDirInfo(rootlessUid)
	if err != nil {
		return opts, err
	}
	opts.RunRoot = rootlessRuntime
	opts.GraphRoot = filepath.Join(dataDir, "containers", "storage")
	if path, err := exec.LookPath("fuse-overlayfs"); err == nil {
		opts.GraphDriverName = "overlay"
		opts.GraphDriverOptions = []string{fmt.Sprintf("overlay.mount_program=%s", path)}
	} else {
		opts.GraphDriverName = "vfs"
	}
	return opts, nil
}

type tomlOptionsConfig struct {
	MountProgram string `toml:"mount_program"`
}

func getTomlStorage(storeOptions *StoreOptions) *tomlConfig {
	config := new(tomlConfig)

	config.Storage.Driver = storeOptions.GraphDriverName
	config.Storage.RunRoot = storeOptions.RunRoot
	config.Storage.GraphRoot = storeOptions.GraphRoot
	for _, i := range storeOptions.GraphDriverOptions {
		s := strings.Split(i, "=")
		if s[0] == "overlay.mount_program" {
			config.Storage.Options.MountProgram = s[1]
		}
	}

	return config
}

func getRootlessUID() int {
	uidEnv := os.Getenv("_CONTAINERS_ROOTLESS_UID")
	if uidEnv != "" {
		u, _ := strconv.Atoi(uidEnv)
		return u
	}
	return os.Geteuid()
}

// DefaultStoreOptionsAutoDetectUID returns the default storage ops for containers
func DefaultStoreOptionsAutoDetectUID() (StoreOptions, error) {
	uid := getRootlessUID()
	return DefaultStoreOptions(uid != 0, uid)
}

// DefaultStoreOptions returns the default storage ops for containers
func DefaultStoreOptions(rootless bool, rootlessUid int) (StoreOptions, error) {
	var (
		defaultRootlessRunRoot   string
		defaultRootlessGraphRoot string
		err                      error
	)
	storageOpts := defaultStoreOptions
	if rootless && rootlessUid != 0 {
		storageOpts, err = getRootlessStorageOpts(rootlessUid)
		if err != nil {
			return storageOpts, err
		}
	}

	storageConf, err := DefaultConfigFile(rootless && rootlessUid != 0)
	if err != nil {
		return storageOpts, err
	}
	_, err = os.Stat(storageConf)
	if err != nil && !os.IsNotExist(err) {
		return storageOpts, errors.Wrapf(err, "cannot stat %s", storageConf)
	}
	if err == nil {
		defaultRootlessRunRoot = storageOpts.RunRoot
		defaultRootlessGraphRoot = storageOpts.GraphRoot
		storageOpts = StoreOptions{}
		ReloadConfigurationFile(storageConf, &storageOpts)
	}

	if rootless && rootlessUid != 0 {
		if err == nil {
			// If the file did not specify a graphroot or runroot,
			// set sane defaults so we don't try and use root-owned
			// directories
			if storageOpts.RunRoot == "" {
				storageOpts.RunRoot = defaultRootlessRunRoot
			}
			if storageOpts.GraphRoot == "" {
				storageOpts.GraphRoot = defaultRootlessGraphRoot
			}
		} else {
			if err := os.MkdirAll(filepath.Dir(storageConf), 0755); err != nil {
				return storageOpts, errors.Wrapf(err, "cannot make directory %s", filepath.Dir(storageConf))
			}
			file, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
			if err != nil {
				return storageOpts, errors.Wrapf(err, "cannot open %s", storageConf)
			}

			tomlConfiguration := getTomlStorage(&storageOpts)
			defer file.Close()
			enc := toml.NewEncoder(file)
			if err := enc.Encode(tomlConfiguration); err != nil {
				os.Remove(storageConf)

				return storageOpts, errors.Wrapf(err, "failed to encode %s", storageConf)
			}
		}
	}
	return storageOpts, nil
}

func homeDir() (string, error) {
	home := os.Getenv("HOME")
	if home == "" {
		usr, err := user.Current()
		if err != nil {
			return "", errors.Wrapf(err, "neither XDG_RUNTIME_DIR nor HOME was set non-empty")
		}
		home = usr.HomeDir
	}
	return home, nil
}
<|endoftext|>


<commit_before>package models

import (
	"github.com/jinzhu/gorm"
	"github.com/qor/accessibility/hyperlink"
)

type Article struct {
	gorm.Model
	Author   User
	AuthorID uint
	Title    string
	Content  string `gorm:"type:text"`
	FromURL  hyperlink.HyperLink
}
<commit_msg>Add publish Version, Schedule, Visible to Blog<commit_after>package models

import (
	"github.com/jinzhu/gorm"
	"github.com/qor/accessibility/hyperlink"
	"github.com/qor/publish2"
)

type Article struct {
	gorm.Model
	Author   User
	AuthorID uint
	Title    string
	Content  string `gorm:"type:text"`
	FromURL  hyperlink.HyperLink
	publish2.Version
	publish2.Schedule
	publish2.Visible
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium 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 global

import (
	"fmt"
	"reflect"
	"sort"

	"v.io/v23/context"
	"v.io/v23/discovery"
	"v.io/v23/naming"

	idiscovery "v.io/x/ref/lib/discovery"
)

func (d *gdiscovery) Scan(ctx *context.T, query string) (<-chan discovery.Update, error) {
	matcher, err := idiscovery.NewMatcher(ctx, query)
	if err != nil {
		return nil, err
	}

	updateCh := make(chan discovery.Update, 10)
	go func() {
		defer close(updateCh)

		var prevFound map[discovery.AdId]*idiscovery.AdInfo
		for {
			found, err := d.doScan(ctx, matcher)
			if found == nil {
				if err != nil {
					ctx.Error(err)
				}
			} else {
				sendUpdates(ctx, prevFound, found, updateCh)
				prevFound = found
			}

			select {
			case <-d.clock.After(d.scanInterval):
			case <-ctx.Done():
				return
			}
		}
	}()
	return updateCh, nil
}

func (d *gdiscovery) doScan(ctx *context.T, matcher idiscovery.Matcher) (map[discovery.AdId]*idiscovery.AdInfo, error) {
	scanCh, err := d.ns.Glob(ctx, generateGlobQuery(matcher))
	if err != nil {
		return nil, err
	}
	defer func() {
		for range scanCh {
		}
	}()

	found := make(map[discovery.AdId]*idiscovery.AdInfo)
	for {
		select {
		case glob, ok := <-scanCh:
			if !ok {
				return found, nil
			}
			adinfo, err := convToAdInfo(glob)
			if err != nil {
				ctx.Error(err)
				continue
			}
			// Since mount operations are not atomic, we may not have addresses yet.
			// Ignore it. It will be re-scanned in the next cycle.
			if len(adinfo.Ad.Addresses) == 0 {
				continue
			}
			// Filter out advertisements from the same discovery instance.
			if d.hasAd(&adinfo.Ad) {
				continue
			}
			matched, err := matcher.Match(&adinfo.Ad)
			if err != nil {
				ctx.Error(err)
				continue
			}
			if !matched {
				continue
			}
			found[adinfo.Ad.Id] = adinfo
		case <-ctx.Done():
			return nil, nil
		}
	}
}

func generateGlobQuery(matcher idiscovery.Matcher) string {
	// The suffixes are of the form "id/interfaceName/timestamp/attrs" so we need
	// to replace wildcards in our query with values based on the query matcher.
	id, interfaceName, timestamp, attrs := "*", "*", "*", "*"
	// Currently we support query by id or interfaceName.
	if targetKey := matcher.TargetKey(); targetKey != "" {
		id = targetKey
	}
	if targetInterface := matcher.TargetInterfaceName(); targetInterface != "" {
		interfaceName = targetInterface
	}
	return naming.Join(id, interfaceName, timestamp, attrs)
}

func (d *gdiscovery) hasAd(ad *discovery.Advertisement) bool {
	d.mu.Lock()
	_, ok := d.ads[ad.Id]
	d.mu.Unlock()
	return ok
}

func convToAdInfo(glob naming.GlobReply) (*idiscovery.AdInfo, error) {
	switch g := glob.(type) {
	case *naming.GlobReplyEntry:
		ad, timestampNs, err := decodeAdFromSuffix(g.Value.Name)
		if err != nil {
			return nil, err
		}
		addrs := make([]string, 0, len(g.Value.Servers))
		for _, server := range g.Value.Servers {
			addrs = append(addrs, server.Server)
		}
		// We sort the addresses to avoid false updates.
		sort.Strings(addrs)
		ad.Addresses = addrs
		return &idiscovery.AdInfo{Ad: *ad, TimestampNs: timestampNs}, nil
	case *naming.GlobReplyError:
		return nil, fmt.Errorf("glob error on %s: %v", g.Value.Name, g.Value.Error)
	default:
		return nil, fmt.Errorf("unexpected glob reply %v", g)
	}
}

func sendUpdates(ctx *context.T, prevFound, found map[discovery.AdId]*idiscovery.AdInfo, updateCh chan<- discovery.Update) {
	for id, adinfo := range found {
		var updates []discovery.Update
		if prev := prevFound[id]; prev == nil {
			updates = []discovery.Update{idiscovery.NewUpdate(adinfo)}
		} else {
			if !reflect.DeepEqual(prev.Ad, adinfo.Ad) {
				prev.Lost = true
				updates = []discovery.Update{
					idiscovery.NewUpdate(prev),
					idiscovery.NewUpdate(adinfo),
				}
			}
			delete(prevFound, id)
		}
		for _, update := range updates {
			select {
			case updateCh <- update:
			case <-ctx.Done():
				return
			}
		}
	}

	for _, prev := range prevFound {
		prev.Lost = true
		update := idiscovery.NewUpdate(prev)
		select {
		case updateCh <- update:
		case <-ctx.Done():
			return
		}
	}
}
<commit_msg>lib/discovery/global: fix query on ifc name<commit_after>// Copyright 2015 The Vanadium 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 global

import (
	"fmt"
	"reflect"
	"sort"

	"v.io/v23/context"
	"v.io/v23/discovery"
	"v.io/v23/naming"

	idiscovery "v.io/x/ref/lib/discovery"
)

func (d *gdiscovery) Scan(ctx *context.T, query string) (<-chan discovery.Update, error) {
	matcher, err := idiscovery.NewMatcher(ctx, query)
	if err != nil {
		return nil, err
	}

	updateCh := make(chan discovery.Update, 10)
	go func() {
		defer close(updateCh)

		var prevFound map[discovery.AdId]*idiscovery.AdInfo
		for {
			found, err := d.doScan(ctx, matcher)
			if found == nil {
				if err != nil {
					ctx.Error(err)
				}
			} else {
				sendUpdates(ctx, prevFound, found, updateCh)
				prevFound = found
			}

			select {
			case <-d.clock.After(d.scanInterval):
			case <-ctx.Done():
				return
			}
		}
	}()
	return updateCh, nil
}

func (d *gdiscovery) doScan(ctx *context.T, matcher idiscovery.Matcher) (map[discovery.AdId]*idiscovery.AdInfo, error) {
	scanCh, err := d.ns.Glob(ctx, generateGlobQuery(matcher))
	if err != nil {
		return nil, err
	}
	defer func() {
		for range scanCh {
		}
	}()

	found := make(map[discovery.AdId]*idiscovery.AdInfo)
	for {
		select {
		case glob, ok := <-scanCh:
			if !ok {
				return found, nil
			}
			adinfo, err := convToAdInfo(glob)
			if err != nil {
				ctx.Error(err)
				continue
			}
			// Since mount operations are not atomic, we may not have addresses yet.
			// Ignore it. It will be re-scanned in the next cycle.
			if len(adinfo.Ad.Addresses) == 0 {
				continue
			}
			// Filter out advertisements from the same discovery instance.
			if d.hasAd(&adinfo.Ad) {
				continue
			}
			matched, err := matcher.Match(&adinfo.Ad)
			if err != nil {
				ctx.Error(err)
				continue
			}
			if !matched {
				continue
			}
			found[adinfo.Ad.Id] = adinfo
		case <-ctx.Done():
			return nil, nil
		}
	}
}

func generateGlobQuery(matcher idiscovery.Matcher) string {
	// The suffixes are of the form "id/interfaceName/timestamp/attrs" so we need
	// to replace wildcards in our query with values based on the query matcher.
	id, interfaceName, timestamp, attrs := "*", "*", "*", "*"
	// Currently we support query by id or interfaceName.
	if targetKey := matcher.TargetKey(); targetKey != "" {
		id = targetKey
	}
	if targetInterface := matcher.TargetInterfaceName(); targetInterface != "" {
		interfaceName = naming.EncodeAsNameElement(targetInterface)
	}
	return naming.Join(id, interfaceName, timestamp, attrs)
}

func (d *gdiscovery) hasAd(ad *discovery.Advertisement) bool {
	d.mu.Lock()
	_, ok := d.ads[ad.Id]
	d.mu.Unlock()
	return ok
}

func convToAdInfo(glob naming.GlobReply) (*idiscovery.AdInfo, error) {
	switch g := glob.(type) {
	case *naming.GlobReplyEntry:
		ad, timestampNs, err := decodeAdFromSuffix(g.Value.Name)
		if err != nil {
			return nil, err
		}
		addrs := make([]string, 0, len(g.Value.Servers))
		for _, server := range g.Value.Servers {
			addrs = append(addrs, server.Server)
		}
		// We sort the addresses to avoid false updates.
		sort.Strings(addrs)
		ad.Addresses = addrs
		return &idiscovery.AdInfo{Ad: *ad, TimestampNs: timestampNs}, nil
	case *naming.GlobReplyError:
		return nil, fmt.Errorf("glob error on %s: %v", g.Value.Name, g.Value.Error)
	default:
		return nil, fmt.Errorf("unexpected glob reply %v", g)
	}
}

func sendUpdates(ctx *context.T, prevFound, found map[discovery.AdId]*idiscovery.AdInfo, updateCh chan<- discovery.Update) {
	for id, adinfo := range found {
		var updates []discovery.Update
		if prev := prevFound[id]; prev == nil {
			updates = []discovery.Update{idiscovery.NewUpdate(adinfo)}
		} else {
			if !reflect.DeepEqual(prev.Ad, adinfo.Ad) {
				prev.Lost = true
				updates = []discovery.Update{
					idiscovery.NewUpdate(prev),
					idiscovery.NewUpdate(adinfo),
				}
			}
			delete(prevFound, id)
		}
		for _, update := range updates {
			select {
			case updateCh <- update:
			case <-ctx.Done():
				return
			}
		}
	}

	for _, prev := range prevFound {
		prev.Lost = true
		update := idiscovery.NewUpdate(prev)
		select {
		case updateCh <- update:
		case <-ctx.Done():
			return
		}
	}
}
<|endoftext|>


<commit_before>package rest

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"
	"gopkg.in/inconshreveable/log15.v2"

	"github.com/nsec/askgod/api"
)

func (r *rest) getTeamFlags(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	flags, err := r.db.GetTeamFlags(team.ID)
	if err != nil {
		logger.Error("Failed to query the flag list", log15.Ctx{"error": err, "teamid": team.ID})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flags, writer, request)
}

func (r *rest) getTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	flag, err := r.db.GetTeamFlag(team.ID, id)
	if err != nil {
		logger.Error("Failed to query the flag", log15.Ctx{"error": err, "teamid": team.ID, "flagid": id})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flag, writer, request)
}

func (r *rest) updateTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Decode the provided JSON input
	flag := api.FlagPut{}
	err = json.NewDecoder(request.Body).Decode(&flag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	err = r.db.UpdateTeamFlag(team.ID, id, flag)
	if err != nil {
		logger.Error("Failed to update the flag", log15.Ctx{"error": err, "teamid": team.ID, "flagid": id})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}
}

func (r *rest) submitTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Decode the provided JSON input
	flag := api.FlagPost{}
	err := json.NewDecoder(request.Body).Decode(&flag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Check that the team is configured
	if team.Name == "" || team.Country == "" {
		logger.Debug("Unconfigured team tried to submit flag", log15.Ctx{"teamid": team.ID})
		r.errorResponse(400, "Team name and country are required to participate", writer, request)
		return
	}

	// Get all the flags for the team
	result, adminFlag, err := r.db.SubmitTeamFlag(team.ID, flag)
	if err == sql.ErrNoRows {
		eventSend("flags", api.EventFlag{Team: *team, Input: flag.Flag, Result: "invalid"})
		logger.Info("Invalid flag submitted", log15.Ctx{"teamid": team.ID, "flag": flag.Flag})
		r.errorResponse(400, "Invalid flag submitted", writer, request)
		return
	} else if err == os.ErrExist {
		eventSend("flags", api.EventFlag{Team: *team, Flag: adminFlag, Input: flag.Flag, Value: 0, Result: "duplicate"})
		logger.Info("The flag was already submitted", log15.Ctx{"teamid": team.ID, "flag": flag.Flag})
		r.errorResponse(400, "The flag was already submitted", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to submit the flag", log15.Ctx{"error": err, "teamid": team.ID})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}
	eventSend("flags", api.EventFlag{Team: *team, Flag: adminFlag, Input: flag.Flag, Value: result.Value, Result: "valid"})

	logger.Info("Correct flag submitted", log15.Ctx{"teamid": team.ID, "flagid": result.ID, "value": result.Value, "flag": flag.Flag})
	r.jsonResponse(result, writer, request)
}

func (r *rest) adminGetFlags(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Get all the flags from the database
	flags, err := r.db.GetFlags()
	if err != nil {
		logger.Error("Failed to query the flag list", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flags, writer, request)
}

func (r *rest) adminCreateFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Decode the provided JSON input
	newFlag := api.AdminFlagPost{}
	err := json.NewDecoder(request.Body).Decode(&newFlag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Attempt to update the database
	id, err := r.db.CreateFlag(newFlag)
	if err != nil {
		logger.Error("Failed to create the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("New flag defined", log15.Ctx{"id": id, "flag": newFlag.Flag, "value": newFlag.Value})
}

func (r *rest) adminGetFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Attempt to get the DB record
	flag, err := r.db.GetFlag(id)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flag, writer, request)
}

func (r *rest) adminUpdateFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Decode the provided JSON input
	newFlag := api.AdminFlagPut{}
	err = json.NewDecoder(request.Body).Decode(&newFlag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Attempt to update the database
	err = r.db.UpdateFlag(id, newFlag)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to update the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("Flag updated", log15.Ctx{"id": id, "flag": newFlag.Flag, "value": newFlag.Value})
}

func (r *rest) adminDeleteFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Attempt to get the DB record
	err = r.db.DeleteFlag(id)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to delete the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("Flag deleted", log15.Ctx{"id": id})
}
<commit_msg>askgod-server: Implement read-only mode<commit_after>package rest

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"github.com/gorilla/mux"
	"gopkg.in/inconshreveable/log15.v2"

	"github.com/nsec/askgod/api"
)

func (r *rest) getTeamFlags(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	flags, err := r.db.GetTeamFlags(team.ID)
	if err != nil {
		logger.Error("Failed to query the flag list", log15.Ctx{"error": err, "teamid": team.ID})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flags, writer, request)
}

func (r *rest) getTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	flag, err := r.db.GetTeamFlag(team.ID, id)
	if err != nil {
		logger.Error("Failed to query the flag", log15.Ctx{"error": err, "teamid": team.ID, "flagid": id})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flag, writer, request)
}

func (r *rest) updateTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Decode the provided JSON input
	flag := api.FlagPut{}
	err = json.NewDecoder(request.Body).Decode(&flag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Get all the flags for the team
	err = r.db.UpdateTeamFlag(team.ID, id, flag)
	if err != nil {
		logger.Error("Failed to update the flag", log15.Ctx{"error": err, "teamid": team.ID, "flagid": id})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}
}

func (r *rest) submitTeamFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Check if read-only
	if r.config.Scoring.ReadOnly {
		r.errorResponse(403, "Flag submission isn't allowed at this time", writer, request)
		return
	}

	// Decode the provided JSON input
	flag := api.FlagPost{}
	err := json.NewDecoder(request.Body).Decode(&flag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Extract the client IP
	ip, err := r.getIP(request)
	if err != nil {
		logger.Error("Failed to get the client's IP", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Look for a matching team
	team, err := r.db.GetTeamForIP(*ip)
	if err == sql.ErrNoRows {
		logger.Warn("No team found for IP", log15.Ctx{"ip": ip.String()})
		r.errorResponse(404, "No team found for IP", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the team", log15.Ctx{"error": err})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}

	// Check that the team is configured
	if team.Name == "" || team.Country == "" {
		logger.Debug("Unconfigured team tried to submit flag", log15.Ctx{"teamid": team.ID})
		r.errorResponse(400, "Team name and country are required to participate", writer, request)
		return
	}

	// Get all the flags for the team
	result, adminFlag, err := r.db.SubmitTeamFlag(team.ID, flag)
	if err == sql.ErrNoRows {
		eventSend("flags", api.EventFlag{Team: *team, Input: flag.Flag, Result: "invalid"})
		logger.Info("Invalid flag submitted", log15.Ctx{"teamid": team.ID, "flag": flag.Flag})
		r.errorResponse(400, "Invalid flag submitted", writer, request)
		return
	} else if err == os.ErrExist {
		eventSend("flags", api.EventFlag{Team: *team, Flag: adminFlag, Input: flag.Flag, Value: 0, Result: "duplicate"})
		logger.Info("The flag was already submitted", log15.Ctx{"teamid": team.ID, "flag": flag.Flag})
		r.errorResponse(400, "The flag was already submitted", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to submit the flag", log15.Ctx{"error": err, "teamid": team.ID})
		r.errorResponse(500, "Internal Server Error", writer, request)
		return
	}
	eventSend("flags", api.EventFlag{Team: *team, Flag: adminFlag, Input: flag.Flag, Value: result.Value, Result: "valid"})

	logger.Info("Correct flag submitted", log15.Ctx{"teamid": team.ID, "flagid": result.ID, "value": result.Value, "flag": flag.Flag})
	r.jsonResponse(result, writer, request)
}

func (r *rest) adminGetFlags(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Get all the flags from the database
	flags, err := r.db.GetFlags()
	if err != nil {
		logger.Error("Failed to query the flag list", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flags, writer, request)
}

func (r *rest) adminCreateFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	// Decode the provided JSON input
	newFlag := api.AdminFlagPost{}
	err := json.NewDecoder(request.Body).Decode(&newFlag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Attempt to update the database
	id, err := r.db.CreateFlag(newFlag)
	if err != nil {
		logger.Error("Failed to create the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("New flag defined", log15.Ctx{"id": id, "flag": newFlag.Flag, "value": newFlag.Value})
}

func (r *rest) adminGetFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Attempt to get the DB record
	flag, err := r.db.GetFlag(id)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to get the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	r.jsonResponse(flag, writer, request)
}

func (r *rest) adminUpdateFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Decode the provided JSON input
	newFlag := api.AdminFlagPut{}
	err = json.NewDecoder(request.Body).Decode(&newFlag)
	if err != nil {
		logger.Warn("Malformed JSON provided", log15.Ctx{"error": err})
		r.errorResponse(400, "Malformed JSON provided", writer, request)
		return
	}

	// Attempt to update the database
	err = r.db.UpdateFlag(id, newFlag)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to update the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("Flag updated", log15.Ctx{"id": id, "flag": newFlag.Flag, "value": newFlag.Value})
}

func (r *rest) adminDeleteFlag(writer http.ResponseWriter, request *http.Request, logger log15.Logger) {
	idVar := mux.Vars(request)["id"]

	// Convert the provided id to int
	id, err := strconv.ParseInt(idVar, 10, 64)
	if err != nil {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(400, "Invalid flag ID provided", writer, request)
		return
	}

	// Attempt to get the DB record
	err = r.db.DeleteFlag(id)
	if err == sql.ErrNoRows {
		logger.Warn("Invalid flag ID provided", log15.Ctx{"id": idVar})
		r.errorResponse(404, "Invalid flag ID provided", writer, request)
		return
	} else if err != nil {
		logger.Error("Failed to delete the flag", log15.Ctx{"error": err})
		r.errorResponse(500, fmt.Sprintf("%v", err), writer, request)
		return
	}

	logger.Info("Flag deleted", log15.Ctx{"id": id})
}
<|endoftext|>


<commit_before>package models

type Item struct {
	Title         string
	Description   string
	Tags          string // seperated by comma, should be mapped with Tag model in database
	Condition     uint8  // percentage of status after depreciation
	Status        string // ([A]vailable / [H]old / [N]ot available...will be hidden) only avabile when it is posted by registered user
	Location      string // current location, free text, can be just district
	Handover      string // ([F]ace / [D]elivery) handover method
	Delivery      string // ([P]ost / [C]ourrier) delivery method if not handover
	ContactMethod string // free text for user
	Contact       string
	Email         string // optional for user notification purpose
	Owner         uint   // owner ID if it is registered (optional subscription)
}
<commit_msg>Add listing duration to item<commit_after>package models

type Item struct {
	Title         string
	Description   string
	Tags          string // seperated by comma, should be mapped with Tag model in database
	Condition     uint8  // percentage of status after depreciation
	Status        string // ([A]vailable / [H]old / [N]ot available...will be hidden) only avabile when it is posted by registered user
	Duration      int    // list duration. default 7 days
	Location      string // current location, free text, can be just district
	Handover      string // ([F]ace / [D]elivery) handover method
	Delivery      string // ([P]ost / [C]ourrier) delivery method if not handover
	ContactMethod string // free text for user
	Contact       string
	Email         string // optional for user notification purpose
	Owner         uint   // owner ID if it is registered (optional subscription)
}
<|endoftext|>


<commit_before>
package main

import (
	"log"
	"net/rpc/jsonrpc"

	"github.com/natefinch/pie"
)

type HelloWorld struct {}

func (HelloWorld) Analyze(fname string, response *string) error {
	log.Printf("Received call for Hello with name: %q", fname)

	*response = fname

	return nil
}

func main () {
	log.SetPrefix("[helloworld ] ")
	p := pie.NewProvider()

	if err := p.RegisterName("HelloWorld", HelloWorld{}); err != nil {
		log.Fatalf("failed to register : %s", err)
	}
	p.ServeCodec(jsonrpc.NewServerCodec)
}<commit_msg>update output from example plugin<commit_after>
package main

import (
	"fmt"
	"log"
	"net/rpc/jsonrpc"

	"github.com/natefinch/pie"
)

type HelloWorld struct {}

func (HelloWorld) Analyze(fname string, response *string) error {
	log.Printf("Received call for Hello with name: %q", fname)

	*response = fmt.Sprintf("{\"Hello\":%q}", fname)

	return nil
}

func main () {
	log.SetPrefix("[helloworld ] ")
	p := pie.NewProvider()

	if err := p.RegisterName("HelloWorld", HelloWorld{}); err != nil {
		log.Fatalf("failed to register : %s", err)
	}
	p.ServeCodec(jsonrpc.NewServerCodec)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
)

func TestCacheGet(t *testing.T) {
	c := NewCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e, ok := c.Get(*example)
	if ok {
		t.Error(fmt.Printf("Cache must not contain %s", example.Url))
	}

	c.Add(*example)
	e, ok = c.Get(*example)
	if !ok {
		t.Error(fmt.Printf("Cache must return %s", example.Url))
	}
	if example.Url != e.Url {
		t.Error(fmt.Printf("Urls must be same(%s, %s)", example.Url, e.Url))
	}
}

func TestCacheSave(t *testing.T) {
	c := NewCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	c.Add(*example)
	c.Get(*example)
	err := c.Save(CacheFilename)

	if err != nil {
		t.Error(fmt.Printf("Error (%s) occurs when saving cache file", err))
	}
}

func TestLoadCache(t *testing.T) {
	c := NewCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	c.Add(*example)
	c.Get(*example)
	c.Save(CacheFilename)

	c, err := LoadCache(CacheFilename)
	if err != nil {
		t.Error(fmt.Printf("Error (%s) occurs when loading cache file", err))
	}

	e, ok := c.Get(*example)
	if !ok {
		t.Error(fmt.Printf("Cache must return %s", example.Url))
	}
	if example.Url != e.Url {
		t.Error(fmt.Printf("Urls must be same(%s, %s)", example.Url, e.Url))
	}
}
<commit_msg>redisに置き換え<commit_after>package main

import (
	"fmt"
	"testing"
)

func TestCacheGet(t *testing.T) {
	c := NewRedisCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	e, ok := c.Get(*example)
	if ok {
		t.Error(fmt.Printf("Cache must not contain %s", example.Url))
	}

	c.Add(*example)
	e, ok = c.Get(*example)
	if !ok {
		t.Error(fmt.Printf("Cache must return %s", example.Url))
	}
	if example.Url != e.Url {
		t.Error(fmt.Printf("Urls must be same(%s, %s)", example.Url, e.Url))
	}
}

func TestCacheSave(t *testing.T) {
	c := NewCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	c.Add(*example)
	c.Get(*example)
	err := c.Save(CacheFilename)

	if err != nil {
		t.Error(fmt.Printf("Error (%s) occurs when saving cache file", err))
	}
}

func TestLoadCache(t *testing.T) {
	c := NewCache()
	example := NewExample("http://b.hatena.ne.jp", POSITIVE)
	c.Add(*example)
	c.Get(*example)
	c.Save(CacheFilename)

	c, err := LoadCache(CacheFilename)
	if err != nil {
		t.Error(fmt.Printf("Error (%s) occurs when loading cache file", err))
	}

	e, ok := c.Get(*example)
	if !ok {
		t.Error(fmt.Printf("Cache must return %s", example.Url))
	}
	if example.Url != e.Url {
		t.Error(fmt.Printf("Urls must be same(%s, %s)", example.Url, e.Url))
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcec

import (
	"crypto/ecdsa"
	"crypto/rand"
	"math/big"
)

// PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing
// things with the the private key without having to directly import the ecdsa
// package.
type PrivateKey ecdsa.PrivateKey

// PrivKeyFromBytes returns a private and public key for `curve' based on the
// private key passed as an argument as a byte slice.
func PrivKeyFromBytes(curve *KoblitzCurve, pk []byte) (*PrivateKey,
	*PublicKey) {
	x, y := curve.ScalarBaseMult(pk)

	priv := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{
			Curve: curve,
			X:     x,
			Y:     y,
		},
		D: new(big.Int).SetBytes(pk),
	}

	return (*PrivateKey)(priv), (*PublicKey)(&priv.PublicKey)
}

// NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey
// instead of the normal ecdsa.PrivateKey.
func NewPrivateKey(curve *KoblitzCurve) (*PrivateKey, error) {
	key, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil, err
	}
	return (*PrivateKey)(key), nil
}

// PubKey returns the PublicKey corresponding to this private key.
func (p *PrivateKey) PubKey() *PublicKey {
	return (*PublicKey)(&p.PublicKey)
}

// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
	return (*ecdsa.PrivateKey)(p)
}

// Sign generates an ECDSA signature for the provided hash (which should be the result
// of hashing a larger message) using the private key. Produced signature
// is deterministic (same message and same key yield the same signature) and canonical
// in accordance with RFC6979 and BIP0062.
func (p *PrivateKey) Sign(hash []byte) (*Signature, error) {
	return signRFC6979(p, hash)
}

// PrivKeyBytesLen defines the length in bytes of a serialized private key.
const PrivKeyBytesLen = 32

// Serialize returns the private key number d as a big-endian binary-encoded
// number, padded to a length of 32 bytes.
func (p *PrivateKey) Serialize() []byte {
	b := make([]byte, 0, PrivKeyBytesLen)
	return paddedAppend(PrivKeyBytesLen, b, p.ToECDSA().D.Bytes())
}
<commit_msg>Replace *KoblitzCurve by elliptic.Curve<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcec

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"math/big"
)

// PrivateKey wraps an ecdsa.PrivateKey as a convenience mainly for signing
// things with the the private key without having to directly import the ecdsa
// package.
type PrivateKey ecdsa.PrivateKey

// PrivKeyFromBytes returns a private and public key for `curve' based on the
// private key passed as an argument as a byte slice.
func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (*PrivateKey,
	*PublicKey) {
	x, y := curve.ScalarBaseMult(pk)

	priv := &ecdsa.PrivateKey{
		PublicKey: ecdsa.PublicKey{
			Curve: curve,
			X:     x,
			Y:     y,
		},
		D: new(big.Int).SetBytes(pk),
	}

	return (*PrivateKey)(priv), (*PublicKey)(&priv.PublicKey)
}

// NewPrivateKey is a wrapper for ecdsa.GenerateKey that returns a PrivateKey
// instead of the normal ecdsa.PrivateKey.
func NewPrivateKey(curve elliptic.Curve) (*PrivateKey, error) {
	key, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil, err
	}
	return (*PrivateKey)(key), nil
}

// PubKey returns the PublicKey corresponding to this private key.
func (p *PrivateKey) PubKey() *PublicKey {
	return (*PublicKey)(&p.PublicKey)
}

// ToECDSA returns the private key as a *ecdsa.PrivateKey.
func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey {
	return (*ecdsa.PrivateKey)(p)
}

// Sign generates an ECDSA signature for the provided hash (which should be the result
// of hashing a larger message) using the private key. Produced signature
// is deterministic (same message and same key yield the same signature) and canonical
// in accordance with RFC6979 and BIP0062.
func (p *PrivateKey) Sign(hash []byte) (*Signature, error) {
	return signRFC6979(p, hash)
}

// PrivKeyBytesLen defines the length in bytes of a serialized private key.
const PrivKeyBytesLen = 32

// Serialize returns the private key number d as a big-endian binary-encoded
// number, padded to a length of 32 bytes.
func (p *PrivateKey) Serialize() []byte {
	b := make([]byte, 0, PrivKeyBytesLen)
	return paddedAppend(PrivKeyBytesLen, b, p.ToECDSA().D.Bytes())
}
<|endoftext|>


<commit_before>// 25 july 2014

package ui

import (
	"unsafe"
)

// #include "winapi_windows.h"
import "C"

/*
On Windows, container controls are just regular controls; their children have to be children of the parent window, and changing the contents of a switching container (such as a tab control) must be done manually.

TODO
- make sure all tabs cannot be deselected (that is, make sure the current tab can never have index -1)
- make sure tabs initially show the right control
- for some reason the text entry tabs show the checkbox tab until the checkbox tab is clicked, THEN they show their proper contents
*/

type tab struct {
	*widgetbase
	tabs			[]*container
}

func newTab() Tab {
	w := newWidget(C.xWC_TABCONTROL,
		C.TCS_TOOLTIPS | C.WS_TABSTOP,
		0)
	t := &tab{
		widgetbase:	w,
	}
	C.controlSetControlFont(w.hwnd)
	C.setTabSubclass(w.hwnd, unsafe.Pointer(t))
	return t
}

func (t *tab) setParent(win C.HWND) {
	t.widgetbase.setParent(win)
	for _, c := range t.tabs {
		c.child.setParent(win)
	}
}

func (t *tab) Append(name string, control Control) {
	c := new(container)
	t.tabs = append(t.tabs, c)
	c.child = control
	if t.parent != nil {
		c.child.setParent(t.parent)
	}
	C.tabAppend(t.hwnd, toUTF16(name))
}

//export tabChanging
func tabChanging(data unsafe.Pointer, current C.LRESULT) {
	t := (*tab)(data)
	t.tabs[int(current)].child.containerHide()
}

//export tabChanged
func tabChanged(data unsafe.Pointer, new C.LRESULT) {
	t := (*tab)(data)
	t.tabs[int(new)].child.containerShow()
}

// a tab control contains other controls; size appropriately
func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	var r C.RECT

	// figure out what the rect for each child is...
	r.left = C.LONG(x)				// load structure with the window's rect
	r.top = C.LONG(y)
	r.right = C.LONG(x + width)
	r.bottom = C.LONG(y + height)
	C.tabGetContentRect(t.hwnd, &r)
	// and allocate
	// don't allocate to just the current tab; allocate to all tabs!
	for _, c := range t.tabs {
		// because each widget is actually a child of the Window, the origin is the one we calculated above
		c.resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top))
	}
	// and now allocate the tab control itself
	return t.widgetbase.allocate(x, y, width, height, d)
}
<commit_msg>Fixed the Tab wrong control drawing issues on Windows.<commit_after>// 25 july 2014

package ui

import (
	"unsafe"
)

// #include "winapi_windows.h"
import "C"

/*
On Windows, container controls are just regular controls; their children have to be children of the parent window, and changing the contents of a switching container (such as a tab control) must be done manually.

TODO
- make sure all tabs cannot be deselected (that is, make sure the current tab can never have index -1)
- see if we can safely make the controls children of the tab control itself or if that would just screw our subclassing
*/

type tab struct {
	*widgetbase
	tabs			[]*container
}

func newTab() Tab {
	w := newWidget(C.xWC_TABCONTROL,
		C.TCS_TOOLTIPS | C.WS_TABSTOP,
		0)
	t := &tab{
		widgetbase:	w,
	}
	C.controlSetControlFont(w.hwnd)
	C.setTabSubclass(w.hwnd, unsafe.Pointer(t))
	return t
}

func (t *tab) setParent(win C.HWND) {
	t.widgetbase.setParent(win)
	for _, c := range t.tabs {
		c.child.setParent(win)
	}
}

func (t *tab) Append(name string, control Control) {
	c := new(container)
	t.tabs = append(t.tabs, c)
	c.child = control
	if t.parent != nil {
		c.child.setParent(t.parent)
	}
	// initially hide tab 1..n controls; if we don't, they'll appear over other tabs, resulting in weird behavior
	if len(t.tabs) != 1 {
		c.child.containerHide()
	}
	C.tabAppend(t.hwnd, toUTF16(name))
}

//export tabChanging
func tabChanging(data unsafe.Pointer, current C.LRESULT) {
	t := (*tab)(data)
	t.tabs[int(current)].child.containerHide()
}

//export tabChanged
func tabChanged(data unsafe.Pointer, new C.LRESULT) {
	t := (*tab)(data)
	t.tabs[int(new)].child.containerShow()
}

// a tab control contains other controls; size appropriately
func (t *tab) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	var r C.RECT

	// figure out what the rect for each child is...
	r.left = C.LONG(x)				// load structure with the window's rect
	r.top = C.LONG(y)
	r.right = C.LONG(x + width)
	r.bottom = C.LONG(y + height)
	C.tabGetContentRect(t.hwnd, &r)
	// and allocate
	// don't allocate to just the current tab; allocate to all tabs!
	for _, c := range t.tabs {
		// because each widget is actually a child of the Window, the origin is the one we calculated above
		c.resize(int(r.left), int(r.top), int(r.right - r.left), int(r.bottom - r.top))
	}
	// and now allocate the tab control itself
	return t.widgetbase.allocate(x, y, width, height, d)
}
<|endoftext|>


<commit_before>package glfw

//#include <GLFW/glfw3.h>
//GLFWmonitor* GetMonitorAtIndex(GLFWmonitor **monitors, int index);
//GLFWvidmode GetVidmodeAtIndex(GLFWvidmode *vidmodes, int index);
//void glfwSetMonitorCallbackCB();
import "C"

import "unsafe"

type Monitor struct {
	data *C.GLFWmonitor
}

//VideoMode describes a single video mode.
type VideoMode struct {
	Width     int //The width, in pixels, of the video mode.
	Height    int //The height, in pixels, of the video mode.
	RedBits   int //The bit depth of the red channel of the video mode.
	GreenBits int //The bit depth of the green channel of the video mode.
	BlueBits  int //The bit depth of the blue channel of the video mode.
}

type goMonitorFunc func(*Monitor, int)

var fMonitorHolder goMonitorFunc

//export goMonitorCB
func goMonitorCB(monitor unsafe.Pointer, event C.int) {
	fMonitorHolder(&Monitor{(*C.GLFWmonitor)(unsafe.Pointer(monitor))}, int(event))
}

//GetMonitors returns a slice of handles for all currently connected monitors.
func GetMonitors() [](*Monitor) {
	var length int

	mC := C.glfwGetMonitors((*C.int)(unsafe.Pointer(&length)))

	if mC == nil {
		return nil
	}

	m := make([](*Monitor), length)

	for i := 0; i < length; i++ {
		m[i] = &Monitor{C.GetMonitorAtIndex(mC, C.int(i))}
	}

	return m
}

//GetPrimaryMonitor returns the primary monitor. This is usually the monitor
//where elements like the Windows task bar or the OS X menu bar is located.
func GetPrimaryMonitor() *Monitor {
	m := C.glfwGetPrimaryMonitor()

	if m == nil {
		return nil
	}
	return &Monitor{m}
}

//GetPosition returns the position, in screen coordinates, of the upper-left
//corner of the monitor.
func (m *Monitor) GetPosition() (int, int) {
	var xpos, ypos C.int

	C.glfwGetMonitorPos(m.data, &xpos, &ypos)
	return int(xpos), int(ypos)
}

//GetPhysicalSize returns the size, in millimetres, of the display area of the
//monitor.
//
//Note: Some operating systems do not provide accurate information, either
//because the monitor's EDID data is incorrect, or because the driver does not
//report it accurately.
func (m *Monitor) GetPhysicalSize() (int, int) {
	var width, height C.int

	C.glfwGetMonitorPhysicalSize(m.data, &width, &height)
	return int(width), int(height)
}

//GetName returns a human-readable name of the monitor, encoded as UTF-8.
func (m *Monitor) GetName() string {
	return C.GoString(C.glfwGetMonitorName(m.data))
}

//SetMonitorCallback sets the monitor configuration callback, or removes the
//currently set callback. This is called when a monitor is connected to or
//disconnected from the system.
//
//Function signature for this callback is: func(*Monitor, int)
func SetMonitorCallback(cbfun goMonitorFunc) {
	fMonitorHolder = cbfun
	C.glfwSetMonitorCallbackCB()
}

//GetVideoModes returns an array of all video modes supported by the monitor.
//The returned array is sorted in ascending order, first by color bit depth
//(the sum of all channel depths) and then by resolution area (the product of
//width and height).
func (m *Monitor) GetVideoModes() [](*VideoMode) {
	var length int

	vC := C.glfwGetVideoModes(m.data, (*C.int)(unsafe.Pointer(&length)))
	if vC == nil {
		return nil
	}

	v := make([](*VideoMode), length)

	for i := 0; i < length; i++ {
		t := C.GetVidmodeAtIndex(vC, C.int(i))
		v[i] = &VideoMode{int(t.width), int(t.height), int(t.redBits), int(t.greenBits), int(t.blueBits)}
	}

	return v
}

//GetVideoMode returns the current video mode of the monitor. If you
//are using a full screen window, the return value will therefore depend on
//whether it is focused.
func (m *Monitor) GetVideoMode() *VideoMode {
	t := C.glfwGetVideoMode(m.data)

	if t == nil {
		return nil
	}
	return &VideoMode{int(t.width), int(t.height), int(t.redBits), int(t.greenBits), int(t.blueBits)}
}
<commit_msg>glfw: Remove unnecessary parentheses used in slice of pointer types.<commit_after>package glfw

//#include <GLFW/glfw3.h>
//GLFWmonitor* GetMonitorAtIndex(GLFWmonitor **monitors, int index);
//GLFWvidmode GetVidmodeAtIndex(GLFWvidmode *vidmodes, int index);
//void glfwSetMonitorCallbackCB();
import "C"

import "unsafe"

type Monitor struct {
	data *C.GLFWmonitor
}

//VideoMode describes a single video mode.
type VideoMode struct {
	Width     int //The width, in pixels, of the video mode.
	Height    int //The height, in pixels, of the video mode.
	RedBits   int //The bit depth of the red channel of the video mode.
	GreenBits int //The bit depth of the green channel of the video mode.
	BlueBits  int //The bit depth of the blue channel of the video mode.
}

type goMonitorFunc func(*Monitor, int)

var fMonitorHolder goMonitorFunc

//export goMonitorCB
func goMonitorCB(monitor unsafe.Pointer, event C.int) {
	fMonitorHolder(&Monitor{(*C.GLFWmonitor)(unsafe.Pointer(monitor))}, int(event))
}

//GetMonitors returns a slice of handles for all currently connected monitors.
func GetMonitors() []*Monitor {
	var length int

	mC := C.glfwGetMonitors((*C.int)(unsafe.Pointer(&length)))

	if mC == nil {
		return nil
	}

	m := make([]*Monitor, length)

	for i := 0; i < length; i++ {
		m[i] = &Monitor{C.GetMonitorAtIndex(mC, C.int(i))}
	}

	return m
}

//GetPrimaryMonitor returns the primary monitor. This is usually the monitor
//where elements like the Windows task bar or the OS X menu bar is located.
func GetPrimaryMonitor() *Monitor {
	m := C.glfwGetPrimaryMonitor()

	if m == nil {
		return nil
	}
	return &Monitor{m}
}

//GetPosition returns the position, in screen coordinates, of the upper-left
//corner of the monitor.
func (m *Monitor) GetPosition() (int, int) {
	var xpos, ypos C.int

	C.glfwGetMonitorPos(m.data, &xpos, &ypos)
	return int(xpos), int(ypos)
}

//GetPhysicalSize returns the size, in millimetres, of the display area of the
//monitor.
//
//Note: Some operating systems do not provide accurate information, either
//because the monitor's EDID data is incorrect, or because the driver does not
//report it accurately.
func (m *Monitor) GetPhysicalSize() (int, int) {
	var width, height C.int

	C.glfwGetMonitorPhysicalSize(m.data, &width, &height)
	return int(width), int(height)
}

//GetName returns a human-readable name of the monitor, encoded as UTF-8.
func (m *Monitor) GetName() string {
	return C.GoString(C.glfwGetMonitorName(m.data))
}

//SetMonitorCallback sets the monitor configuration callback, or removes the
//currently set callback. This is called when a monitor is connected to or
//disconnected from the system.
//
//Function signature for this callback is: func(*Monitor, int)
func SetMonitorCallback(cbfun goMonitorFunc) {
	fMonitorHolder = cbfun
	C.glfwSetMonitorCallbackCB()
}

//GetVideoModes returns an array of all video modes supported by the monitor.
//The returned array is sorted in ascending order, first by color bit depth
//(the sum of all channel depths) and then by resolution area (the product of
//width and height).
func (m *Monitor) GetVideoModes() []*VideoMode {
	var length int

	vC := C.glfwGetVideoModes(m.data, (*C.int)(unsafe.Pointer(&length)))
	if vC == nil {
		return nil
	}

	v := make([]*VideoMode, length)

	for i := 0; i < length; i++ {
		t := C.GetVidmodeAtIndex(vC, C.int(i))
		v[i] = &VideoMode{int(t.width), int(t.height), int(t.redBits), int(t.greenBits), int(t.blueBits)}
	}

	return v
}

//GetVideoMode returns the current video mode of the monitor. If you
//are using a full screen window, the return value will therefore depend on
//whether it is focused.
func (m *Monitor) GetVideoMode() *VideoMode {
	t := C.glfwGetVideoMode(m.data)

	if t == nil {
		return nil
	}
	return &VideoMode{int(t.width), int(t.height), int(t.redBits), int(t.greenBits), int(t.blueBits)}
}
<|endoftext|>


<commit_before>package main

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

	"gopkg.in/yaml.v2"

	"github.com/kusabashira/acgen"
	"github.com/ogier/pflag"
)

var (
	name    = "acgen"
	version = "0.1.0"

	flag       = pflag.NewFlagSet(name, pflag.ContinueOnError)
	outputType = flag.StringP("type", "t", "", "")
	isHelp     = flag.BoolP("help", "h", false, "")
	isVersion  = flag.BoolP("version", "v", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... FILE
Generate auto-completions for specifyed TYPE.

Options:
  -t, --type=TYPE   output auto-completion for specified TYPE
                      TYPE=bash|zsh|fish|yash
  -h, --help        display this help text and exit
  -v, --version     output version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n",
		name)
}

func main() {
	flag.SetOutput(ioutil.Discard)
	if err := flag.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	switch {
	case *isHelp:
		printUsage()
		os.Exit(0)
	case *isVersion:
		printVersion()
		os.Exit(0)
	}
	switch {
	case flag.NArg() < 1:
		printErr(fmt.Errorf("no input file"))
		guideToHelp()
		os.Exit(2)
	case *outputType == "":
		printErr(fmt.Errorf("no specify TYPE"))
		guideToHelp()
		os.Exit(2)
	}

	generator, err := acgen.LookGenerator(*outputType)
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	file := flag.Arg(0)
	conf, err := ioutil.ReadFile(file)
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	command := &acgen.Command{}
	if err = yaml.Unmarshal(conf, command); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}

	if err = generator(os.Stdout, command); err != nil {
		printErr(err)
		os.Exit(1)
	}
}
<commit_msg>Update usage to clarify acgen takes a source-file writen in YAML<commit_after>package main

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

	"gopkg.in/yaml.v2"

	"github.com/kusabashira/acgen"
	"github.com/ogier/pflag"
)

var (
	name    = "acgen"
	version = "0.1.0"

	flag       = pflag.NewFlagSet(name, pflag.ContinueOnError)
	outputType = flag.StringP("type", "t", "", "")
	isHelp     = flag.BoolP("help", "h", false, "")
	isVersion  = flag.BoolP("version", "v", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... SOURCE
Generate auto-completions for specifyed TYPE
by SOURCE written in YAML.

Options:
  -t, --type=TYPE   output auto-completion for specified TYPE
                      TYPE=bash|zsh|fish|yash
  -h, --help        display this help text and exit
  -v, --version     output version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintln(os.Stderr, version)
}

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n",
		name)
}

func main() {
	flag.SetOutput(ioutil.Discard)
	if err := flag.Parse(os.Args[1:]); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	switch {
	case *isHelp:
		printUsage()
		os.Exit(0)
	case *isVersion:
		printVersion()
		os.Exit(0)
	}
	switch {
	case flag.NArg() < 1:
		printErr(fmt.Errorf("no input file"))
		guideToHelp()
		os.Exit(2)
	case *outputType == "":
		printErr(fmt.Errorf("no specify TYPE"))
		guideToHelp()
		os.Exit(2)
	}

	generator, err := acgen.LookGenerator(*outputType)
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	file := flag.Arg(0)
	conf, err := ioutil.ReadFile(file)
	if err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}
	command := &acgen.Command{}
	if err = yaml.Unmarshal(conf, command); err != nil {
		printErr(err)
		guideToHelp()
		os.Exit(2)
	}

	if err = generator(os.Stdout, command); err != nil {
		printErr(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/ancientlore/vbscribble/vblexer"
	"github.com/ancientlore/vbscribble/vbscanner"
)

var (
	respWrite = flag.Bool("rw", false, "Use Response.Write formatting")
)

func main() {
	flag.Parse()

	for _, pattern := range flag.Args() {
		files, err := filepath.Glob(pattern)
		if err != nil {
			log.Fatal(err)
		}
		for _, f := range files {
			fi, err := os.Stat(f)
			if err != nil {
				log.Fatal(err)
			}
			if !fi.IsDir() {
				fmt.Fprintln(os.Stderr, "\n*** ", f, " ***")
				fil, err := os.Open(f)
				if err != nil {
					log.Fatal(err)
				}
				func(fil io.Reader, f string) {
					var lex vblexer.Lex
					defer func() {
						if r := recover(); r != nil {
							log.Print("PARSE ERROR ", f, ":", lex.Line, ": ", r)
						}
					}()
					lex.Init(fil, f, vbscanner.HTML_MODE)
					aft := ""
					tabs := 0
					startLine := true
					paren := false
					prevK := vblexer.EOF
					var prevT interface{}
					needStarter := false
					remTabAfterEOL := false
					if *respWrite {
						fmt.Print("<%")
					}
					for k, t, v := lex.Lex(); k != vblexer.EOF; k, t, v = lex.Lex() {
						if needStarter {
							fmt.Print("<%")
							needStarter = false
						}
						if startLine {
							if k == vblexer.STATEMENT {
								if t == "End" {
									pv := v
									k, t, v = lex.Lex()
									if k != vblexer.EOF {
										t = "End " + t.(string)
										v = pv + " " + v
										tabs--
										if t == "End Select" {
											tabs--
										}
									}
								}
								switch t {
								case "Else", "ElseIf", "Case", "Wend":
									tabs--
								}
							}
							if tabs < 0 {
								tabs = 0
							}
							if prevK != vblexer.HTML {
								fmt.Print(strings.Repeat("\t", tabs))
							}
							if remTabAfterEOL {
								remTabAfterEOL = false
								tabs--
							}
							startLine = false
							aft = ""
							paren = false
						} else {
							aft = " "
						}
						if paren {
							paren = false
							aft = ""
						}
						if prevK == vblexer.STATEMENT && prevT == "Then" {
							if k != vblexer.EOL && k != vblexer.HTML {
								tabs--
							}
						}
						switch k {
						case vblexer.EOF:
						case vblexer.STATEMENT:
							fmt.Print(aft)
							fmt.Print(t)
							switch t {
							case "If", "Function", "Sub", "Class", "Select", "Property":
								if !(prevK == vblexer.STATEMENT && prevT == "Exit") {
									tabs++
								}
							case "Else":
								if !(prevK == vblexer.STATEMENT && prevT == "Case") {
									tabs++
								}
							case "ElseIf", "Case", "Do", "While":
								tabs++
							}
						case vblexer.FUNCTION:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.KEYWORD, vblexer.KEYWORD_BOOL:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.COLOR_CONSTANT, vblexer.COMPARE_CONSTANT, vblexer.DATE_CONSTANT, vblexer.DATEFORMAT_CONSTANT, vblexer.MISC_CONSTANT, vblexer.MSGBOX_CONSTANT, vblexer.STRING_CONSTANT, vblexer.TRISTATE_CONSTANT, vblexer.VARTYPE_CONSTANT:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.IDENTIFIER:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.STRING:
							fmt.Print(aft)
							fmt.Printf("\"%s\"", strings.Replace(v, "\"", "\"\"", -1))
						case vblexer.INT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.FLOAT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.DATE:
							fmt.Print(aft)
							fmt.Print("#", v, "#")
						case vblexer.COMMENT:
							fmt.Print(aft)
							fmt.Printf("' %s", t)
						case vblexer.HTML:
							if *respWrite {
								lines := strings.Split(strings.Replace(v, "\r", "", -1), "\n")
								for index, line := range lines {
									if index == 0 {
										fmt.Println()
										fmt.Print(aft)
										fmt.Print("Response.Write ")
									} else {
										fmt.Print(strings.Repeat("\t", tabs+1))
										fmt.Print("& vbCrLf & ")
									}
									fmt.Printf("\"%s\"\n", strings.Replace(line, "\"", "\"\"", -1))
								}
							} else {
								if prevK != vblexer.EOF {
									fmt.Print(aft)
									fmt.Print("%>")
								}
								fmt.Print(v)
								needStarter = true
							}
							startLine = true
						case vblexer.CHAR:
							fmt.Print(t)
							if t == "(" {
								paren = true
							}
						case vblexer.EOL:
							if t == ":" {
								fmt.Print(aft)
								fmt.Print(t)
								fmt.Print(" ")
							} else {
								fmt.Println()
							}
							startLine = true
						case vblexer.OP:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.CONTINUATION:
							fmt.Print(aft)
							fmt.Print(t)
							tabs++
							remTabAfterEOL = true
						default:
							panic("Unexpected token type")
						}
						prevK = k
						prevT = t
					}
					if *respWrite {
						fmt.Println("%>")
					}
				}(fil, f)
				fil.Close()
			}
		}
	}
}
<commit_msg>Fix do/for loop indentation<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/ancientlore/vbscribble/vblexer"
	"github.com/ancientlore/vbscribble/vbscanner"
)

var (
	respWrite = flag.Bool("rw", false, "Use Response.Write formatting")
)

func main() {
	flag.Parse()

	for _, pattern := range flag.Args() {
		files, err := filepath.Glob(pattern)
		if err != nil {
			log.Fatal(err)
		}
		for _, f := range files {
			fi, err := os.Stat(f)
			if err != nil {
				log.Fatal(err)
			}
			if !fi.IsDir() {
				fmt.Fprintln(os.Stderr, "\n*** ", f, " ***")
				fil, err := os.Open(f)
				if err != nil {
					log.Fatal(err)
				}
				func(fil io.Reader, f string) {
					var lex vblexer.Lex
					defer func() {
						if r := recover(); r != nil {
							log.Print("PARSE ERROR ", f, ":", lex.Line, ": ", r)
						}
					}()
					lex.Init(fil, f, vbscanner.HTML_MODE)
					aft := ""
					tabs := 0
					startLine := true
					paren := false
					prevK := vblexer.EOF
					var prevT interface{}
					needStarter := false
					remTabAfterEOL := false
					if *respWrite {
						fmt.Print("<%")
					}
					for k, t, v := lex.Lex(); k != vblexer.EOF; k, t, v = lex.Lex() {
						if needStarter {
							fmt.Print("<%")
							needStarter = false
						}
						if startLine {
							if k == vblexer.STATEMENT {
								if t == "End" {
									pv := v
									k, t, v = lex.Lex()
									if k != vblexer.EOF {
										t = "End " + t.(string)
										v = pv + " " + v
										tabs--
										/*
											if t == "End Select" {
												tabs--
											}
										*/
									}
								}
								switch t {
								case "Else", "ElseIf", "Case", "Wend", "Next", "Loop":
									tabs--
								}
							}
							if tabs < 0 {
								tabs = 0
							}
							if prevK != vblexer.HTML {
								fmt.Print(strings.Repeat("\t", tabs))
							}
							if remTabAfterEOL {
								remTabAfterEOL = false
								tabs--
							}
							startLine = false
							aft = ""
							paren = false
						} else {
							aft = " "
						}
						if paren {
							paren = false
							aft = ""
						}
						if prevK == vblexer.STATEMENT && prevT == "Then" {
							if k != vblexer.EOL && k != vblexer.HTML {
								tabs--
							}
						}
						switch k {
						case vblexer.EOF:
						case vblexer.STATEMENT:
							fmt.Print(aft)
							fmt.Print(t)
							switch t {
							case "If", "Function", "Sub", "Class", "Property": // "Select"
								if !(prevK == vblexer.STATEMENT && prevT == "Exit") {
									tabs++
								}
							case "Else":
								if !(prevK == vblexer.STATEMENT && prevT == "Case") {
									tabs++
								}
							case "ElseIf", "Case", "While", "For": // "Do"
								tabs++
							}
						case vblexer.FUNCTION:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.KEYWORD, vblexer.KEYWORD_BOOL:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.COLOR_CONSTANT, vblexer.COMPARE_CONSTANT, vblexer.DATE_CONSTANT, vblexer.DATEFORMAT_CONSTANT, vblexer.MISC_CONSTANT, vblexer.MSGBOX_CONSTANT, vblexer.STRING_CONSTANT, vblexer.TRISTATE_CONSTANT, vblexer.VARTYPE_CONSTANT:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.IDENTIFIER:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.STRING:
							fmt.Print(aft)
							fmt.Printf("\"%s\"", strings.Replace(v, "\"", "\"\"", -1))
						case vblexer.INT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.FLOAT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.DATE:
							fmt.Print(aft)
							fmt.Print("#", v, "#")
						case vblexer.COMMENT:
							fmt.Print(aft)
							fmt.Printf("' %s", t)
						case vblexer.HTML:
							if *respWrite {
								lines := strings.Split(strings.Replace(v, "\r", "", -1), "\n")
								for index, line := range lines {
									if index == 0 {
										fmt.Println()
										fmt.Print(aft)
										fmt.Print("Response.Write ")
									} else {
										fmt.Print(strings.Repeat("\t", tabs+1))
										fmt.Print("& vbCrLf & ")
									}
									fmt.Printf("\"%s\"\n", strings.Replace(line, "\"", "\"\"", -1))
								}
							} else {
								if prevK != vblexer.EOF {
									fmt.Print(aft)
									fmt.Print("%>")
								}
								fmt.Print(v)
								needStarter = true
							}
							startLine = true
						case vblexer.CHAR:
							fmt.Print(t)
							if t == "(" {
								paren = true
							}
						case vblexer.EOL:
							if t == ":" {
								fmt.Print(aft)
								fmt.Print(t)
								fmt.Print(" ")
							} else {
								fmt.Println()
							}
							startLine = true
						case vblexer.OP:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.CONTINUATION:
							fmt.Print(aft)
							fmt.Print(t)
							tabs++
							remTabAfterEOL = true
						default:
							panic("Unexpected token type")
						}
						prevK = k
						prevT = t
					}
					if *respWrite {
						fmt.Println("%>")
					}
				}(fil, f)
				fil.Close()
			}
		}
	}
}
<|endoftext|>


<commit_before>package control

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"golang.org/x/net/context"

	log "github.com/Sirupsen/logrus"
	yaml "github.com/cloudfoundry-incubator/candiedyaml"

	"github.com/codegangsta/cli"
	dockerClient "github.com/docker/engine-api/client"
	composeConfig "github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project/options"
	"github.com/rancher/os/cmd/power"
	"github.com/rancher/os/compose"
	"github.com/rancher/os/config"
	"github.com/rancher/os/docker"
)

type Images struct {
	Current   string   `yaml:"current,omitempty"`
	Available []string `yaml:"available,omitempty"`
}

func osSubcommands() []cli.Command {
	return []cli.Command{
		{
			Name:   "upgrade",
			Usage:  "upgrade to latest version",
			Action: osUpgrade,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "stage, s",
					Usage: "Only stage the new upgrade, don't apply it",
				},
				cli.StringFlag{
					Name:  "image, i",
					Usage: "upgrade to a certain image",
				},
				cli.BoolFlag{
					Name:  "force, f",
					Usage: "do not prompt for input",
				},
				cli.BoolFlag{
					Name:  "no-reboot",
					Usage: "do not reboot after upgrade",
				},
				cli.BoolFlag{
					Name:  "kexec",
					Usage: "reboot using kexec",
				},
				cli.StringFlag{
					Name:  "append",
					Usage: "kernel args to append by kexec",
				},
				cli.BoolFlag{
					Name:  "upgrade-console",
					Usage: "upgrade console even if persistent",
				},
			},
		},
		{
			Name:   "list",
			Usage:  "list the current available versions",
			Action: osMetaDataGet,
		},
		{
			Name:   "version",
			Usage:  "show the currently installed version",
			Action: osVersion,
		},
	}
}

func getImages() (*Images, error) {
	upgradeUrl, err := getUpgradeUrl()
	if err != nil {
		return nil, err
	}

	var body []byte

	if strings.HasPrefix(upgradeUrl, "/") {
		body, err = ioutil.ReadFile(upgradeUrl)
		if err != nil {
			return nil, err
		}
	} else {
		u, err := url.Parse(upgradeUrl)
		if err != nil {
			return nil, err
		}

		q := u.Query()
		q.Set("current", config.VERSION)
		u.RawQuery = q.Encode()
		upgradeUrl = u.String()

		resp, err := http.Get(upgradeUrl)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
	}

	return parseBody(body)
}

func osMetaDataGet(c *cli.Context) error {
	images, err := getImages()
	if err != nil {
		log.Fatal(err)
	}

	client, err := docker.NewSystemClient()
	if err != nil {
		log.Fatal(err)
	}

	for _, image := range images.Available {
		_, _, err := client.ImageInspectWithRaw(context.Background(), image, false)
		if dockerClient.IsErrImageNotFound(err) {
			fmt.Println(image, "remote")
		} else {
			fmt.Println(image, "local")
		}
	}

	return nil
}

func getLatestImage() (string, error) {
	images, err := getImages()
	if err != nil {
		return "", err
	}

	return images.Current, nil
}

func osUpgrade(c *cli.Context) error {
	image := c.String("image")

	if image == "" {
		var err error
		image, err = getLatestImage()
		if err != nil {
			log.Fatal(err)
		}
		if image == "" {
			log.Fatal("Failed to find latest image")
		}
	}
	if c.Args().Present() {
		log.Fatalf("invalid arguments %v", c.Args())
	}
	if err := startUpgradeContainer(image, c.Bool("stage"), c.Bool("force"), !c.Bool("no-reboot"), c.Bool("kexec"), c.Bool("upgrade-console"), c.String("append")); err != nil {
		log.Fatal(err)
	}

	return nil
}

func osVersion(c *cli.Context) error {
	fmt.Println(config.VERSION)
	return nil
}

func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgradeConsole bool, kernelArgs string) error {
	in := bufio.NewReader(os.Stdin)

	command := []string{
		"-t", "rancher-upgrade",
		"-r", config.VERSION,
	}

	if kexec {
		command = append(command, "-k")

		kernelArgs = strings.TrimSpace(kernelArgs)
		if kernelArgs != "" {
			command = append(command, "-a", kernelArgs)
		}
	}

	if upgradeConsole {
		if err := config.Set("rancher.force_console_rebuild", true); err != nil {
			log.Fatal(err)
		}
	}

	fmt.Printf("Upgrading to %s\n", image)
	confirmation := "Continue"
	imageSplit := strings.Split(image, ":")
	if len(imageSplit) > 1 && imageSplit[1] == config.VERSION+config.SUFFIX {
		confirmation = fmt.Sprintf("Already at version %s. Continue anyway", imageSplit[1])
	}
	if !force && !yes(in, confirmation) {
		os.Exit(1)
	}

	container, err := compose.CreateService(nil, "os-upgrade", &composeConfig.ServiceConfigV1{
		LogDriver:  "json-file",
		Privileged: true,
		Net:        "host",
		Pid:        "host",
		Image:      image,
		Labels: map[string]string{
			config.SCOPE: config.SYSTEM,
		},
		Command: command,
	})
	if err != nil {
		return err
	}

	client, err := docker.NewSystemClient()
	if err != nil {
		return err
	}

	// Only pull image if not found locally
	if _, _, err := client.ImageInspectWithRaw(context.Background(), image, false); err != nil {
		if err := container.Pull(context.Background()); err != nil {
			return err
		}
	}

	if !stage {
		// If there is already an upgrade container, delete it
		// Up() should to this, but currently does not due to a bug
		if err := container.Delete(context.Background(), options.Delete{}); err != nil {
			return err
		}

		if err := container.Up(context.Background(), options.Up{
			Log: true,
		}); err != nil {
			return err
		}

		if err := container.Log(context.Background(), true); err != nil {
			return err
		}

		if err := container.Delete(context.Background(), options.Delete{}); err != nil {
			return err
		}

		if reboot && (force || yes(in, "Continue with reboot")) {
			log.Info("Rebooting")
			power.Reboot()
		}
	}

	return nil
}

func parseBody(body []byte) (*Images, error) {
	update := &Images{}
	err := yaml.Unmarshal(body, update)
	if err != nil {
		return nil, err
	}

	return update, nil
}

func getUpgradeUrl() (string, error) {
	cfg := config.LoadConfig()
	return cfg.Rancher.Upgrade.Url, nil
}
<commit_msg>Only log once during upgrade<commit_after>package control

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"strings"

	"golang.org/x/net/context"

	log "github.com/Sirupsen/logrus"
	yaml "github.com/cloudfoundry-incubator/candiedyaml"

	"github.com/codegangsta/cli"
	dockerClient "github.com/docker/engine-api/client"
	composeConfig "github.com/docker/libcompose/config"
	"github.com/docker/libcompose/project/options"
	"github.com/rancher/os/cmd/power"
	"github.com/rancher/os/compose"
	"github.com/rancher/os/config"
	"github.com/rancher/os/docker"
)

type Images struct {
	Current   string   `yaml:"current,omitempty"`
	Available []string `yaml:"available,omitempty"`
}

func osSubcommands() []cli.Command {
	return []cli.Command{
		{
			Name:   "upgrade",
			Usage:  "upgrade to latest version",
			Action: osUpgrade,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "stage, s",
					Usage: "Only stage the new upgrade, don't apply it",
				},
				cli.StringFlag{
					Name:  "image, i",
					Usage: "upgrade to a certain image",
				},
				cli.BoolFlag{
					Name:  "force, f",
					Usage: "do not prompt for input",
				},
				cli.BoolFlag{
					Name:  "no-reboot",
					Usage: "do not reboot after upgrade",
				},
				cli.BoolFlag{
					Name:  "kexec",
					Usage: "reboot using kexec",
				},
				cli.StringFlag{
					Name:  "append",
					Usage: "kernel args to append by kexec",
				},
				cli.BoolFlag{
					Name:  "upgrade-console",
					Usage: "upgrade console even if persistent",
				},
			},
		},
		{
			Name:   "list",
			Usage:  "list the current available versions",
			Action: osMetaDataGet,
		},
		{
			Name:   "version",
			Usage:  "show the currently installed version",
			Action: osVersion,
		},
	}
}

func getImages() (*Images, error) {
	upgradeUrl, err := getUpgradeUrl()
	if err != nil {
		return nil, err
	}

	var body []byte

	if strings.HasPrefix(upgradeUrl, "/") {
		body, err = ioutil.ReadFile(upgradeUrl)
		if err != nil {
			return nil, err
		}
	} else {
		u, err := url.Parse(upgradeUrl)
		if err != nil {
			return nil, err
		}

		q := u.Query()
		q.Set("current", config.VERSION)
		u.RawQuery = q.Encode()
		upgradeUrl = u.String()

		resp, err := http.Get(upgradeUrl)
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
	}

	return parseBody(body)
}

func osMetaDataGet(c *cli.Context) error {
	images, err := getImages()
	if err != nil {
		log.Fatal(err)
	}

	client, err := docker.NewSystemClient()
	if err != nil {
		log.Fatal(err)
	}

	for _, image := range images.Available {
		_, _, err := client.ImageInspectWithRaw(context.Background(), image, false)
		if dockerClient.IsErrImageNotFound(err) {
			fmt.Println(image, "remote")
		} else {
			fmt.Println(image, "local")
		}
	}

	return nil
}

func getLatestImage() (string, error) {
	images, err := getImages()
	if err != nil {
		return "", err
	}

	return images.Current, nil
}

func osUpgrade(c *cli.Context) error {
	image := c.String("image")

	if image == "" {
		var err error
		image, err = getLatestImage()
		if err != nil {
			log.Fatal(err)
		}
		if image == "" {
			log.Fatal("Failed to find latest image")
		}
	}
	if c.Args().Present() {
		log.Fatalf("invalid arguments %v", c.Args())
	}
	if err := startUpgradeContainer(image, c.Bool("stage"), c.Bool("force"), !c.Bool("no-reboot"), c.Bool("kexec"), c.Bool("upgrade-console"), c.String("append")); err != nil {
		log.Fatal(err)
	}

	return nil
}

func osVersion(c *cli.Context) error {
	fmt.Println(config.VERSION)
	return nil
}

func startUpgradeContainer(image string, stage, force, reboot, kexec bool, upgradeConsole bool, kernelArgs string) error {
	in := bufio.NewReader(os.Stdin)

	command := []string{
		"-t", "rancher-upgrade",
		"-r", config.VERSION,
	}

	if kexec {
		command = append(command, "-k")

		kernelArgs = strings.TrimSpace(kernelArgs)
		if kernelArgs != "" {
			command = append(command, "-a", kernelArgs)
		}
	}

	if upgradeConsole {
		if err := config.Set("rancher.force_console_rebuild", true); err != nil {
			log.Fatal(err)
		}
	}

	fmt.Printf("Upgrading to %s\n", image)
	confirmation := "Continue"
	imageSplit := strings.Split(image, ":")
	if len(imageSplit) > 1 && imageSplit[1] == config.VERSION+config.SUFFIX {
		confirmation = fmt.Sprintf("Already at version %s. Continue anyway", imageSplit[1])
	}
	if !force && !yes(in, confirmation) {
		os.Exit(1)
	}

	container, err := compose.CreateService(nil, "os-upgrade", &composeConfig.ServiceConfigV1{
		LogDriver:  "json-file",
		Privileged: true,
		Net:        "host",
		Pid:        "host",
		Image:      image,
		Labels: map[string]string{
			config.SCOPE: config.SYSTEM,
		},
		Command: command,
	})
	if err != nil {
		return err
	}

	client, err := docker.NewSystemClient()
	if err != nil {
		return err
	}

	// Only pull image if not found locally
	if _, _, err := client.ImageInspectWithRaw(context.Background(), image, false); err != nil {
		if err := container.Pull(context.Background()); err != nil {
			return err
		}
	}

	if !stage {
		// If there is already an upgrade container, delete it
		// Up() should to this, but currently does not due to a bug
		if err := container.Delete(context.Background(), options.Delete{}); err != nil {
			return err
		}

		if err := container.Up(context.Background(), options.Up{}); err != nil {
			return err
		}

		if err := container.Log(context.Background(), true); err != nil {
			return err
		}

		if err := container.Delete(context.Background(), options.Delete{}); err != nil {
			return err
		}

		if reboot && (force || yes(in, "Continue with reboot")) {
			log.Info("Rebooting")
			power.Reboot()
		}
	}

	return nil
}

func parseBody(body []byte) (*Images, error) {
	update := &Images{}
	err := yaml.Unmarshal(body, update)
	if err != nil {
		return nil, err
	}

	return update, nil
}

func getUpgradeUrl() (string, error) {
	cfg := config.LoadConfig()
	return cfg.Rancher.Upgrade.Url, nil
}
<|endoftext|>