<commit_before>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/pkg/errors"
)

type cmdMove struct {
	global *cmdGlobal

	flagNoProfiles    bool
	flagProfile       []string
	flagConfig        []string
	flagInstanceOnly  bool
	flagDevice        []string
	flagMode          string
	flagStateless     bool
	flagStorage       string
	flagTarget        string
	flagTargetProject string
}

func (c *cmdMove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("move", i18n.G("[<remote>:]<instance>[/<snapshot>] [<remote>:][<instance>[/<snapshot>]]"))
	cmd.Aliases = []string{"mv"}
	cmd.Short = i18n.G("Move instances within or in between LXD servers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Move instances within or in between LXD servers`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc move [<remote>:]<source instance> [<remote>:][<destination instance>] [--instance-only]
    Move an instance between two hosts, renaming it if destination name differs.

lxc move <old name> <new name> [--instance-only]
    Rename a local instance.

lxc move <instance>/<old snapshot name> <instance>/<new snapshot name>
    Rename a snapshot.`))

	cmd.RunE = c.Run
	cmd.Flags().StringArrayVarP(&c.flagConfig, "config", "c", nil, i18n.G("Config key/value to apply to the target instance")+"``")
	cmd.Flags().StringArrayVarP(&c.flagDevice, "device", "d", nil, i18n.G("New key/value to apply to a specific device")+"``")
	cmd.Flags().StringArrayVarP(&c.flagProfile, "profile", "p", nil, i18n.G("Profile to apply to the target instance")+"``")
	cmd.Flags().BoolVar(&c.flagNoProfiles, "no-profiles", false, i18n.G("Unset all profiles on the target instance"))
	cmd.Flags().BoolVar(&c.flagInstanceOnly, "instance-only", false, i18n.G("Move the instance without its snapshots"))
	cmd.Flags().StringVar(&c.flagMode, "mode", moveDefaultMode, i18n.G("Transfer mode. One of pull (default), push or relay.")+"``")
	cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Copy a stateful instance stateless"))
	cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", i18n.G("Storage pool name")+"``")
	cmd.Flags().StringVar(&c.flagTarget, "target", "", i18n.G("Cluster member name")+"``")
	cmd.Flags().StringVar(&c.flagTargetProject, "target-project", "", i18n.G("Copy to a project different from the source")+"``")

	return cmd
}

func (c *cmdMove) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Quick checks.
	if c.flagTarget == "" && c.flagTargetProject == "" && c.flagStorage == "" {
		exit, err := c.global.CheckArgs(cmd, args, 2, 2)
		if exit {
			return err
		}
	} else {
		exit, err := c.global.CheckArgs(cmd, args, 1, 2)
		if exit {
			return err
		}
	}

	// Parse the mode
	mode := moveDefaultMode
	if c.flagMode != "" {
		mode = c.flagMode
	}

	sourceRemote, sourceName, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	destRemote := sourceRemote
	destName := ""
	if len(args) == 2 {
		var err error
		destRemote, destName, err = conf.ParseRemote(args[1])
		if err != nil {
			return err
		}
	}

	// As an optimization, if the source an destination are the same, do
	// this via a simple rename. This only works for instances that aren't
	// running, instances that are running should be live migrated (of
	// course, this changing of hostname isn't supported right now, so this
	// simply won't work).
	if sourceRemote == destRemote && c.flagTarget == "" && c.flagStorage == "" && c.flagTargetProject == "" {
		if c.flagConfig != nil || c.flagDevice != nil || c.flagProfile != nil || c.flagNoProfiles {
			return fmt.Errorf(i18n.G("Can't override configuration or profiles in local rename"))
		}

		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if shared.IsSnapshot(sourceName) {
			// Snapshot rename
			srcParent, srcSnap, _ := shared.InstanceGetParentAndSnapshotName(sourceName)
			dstParent, dstSnap, dstIsSnap := shared.InstanceGetParentAndSnapshotName(destName)

			if srcParent != dstParent {
				return fmt.Errorf("Invalid new snapshot name, parent must be the same as source")
			}

			if !dstIsSnap {
				return fmt.Errorf("Invalid new snapshot name")
			}

			op, err := source.RenameInstanceSnapshot(srcParent, srcSnap, api.InstanceSnapshotPost{Name: dstSnap})
			if err != nil {
				return err
			}

			return op.Wait()
		}

		// Instance rename
		op, err := source.RenameInstance(sourceName, api.InstancePost{Name: destName})
		if err != nil {
			return err
		}

		return op.Wait()
	}

	sourceResource := args[0]
	destResource := sourceResource
	if len(args) == 2 {
		destResource = args[1]
	}

	if c.flagTarget != "" {
		// If the target option was specified, we're moving an instance from a
		// cluster member to another, let's use the dedicated API.
		if sourceRemote == destRemote {
			if c.flagStateless {
				return fmt.Errorf(i18n.G("The --stateless flag can't be used with --target"))
			}

			if c.flagInstanceOnly {
				return fmt.Errorf(i18n.G("The --instance-only flag can't be used with --target"))
			}

			if c.flagStorage != "" {
				return fmt.Errorf(i18n.G("The --storage flag can't be used with --target"))
			}

			if c.flagMode != moveDefaultMode {
				return fmt.Errorf(i18n.G("The --mode flag can't be used with --target"))
			}

			return moveClusterInstance(conf, sourceResource, destResource, c.flagTarget, c.global.flagQuiet)
		}

		dest, err := conf.GetInstanceServer(destRemote)
		if err != nil {
			return err
		}

		if !dest.IsClustered() {
			return fmt.Errorf(i18n.G("The destination LXD server is not clustered"))
		}
	}

	// Support for server-side pool move.
	if c.flagStorage != "" && sourceRemote == destRemote {
		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if source.HasExtension("instance_pool_move") {
			if c.flagStateless {
				return fmt.Errorf(i18n.G("The --stateless flag can't be used with --storage"))
			}

			if c.flagMode != moveDefaultMode {
				return fmt.Errorf(i18n.G("The --mode flag can't be used with --storage"))
			}

			return moveInstancePool(conf, sourceResource, destResource, c.flagInstanceOnly, c.flagStorage)
		}
	}

	cpy := cmdCopy{}
	cpy.global = c.global
	cpy.flagTarget = c.flagTarget
	cpy.flagTargetProject = c.flagTargetProject
	cpy.flagConfig = c.flagConfig
	cpy.flagDevice = c.flagDevice
	cpy.flagProfile = c.flagProfile
	cpy.flagNoProfiles = c.flagNoProfiles

	stateful := !c.flagStateless
	instanceOnly := c.flagInstanceOnly

	// A move is just a copy followed by a delete; however, we want to
	// keep the volatile entries around since we are moving the instance.
	err = cpy.copyInstance(conf, sourceResource, destResource, true, -1, stateful, instanceOnly, mode, c.flagStorage, true)
	if err != nil {
		return err
	}

	del := cmdDelete{global: c.global}
	del.flagForce = true
	del.flagForceProtected = true
	err = del.Run(cmd, args[:1])
	if err != nil {
		return errors.Wrap(err, "Failed to delete original instance after copying it")
	}

	return nil
}

// Move an instance using special POST /instances/<name>?target=<member> API.
func moveClusterInstance(conf *config.Config, sourceResource string, destResource string, target string, quiet bool) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Check that it's a cluster
	if !source.IsClustered() {
		return fmt.Errorf(i18n.G("The source LXD server is not clustered"))
	}

	// The migrate API will do the right thing when passed a target.
	source = source.UseTarget(target)
	req := api.InstancePost{
		Name:      destName,
		Migration: true,
	}

	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	// Watch the background operation
	progress := utils.ProgressRenderer{
		Format: i18n.G("Transferring instance: %s"),
		Quiet:  quiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}
	// Wait for the move to complete
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return err
	}
	progress.Done("")

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Move an instance between pools using special POST /instances/<name> API.
func moveInstancePool(conf *config.Config, sourceResource string, destResource string, instanceOnly bool, storage string) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Pass the new pool to the migration API.
	req := api.InstancePost{
		Name:         destName,
		Migration:    true,
		Pool:         storage,
		InstanceOnly: instanceOnly,
	}

	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Default migration mode when moving an instance.
const moveDefaultMode = "pull"
<commit_msg>lxd/move: Adds stateful migration support for cross-pool instance migrations<commit_after>package main

import (
	"fmt"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
	"github.com/pkg/errors"
)

type cmdMove struct {
	global *cmdGlobal

	flagNoProfiles    bool
	flagProfile       []string
	flagConfig        []string
	flagInstanceOnly  bool
	flagDevice        []string
	flagMode          string
	flagStateless     bool
	flagStorage       string
	flagTarget        string
	flagTargetProject string
}

func (c *cmdMove) Command() *cobra.Command {
	cmd := &cobra.Command{}
	cmd.Use = usage("move", i18n.G("[<remote>:]<instance>[/<snapshot>] [<remote>:][<instance>[/<snapshot>]]"))
	cmd.Aliases = []string{"mv"}
	cmd.Short = i18n.G("Move instances within or in between LXD servers")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Move instances within or in between LXD servers`))
	cmd.Example = cli.FormatSection("", i18n.G(
		`lxc move [<remote>:]<source instance> [<remote>:][<destination instance>] [--instance-only]
    Move an instance between two hosts, renaming it if destination name differs.

lxc move <old name> <new name> [--instance-only]
    Rename a local instance.

lxc move <instance>/<old snapshot name> <instance>/<new snapshot name>
    Rename a snapshot.`))

	cmd.RunE = c.Run
	cmd.Flags().StringArrayVarP(&c.flagConfig, "config", "c", nil, i18n.G("Config key/value to apply to the target instance")+"``")
	cmd.Flags().StringArrayVarP(&c.flagDevice, "device", "d", nil, i18n.G("New key/value to apply to a specific device")+"``")
	cmd.Flags().StringArrayVarP(&c.flagProfile, "profile", "p", nil, i18n.G("Profile to apply to the target instance")+"``")
	cmd.Flags().BoolVar(&c.flagNoProfiles, "no-profiles", false, i18n.G("Unset all profiles on the target instance"))
	cmd.Flags().BoolVar(&c.flagInstanceOnly, "instance-only", false, i18n.G("Move the instance without its snapshots"))
	cmd.Flags().StringVar(&c.flagMode, "mode", moveDefaultMode, i18n.G("Transfer mode. One of pull (default), push or relay.")+"``")
	cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Copy a stateful instance stateless"))
	cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", i18n.G("Storage pool name")+"``")
	cmd.Flags().StringVar(&c.flagTarget, "target", "", i18n.G("Cluster member name")+"``")
	cmd.Flags().StringVar(&c.flagTargetProject, "target-project", "", i18n.G("Copy to a project different from the source")+"``")

	return cmd
}

func (c *cmdMove) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	// Quick checks.
	if c.flagTarget == "" && c.flagTargetProject == "" && c.flagStorage == "" {
		exit, err := c.global.CheckArgs(cmd, args, 2, 2)
		if exit {
			return err
		}
	} else {
		exit, err := c.global.CheckArgs(cmd, args, 1, 2)
		if exit {
			return err
		}
	}

	// Parse the mode
	mode := moveDefaultMode
	if c.flagMode != "" {
		mode = c.flagMode
	}

	sourceRemote, sourceName, err := conf.ParseRemote(args[0])
	if err != nil {
		return err
	}

	destRemote := sourceRemote
	destName := ""
	if len(args) == 2 {
		var err error
		destRemote, destName, err = conf.ParseRemote(args[1])
		if err != nil {
			return err
		}
	}

	// As an optimization, if the source an destination are the same, do
	// this via a simple rename. This only works for instances that aren't
	// running, instances that are running should be live migrated (of
	// course, this changing of hostname isn't supported right now, so this
	// simply won't work).
	if sourceRemote == destRemote && c.flagTarget == "" && c.flagStorage == "" && c.flagTargetProject == "" {
		if c.flagConfig != nil || c.flagDevice != nil || c.flagProfile != nil || c.flagNoProfiles {
			return fmt.Errorf(i18n.G("Can't override configuration or profiles in local rename"))
		}

		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if shared.IsSnapshot(sourceName) {
			// Snapshot rename
			srcParent, srcSnap, _ := shared.InstanceGetParentAndSnapshotName(sourceName)
			dstParent, dstSnap, dstIsSnap := shared.InstanceGetParentAndSnapshotName(destName)

			if srcParent != dstParent {
				return fmt.Errorf("Invalid new snapshot name, parent must be the same as source")
			}

			if !dstIsSnap {
				return fmt.Errorf("Invalid new snapshot name")
			}

			op, err := source.RenameInstanceSnapshot(srcParent, srcSnap, api.InstanceSnapshotPost{Name: dstSnap})
			if err != nil {
				return err
			}

			return op.Wait()
		}

		// Instance rename
		op, err := source.RenameInstance(sourceName, api.InstancePost{Name: destName})
		if err != nil {
			return err
		}

		return op.Wait()
	}

	sourceResource := args[0]
	destResource := sourceResource
	if len(args) == 2 {
		destResource = args[1]
	}

	if c.flagTarget != "" {
		// If the target option was specified, we're moving an instance from a
		// cluster member to another, let's use the dedicated API.
		if sourceRemote == destRemote {
			if c.flagStateless {
				return fmt.Errorf(i18n.G("The --stateless flag can't be used with --target"))
			}

			if c.flagInstanceOnly {
				return fmt.Errorf(i18n.G("The --instance-only flag can't be used with --target"))
			}

			if c.flagStorage != "" {
				return fmt.Errorf(i18n.G("The --storage flag can't be used with --target"))
			}

			if c.flagMode != moveDefaultMode {
				return fmt.Errorf(i18n.G("The --mode flag can't be used with --target"))
			}

			return moveClusterInstance(conf, sourceResource, destResource, c.flagTarget, c.global.flagQuiet)
		}

		dest, err := conf.GetInstanceServer(destRemote)
		if err != nil {
			return err
		}

		if !dest.IsClustered() {
			return fmt.Errorf(i18n.G("The destination LXD server is not clustered"))
		}
	}

	stateful := !c.flagStateless

	// Support for server-side pool move.
	if c.flagStorage != "" && sourceRemote == destRemote {
		source, err := conf.GetInstanceServer(sourceRemote)
		if err != nil {
			return err
		}

		if source.HasExtension("instance_pool_move") {
			if c.flagMode != moveDefaultMode {
				return fmt.Errorf(i18n.G("The --mode flag can't be used with --storage"))
			}

			return moveInstancePool(conf, sourceResource, destResource, c.flagInstanceOnly, c.flagStorage, stateful)
		}
	}

	cpy := cmdCopy{}
	cpy.global = c.global
	cpy.flagTarget = c.flagTarget
	cpy.flagTargetProject = c.flagTargetProject
	cpy.flagConfig = c.flagConfig
	cpy.flagDevice = c.flagDevice
	cpy.flagProfile = c.flagProfile
	cpy.flagNoProfiles = c.flagNoProfiles

	instanceOnly := c.flagInstanceOnly

	// A move is just a copy followed by a delete; however, we want to
	// keep the volatile entries around since we are moving the instance.
	err = cpy.copyInstance(conf, sourceResource, destResource, true, -1, stateful, instanceOnly, mode, c.flagStorage, true)
	if err != nil {
		return err
	}

	del := cmdDelete{global: c.global}
	del.flagForce = true
	del.flagForceProtected = true
	err = del.Run(cmd, args[:1])
	if err != nil {
		return errors.Wrap(err, "Failed to delete original instance after copying it")
	}

	return nil
}

// Move an instance using special POST /instances/<name>?target=<member> API.
func moveClusterInstance(conf *config.Config, sourceResource string, destResource string, target string, quiet bool) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Check that it's a cluster
	if !source.IsClustered() {
		return fmt.Errorf(i18n.G("The source LXD server is not clustered"))
	}

	// The migrate API will do the right thing when passed a target.
	source = source.UseTarget(target)
	req := api.InstancePost{
		Name:      destName,
		Migration: true,
	}

	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	// Watch the background operation
	progress := utils.ProgressRenderer{
		Format: i18n.G("Transferring instance: %s"),
		Quiet:  quiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}
	// Wait for the move to complete
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return err
	}
	progress.Done("")

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Move an instance between pools using special POST /instances/<name> API.
func moveInstancePool(conf *config.Config, sourceResource string, destResource string, instanceOnly bool, storage string, stateful bool) error {
	// Parse the source.
	sourceRemote, sourceName, err := conf.ParseRemote(sourceResource)
	if err != nil {
		return err
	}

	// Parse the destination.
	_, destName, err := conf.ParseRemote(destResource)
	if err != nil {
		return err
	}

	// Make sure we have an instance or snapshot name.
	if sourceName == "" {
		return fmt.Errorf(i18n.G("You must specify a source instance name"))
	}

	// The destination name is optional.
	if destName == "" {
		destName = sourceName
	}

	// Connect to the source host
	source, err := conf.GetInstanceServer(sourceRemote)
	if err != nil {
		return errors.Wrap(err, i18n.G("Failed to connect to cluster member"))
	}

	// Pass the new pool to the migration API.
	req := api.InstancePost{
		Name:         destName,
		Migration:    true,
		Pool:         storage,
		InstanceOnly: instanceOnly,
		Live:         stateful,
	}

	op, err := source.MigrateInstance(sourceName, req)
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration API failure"))
	}

	err = op.Wait()
	if err != nil {
		return errors.Wrap(err, i18n.G("Migration operation failure"))
	}

	return nil
}

// Default migration mode when moving an instance.
const moveDefaultMode = "pull"
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/lxc/lxd/internal/gnuflag"
	"github.com/lxc/lxd/shared"
)

func main() {
	if err := run(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

var verbose = gnuflag.Bool("v", false, "Enables verbose mode.")
var debug = gnuflag.Bool("debug", false, "Enables debug mode.")
var listenAddr = gnuflag.String("tcp", "", "TCP address <addr:port> to listen on in addition to the unix socket (e.g., 127.0.0.1:8443)")
var group = gnuflag.String("group", "", "Group which owns the shared socket")
var help = gnuflag.Bool("help", false, "Print this help message.")
var version = gnuflag.Bool("version", false, "Print LXD's version number and exit.")

func init() {
	myGroup, err := shared.GroupName(os.Getgid())
	if err != nil {
		shared.Debugf("Problem finding default group %s", err)
	}
	*group = myGroup

	rand.Seed(time.Now().UTC().UnixNano())
}

func run() error {
	gnuflag.Usage = func() {
		fmt.Printf("Usage: lxd [options]\n\nOptions:\n")
		gnuflag.PrintDefaults()
	}

	gnuflag.Parse(true)
	if *help {
		// The user asked for help via --help, so we shouldn't print to
		// stderr.
		gnuflag.SetOut(os.Stdout)
		gnuflag.Usage()
		return nil
	}

	if *version {
		fmt.Println(shared.Version)
		return nil
	}

	if *verbose || *debug {
		shared.SetLogger(log.New(os.Stderr, "", log.LstdFlags))
		shared.SetDebug(*debug)
	}

	d, err := StartDaemon(*listenAddr)

	if err != nil {
		if d != nil && d.db != nil {
			d.db.Close()
		}
		return err
	}

	defer d.db.Close()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT)
	signal.Notify(ch, syscall.SIGTERM)
	<-ch
	return d.Stop()
}
<commit_msg>lxd: fail at startup if setfacl does not exist.<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"os/signal"
	"syscall"
	"time"

	"github.com/lxc/lxd/internal/gnuflag"
	"github.com/lxc/lxd/shared"
)

func main() {
	if err := run(); err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}
}

var verbose = gnuflag.Bool("v", false, "Enables verbose mode.")
var debug = gnuflag.Bool("debug", false, "Enables debug mode.")
var listenAddr = gnuflag.String("tcp", "", "TCP address <addr:port> to listen on in addition to the unix socket (e.g., 127.0.0.1:8443)")
var group = gnuflag.String("group", "", "Group which owns the shared socket")
var help = gnuflag.Bool("help", false, "Print this help message.")
var version = gnuflag.Bool("version", false, "Print LXD's version number and exit.")

func init() {
	myGroup, err := shared.GroupName(os.Getgid())
	if err != nil {
		shared.Debugf("Problem finding default group %s", err)
	}
	*group = myGroup

	rand.Seed(time.Now().UTC().UnixNano())
}

func run() error {
	gnuflag.Usage = func() {
		fmt.Printf("Usage: lxd [options]\n\nOptions:\n")
		gnuflag.PrintDefaults()
	}

	gnuflag.Parse(true)
	if *help {
		// The user asked for help via --help, so we shouldn't print to
		// stderr.
		gnuflag.SetOut(os.Stdout)
		gnuflag.Usage()
		return nil
	}

	if *version {
		fmt.Println(shared.Version)
		return nil
	}

	if *verbose || *debug {
		shared.SetLogger(log.New(os.Stderr, "", log.LstdFlags))
		shared.SetDebug(*debug)
	}

	needed_programs := []string{"setfacl", "rsync", "tar", "xz"}
	for _, p := range needed_programs {
		_, err := exec.LookPath(p)
		if err != nil {
			return err
		}
	}

	d, err := StartDaemon(*listenAddr)

	if err != nil {
		if d != nil && d.db != nil {
			d.db.Close()
		}
		return err
	}

	defer d.db.Close()

	ch := make(chan os.Signal)
	signal.Notify(ch, syscall.SIGINT)
	signal.Notify(ch, syscall.SIGTERM)
	<-ch
	return d.Stop()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"sync"

	"../dos"
	"../interpreter"
	"../lua"
)

const dbg = false

type LuaFunction struct {
	L            lua.Lua
	registoryKey string
}

var LuaInstanceToCmd = map[uintptr]*interpreter.Interpreter{}

func (this LuaFunction) String() string {
	return "<<Lua-function>>"
}

var mutex4dll sync.Mutex
var luaUsedOnThatPipeline = map[uint]uint{}

const ERRMSG_CAN_NOT_USE_TWO_LUA_ON = "Can not use two Lua-command on the same pipeline"
const ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND = "Can not run Lua-Command on background"

func (this LuaFunction) Call(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error) {
	if cmd.IsBackGround {
		fmt.Fprintf(os.Stderr, "%s: %s\n",
			cmd.Args[0],
			ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND)
		return interpreter.NOERROR,
			errors.New(ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND)
	}
	L := this.L
	seq := cmd.PipeSeq
	mutex4dll.Lock()
	if p, ok := luaUsedOnThatPipeline[seq[0]]; ok && p != seq[1] {
		mutex4dll.Unlock()
		fmt.Fprintf(os.Stderr, "%s: %s\n",
			cmd.Args[0],
			ERRMSG_CAN_NOT_USE_TWO_LUA_ON)
		return interpreter.NOERROR, errors.New(ERRMSG_CAN_NOT_USE_TWO_LUA_ON)
	}
	luaUsedOnThatPipeline[seq[0]] = seq[1]
	mutex4dll.Unlock()

	L.GetField(lua.LUA_REGISTRYINDEX, this.registoryKey)
	L.NewTable()
	for i, arg1 := range cmd.Args {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	save := LuaInstanceToCmd[L.State()]
	LuaInstanceToCmd[L.State()] = cmd
	err := L.Call(1, 1)
	errorlevel := interpreter.NOERROR
	if err == nil {
		newargs := make([]string, 0)
		if L.IsTable(-1) {
			L.PushInteger(0)
			L.GetTable(-2)
			if val, err1 := L.ToString(-1); val != "" && err1 == nil {
				newargs = append(newargs, val)
			}
			L.Pop(1)
			for i := 1; ; i++ {
				L.PushInteger(lua.Integer(i))
				L.GetTable(-2)
				if L.IsNil(-1) {
					L.Pop(1)
					break
				}
				val, err1 := L.ToString(-1)
				L.Pop(1)
				if err1 != nil {
					break
				}
				newargs = append(newargs, val)
			}
			it := cmd.Clone()
			it.Args = newargs
			errorlevel, err = it.Spawnvp()
		} else if val, err1 := L.ToInteger(-1); err1 == nil {
			errorlevel = interpreter.ErrorLevel(val)
		} else if val, err1 := L.ToString(-1); val != "" && err1 == nil {
			errorlevel, err = cmd.Clone().Interpret(val)
		}
	}
	L.Pop(1)
	LuaInstanceToCmd[this.L.State()] = save
	return errorlevel, err
}

const original_io_lines = "original_io_lines"

func ioLines(this lua.Lua) int {
	if this.IsString(1) {
		// io.lines("FILENAME") --> use original io.lines
		this.GetField(lua.LUA_REGISTRYINDEX, original_io_lines)
		this.PushValue(1)
		this.Call(1, 1)
	} else {
		// io.lines() --> use nyagos version
		this.PushGoFunction(ioLinesNext)
	}
	return 1
}

func ioLinesNext(this lua.Lua) int {
	cmd := LuaInstanceToCmd[this.State()]

	line := make([]byte, 0, 256)
	var ch [1]byte
	for {
		n, err := cmd.Stdin.Read(ch[0:1])
		if n <= 0 || err != nil {
			if len(line) <= 0 {
				this.PushNil()
			} else {
				this.PushAnsiString(line)
			}
			return 1
		}
		if ch[0] == '\n' {
			this.PushAnsiString(line)
			return 1
		}
		line = append(line, ch[0])
	}
}

var orgArgHook func(*interpreter.Interpreter, []string) []string

var newArgsHookLock sync.Mutex

func newArgHook(it *interpreter.Interpreter, args []string) []string {
	newArgsHookLock.Lock()
	defer newArgsHookLock.Unlock()

	if dbg {
		print("Enter newArgHook")
		for _, arg1 := range args {
			print("[", arg1, "]")
		}
		print("\n")
		defer print("Leave newArgHook\n")
	}
	L, Lok := it.Tag.(lua.Lua)
	if !Lok {
		panic("main/lua.go: can get interpreter instance")
	}
	pos := L.GetTop()
	defer L.SetTop(pos)
	L.GetGlobal("nyagos")
	L.GetField(-1, "argsfilter")
	if !L.IsFunction(-1) {
		return orgArgHook(it, args)
	}
	L.NewTable()
	for i := 0; i < len(args); i++ {
		L.PushString(args[i])
		L.RawSetI(-2, lua.Integer(i))
	}
	if err := L.Call(1, 1); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return orgArgHook(it, args)
	}
	if L.GetType(-1) != lua.LUA_TTABLE {
		return orgArgHook(it, args)
	}
	newargs := []string{}
	for i := lua.Integer(0); true; i++ {
		L.PushInteger(i)
		L.GetTable(-2)
		if L.GetType(-1) == lua.LUA_TNIL {
			break
		}
		arg1, arg1err := L.ToString(-1)
		if arg1err == nil {
			newargs = append(newargs, arg1)
		} else {
			fmt.Fprintln(os.Stderr, arg1err.Error())
		}
		L.Pop(1)
	}
	return orgArgHook(it, newargs)
}

var orgOnCommandNotFound func(*interpreter.Interpreter, error) error

func on_command_not_found(inte *interpreter.Interpreter, err error) error {
	L, Lok := inte.Tag.(lua.Lua)
	if !Lok {
		panic("on_command_not_found: Interpreter.Tag is not lua instance")
	}
	L.GetGlobal("nyagos")
	L.GetField(-1, "on_command_not_found")
	L.Remove(-2) // remove nyagos.
	if L.IsFunction(-1) {
		L.NewTable()
		for key, val := range inte.Args {
			L.PushString(val)
			L.RawSetI(-2, lua.Integer(key))
		}
		L.Call(1, 1)
		defer L.Pop(1)
		if L.ToBool(-1) {
			return nil
		} else {
			return orgOnCommandNotFound(inte, err)
		}
	} else {
		L.Pop(1)
		return orgOnCommandNotFound(inte, err)
	}
}

func SetLuaFunctions(this lua.Lua) {
	stackPos := this.GetTop()
	defer this.SetTop(stackPos)

	nyagos_table := map[string]interface{}{
		"access":       cmdAccess,
		"atou":         cmdAtoU,
		"bindkey":      cmdBindKey,
		"commonprefix": cmdCommonPrefix,
		"eval":         cmdEval,
		"exec":         cmdExec,
		"getalias":     cmdGetAlias,
		"getenv":       cmdGetEnv,
		"gethistory":   cmdGetHistory,
		"getkey":       cmdGetKey,
		"getviewwidth": cmdGetViewWidth,
		"getwd":        cmdGetwd,
		"glob":         cmdGlob,
		"pathjoin":     cmdPathJoin,
		"raweval":      cmdRawEval,
		"rawexec":      cmdRawExec,
		"setalias":     cmdSetAlias,
		"setenv":       cmdSetEnv,
		"setrunewidth": cmdSetRuneWidth,
		"shellexecute": cmdShellExecute,
		"stat":         cmdStat,
		"utoa":         cmdUtoA,
		"which":        cmdWhich,
		"write":        cmdWrite,
		"writerr":      cmdWriteErr,
	}
	if exeName, exeNameErr := dos.GetModuleFileName(); exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	} else {
		nyagos_table["exe"] = exeName
	}
	nyagos_table["goarch"] = runtime.GOARCH
	nyagos_table["goversion"] = runtime.Version()
	this.Push(nyagos_table)

	this.NewTable() // "nyagos.alias"
	this.NewTable() // metatable.
	this.PushGoFunction(cmdSetAlias)
	this.SetField(-2, "__call")
	this.PushGoFunction(cmdSetAlias)
	this.SetField(-2, "__newindex")
	this.PushGoFunction(cmdGetAlias)
	this.SetField(-2, "__index")
	this.SetMetaTable(-2)
	this.SetField(-2, "alias")

	this.NewTable() // "nyagos.env"
	this.NewTable() // metatable
	this.PushGoFunction(cmdSetEnv)
	this.SetField(-2, "__newindex")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "__index")
	this.SetMetaTable(-2)
	this.SetField(-2, "env")

	this.SetGlobal("nyagos")

	// replace os.getenv
	this.GetGlobal("os")           // +1
	this.PushGoFunction(cmdGetEnv) // +2
	this.SetField(-2, "getenv")    // +1
	this.Pop(1)                    // 0

	// save io.lines as original_io_lines
	this.GetGlobal("io")                                    // +1
	this.GetField(-1, "lines")                              // +2
	this.SetField(lua.LUA_REGISTRYINDEX, original_io_lines) // +1
	this.Pop(1)                                             // 0

	// replace io.lines
	this.GetGlobal("io")         // +1
	this.PushGoFunction(ioLines) // +2
	this.SetField(-2, "lines")   // +1
	this.Pop(1)                  // 0

	orgArgHook = interpreter.SetArgsHook(newArgHook)

	orgOnCommandNotFound = interpreter.OnCommandNotFound
	interpreter.OnCommandNotFound = on_command_not_found
}
<commit_msg>Fixed Interpreter instance was not given on nyagos.on_command_not_found. (for #83)<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"sync"

	"../dos"
	"../interpreter"
	"../lua"
)

const dbg = false

type LuaFunction struct {
	L            lua.Lua
	registoryKey string
}

var LuaInstanceToCmd = map[uintptr]*interpreter.Interpreter{}

func (this LuaFunction) String() string {
	return "<<Lua-function>>"
}

var mutex4dll sync.Mutex
var luaUsedOnThatPipeline = map[uint]uint{}

const ERRMSG_CAN_NOT_USE_TWO_LUA_ON = "Can not use two Lua-command on the same pipeline"
const ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND = "Can not run Lua-Command on background"

func (this LuaFunction) Call(cmd *interpreter.Interpreter) (interpreter.ErrorLevel, error) {
	if cmd.IsBackGround {
		fmt.Fprintf(os.Stderr, "%s: %s\n",
			cmd.Args[0],
			ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND)
		return interpreter.NOERROR,
			errors.New(ERRMSG_CAN_NOT_RUN_LUA_ON_BACKGROUND)
	}
	L := this.L
	seq := cmd.PipeSeq
	mutex4dll.Lock()
	if p, ok := luaUsedOnThatPipeline[seq[0]]; ok && p != seq[1] {
		mutex4dll.Unlock()
		fmt.Fprintf(os.Stderr, "%s: %s\n",
			cmd.Args[0],
			ERRMSG_CAN_NOT_USE_TWO_LUA_ON)
		return interpreter.NOERROR, errors.New(ERRMSG_CAN_NOT_USE_TWO_LUA_ON)
	}
	luaUsedOnThatPipeline[seq[0]] = seq[1]
	mutex4dll.Unlock()

	L.GetField(lua.LUA_REGISTRYINDEX, this.registoryKey)
	L.NewTable()
	for i, arg1 := range cmd.Args {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i))
	}
	save := LuaInstanceToCmd[L.State()]
	LuaInstanceToCmd[L.State()] = cmd
	err := L.Call(1, 1)
	errorlevel := interpreter.NOERROR
	if err == nil {
		newargs := make([]string, 0)
		if L.IsTable(-1) {
			L.PushInteger(0)
			L.GetTable(-2)
			if val, err1 := L.ToString(-1); val != "" && err1 == nil {
				newargs = append(newargs, val)
			}
			L.Pop(1)
			for i := 1; ; i++ {
				L.PushInteger(lua.Integer(i))
				L.GetTable(-2)
				if L.IsNil(-1) {
					L.Pop(1)
					break
				}
				val, err1 := L.ToString(-1)
				L.Pop(1)
				if err1 != nil {
					break
				}
				newargs = append(newargs, val)
			}
			it := cmd.Clone()
			it.Args = newargs
			errorlevel, err = it.Spawnvp()
		} else if val, err1 := L.ToInteger(-1); err1 == nil {
			errorlevel = interpreter.ErrorLevel(val)
		} else if val, err1 := L.ToString(-1); val != "" && err1 == nil {
			errorlevel, err = cmd.Clone().Interpret(val)
		}
	}
	L.Pop(1)
	LuaInstanceToCmd[this.L.State()] = save
	return errorlevel, err
}

const original_io_lines = "original_io_lines"

func ioLines(this lua.Lua) int {
	if this.IsString(1) {
		// io.lines("FILENAME") --> use original io.lines
		this.GetField(lua.LUA_REGISTRYINDEX, original_io_lines)
		this.PushValue(1)
		this.Call(1, 1)
	} else {
		// io.lines() --> use nyagos version
		this.PushGoFunction(ioLinesNext)
	}
	return 1
}

func ioLinesNext(this lua.Lua) int {
	cmd := LuaInstanceToCmd[this.State()]

	line := make([]byte, 0, 256)
	var ch [1]byte
	for {
		n, err := cmd.Stdin.Read(ch[0:1])
		if n <= 0 || err != nil {
			if len(line) <= 0 {
				this.PushNil()
			} else {
				this.PushAnsiString(line)
			}
			return 1
		}
		if ch[0] == '\n' {
			this.PushAnsiString(line)
			return 1
		}
		line = append(line, ch[0])
	}
}

var orgArgHook func(*interpreter.Interpreter, []string) []string

var newArgsHookLock sync.Mutex

func newArgHook(it *interpreter.Interpreter, args []string) []string {
	newArgsHookLock.Lock()
	defer newArgsHookLock.Unlock()

	if dbg {
		print("Enter newArgHook")
		for _, arg1 := range args {
			print("[", arg1, "]")
		}
		print("\n")
		defer print("Leave newArgHook\n")
	}
	L, Lok := it.Tag.(lua.Lua)
	if !Lok {
		panic("main/lua.go: can get interpreter instance")
	}
	pos := L.GetTop()
	defer L.SetTop(pos)
	L.GetGlobal("nyagos")
	L.GetField(-1, "argsfilter")
	if !L.IsFunction(-1) {
		return orgArgHook(it, args)
	}
	L.NewTable()
	for i := 0; i < len(args); i++ {
		L.PushString(args[i])
		L.RawSetI(-2, lua.Integer(i))
	}
	if err := L.Call(1, 1); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		return orgArgHook(it, args)
	}
	if L.GetType(-1) != lua.LUA_TTABLE {
		return orgArgHook(it, args)
	}
	newargs := []string{}
	for i := lua.Integer(0); true; i++ {
		L.PushInteger(i)
		L.GetTable(-2)
		if L.GetType(-1) == lua.LUA_TNIL {
			break
		}
		arg1, arg1err := L.ToString(-1)
		if arg1err == nil {
			newargs = append(newargs, arg1)
		} else {
			fmt.Fprintln(os.Stderr, arg1err.Error())
		}
		L.Pop(1)
	}
	return orgArgHook(it, newargs)
}

var orgOnCommandNotFound func(*interpreter.Interpreter, error) error

func on_command_not_found(inte *interpreter.Interpreter, err error) error {
	L, Lok := inte.Tag.(lua.Lua)
	if !Lok {
		panic("on_command_not_found: Interpreter.Tag is not lua instance")
	}
	L.GetGlobal("nyagos")
	L.GetField(-1, "on_command_not_found")
	L.Remove(-2) // remove nyagos.
	if L.IsFunction(-1) {
		L.NewTable()
		for key, val := range inte.Args {
			L.PushString(val)
			L.RawSetI(-2, lua.Integer(key))
		}
		save := LuaInstanceToCmd[L.State()]
		LuaInstanceToCmd[L.State()] = inte
		L.Call(1, 1)
		LuaInstanceToCmd[L.State()] = save
		defer L.Pop(1)
		if L.ToBool(-1) {
			return nil
		} else {
			return orgOnCommandNotFound(inte, err)
		}
	} else {
		L.Pop(1)
		return orgOnCommandNotFound(inte, err)
	}
}

func SetLuaFunctions(this lua.Lua) {
	stackPos := this.GetTop()
	defer this.SetTop(stackPos)

	nyagos_table := map[string]interface{}{
		"access":       cmdAccess,
		"atou":         cmdAtoU,
		"bindkey":      cmdBindKey,
		"commonprefix": cmdCommonPrefix,
		"eval":         cmdEval,
		"exec":         cmdExec,
		"getalias":     cmdGetAlias,
		"getenv":       cmdGetEnv,
		"gethistory":   cmdGetHistory,
		"getkey":       cmdGetKey,
		"getviewwidth": cmdGetViewWidth,
		"getwd":        cmdGetwd,
		"glob":         cmdGlob,
		"pathjoin":     cmdPathJoin,
		"raweval":      cmdRawEval,
		"rawexec":      cmdRawExec,
		"setalias":     cmdSetAlias,
		"setenv":       cmdSetEnv,
		"setrunewidth": cmdSetRuneWidth,
		"shellexecute": cmdShellExecute,
		"stat":         cmdStat,
		"utoa":         cmdUtoA,
		"which":        cmdWhich,
		"write":        cmdWrite,
		"writerr":      cmdWriteErr,
	}
	if exeName, exeNameErr := dos.GetModuleFileName(); exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	} else {
		nyagos_table["exe"] = exeName
	}
	nyagos_table["goarch"] = runtime.GOARCH
	nyagos_table["goversion"] = runtime.Version()
	this.Push(nyagos_table)

	this.NewTable() // "nyagos.alias"
	this.NewTable() // metatable.
	this.PushGoFunction(cmdSetAlias)
	this.SetField(-2, "__call")
	this.PushGoFunction(cmdSetAlias)
	this.SetField(-2, "__newindex")
	this.PushGoFunction(cmdGetAlias)
	this.SetField(-2, "__index")
	this.SetMetaTable(-2)
	this.SetField(-2, "alias")

	this.NewTable() // "nyagos.env"
	this.NewTable() // metatable
	this.PushGoFunction(cmdSetEnv)
	this.SetField(-2, "__newindex")
	this.PushGoFunction(cmdGetEnv)
	this.SetField(-2, "__index")
	this.SetMetaTable(-2)
	this.SetField(-2, "env")

	this.SetGlobal("nyagos")

	// replace os.getenv
	this.GetGlobal("os")           // +1
	this.PushGoFunction(cmdGetEnv) // +2
	this.SetField(-2, "getenv")    // +1
	this.Pop(1)                    // 0

	// save io.lines as original_io_lines
	this.GetGlobal("io")                                    // +1
	this.GetField(-1, "lines")                              // +2
	this.SetField(lua.LUA_REGISTRYINDEX, original_io_lines) // +1
	this.Pop(1)                                             // 0

	// replace io.lines
	this.GetGlobal("io")         // +1
	this.PushGoFunction(ioLines) // +2
	this.SetField(-2, "lines")   // +1
	this.Pop(1)                  // 0

	orgArgHook = interpreter.SetArgsHook(newArgHook)

	orgOnCommandNotFound = interpreter.OnCommandNotFound
	interpreter.OnCommandNotFound = on_command_not_found
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/dynport/dgtk/github"
	"github.com/dynport/gocli"
)

type Status struct {
	WithURLs bool   `cli:"opt --with-urls"`
	Open     bool   `cli:"opt --open"`
	Branch   string `cli:"opt --branch"`
	Wait     bool   `cli:"opt --wait"`
}

func (r *Status) Run() error {
	var branches []string
	if r.Branch != "" {
		branches = []string{r.Branch}
	} else {
		branches = []string{"master"}
		if cb, err := currentBranch(); err == nil && cb != "master" {
			branches = append([]string{cb}, "master")
		}
	}
	repo, err := githubRepo()
	if err != nil {
		return err
	}
	cl, err := client()
	if err != nil {
		return err
	}

	l := log.New(os.Stderr, "", 0)

	if r.Wait {
		branch := r.Branch
		if branch == "" {
			branch, err = currentBranch()
			if err != nil {
				return err
			}
		}
		var printedURL bool
		for {
			s, err := loadStatus(cl, repo, branch)
			if err != nil {
				l.Printf("error fetching status: %s", err)
			} else {
				if s.State != statePending {
					fmt.Println(s.State)
					if s.State == stateSuccess {
						return nil
					}
					return fmt.Errorf("not successful (%s)", s.State)
				}
				if !printedURL && len(s.Statuses) > 0 {
					l.Printf("url=%s", s.Statuses[0].TargetURL)
					printedURL = true
				}
			}
			time.Sleep(10 * time.Second)
		}
		return nil
	}

	type status struct {
		Time   time.Time
		Branch string
		URL    string
		Status string
		SHA    string
	}

	t := gocli.NewTable()
	all := []*status{}
	agoFunc := func(t time.Time) string { return strings.Split(time.Since(t).String(), ".")[0] }
	for _, b := range branches {
		st := &status{Branch: b}
		all = append(all, st)
		if s, err := loadStatus(cl, repo, b); err != nil {
			if isNotFound(err) {
				st.Status = "not_found"
			} else {
				return err
			}
		} else {
			st.Status = s.State
			st.SHA = s.SHA
			sm := map[string]int{}
			for _, s := range s.Statuses {
				sm[s.State]++
			}
			if sm["failed"] > 0 {
				st.Status = "failed"
			} else if sm["pending"] > 0 {
				st.Status = "pending"
			} else {
				st.Status = "success"
			}
			t.Add(string(b), colorizeStatus(st.Status))
			if len(s.Statuses) > 0 {
				for _, ss := range s.Statuses {
					args := []interface{}{"", colorizeStatus(ss.State), truncate(s.SHA, 8, false), ss.Context, agoFunc(ss.CreatedAt)}
					if r.WithURLs {
						args = append(args, ss.TargetURL)
					}
					t.Add(args...)
				}
			}
		}
	}

	if r.Open {
		if len(all) == 0 {
			return fmt.Errorf("no status found")
		}
		s := all[0]
		if s.URL == "" {
			return fmt.Errorf("status has no url (yet?)")
		}
		return openUrl(s.URL)
	}

	fmt.Println(t)
	return nil
}

func isNotFound(err error) bool {
	return err != nil && strings.Contains(err.Error(), "404 Not Found")
}

const (
	stateSuccess  = "success"
	statePending  = "pending"
	stateNotFound = "not_found"
)

func colorizeStatus(in string) string {
	color := gocli.Green
	switch in {
	case stateSuccess:
		color = gocli.Green
	case statePending, stateNotFound:
		color = gocli.Yellow
	default:
		color = gocli.Red
	}
	return color(in)
}

func loadStatus(cl *github.Client, repo, ref string) (res *statusResponse, err error) {
	u := "https://api.github.com/repos/" + repo + "/commits/" + ref + "/status"
	rsp, err := cl.Get(u)
	if err != nil {
		return nil, err
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		b, _ := ioutil.ReadAll(rsp.Body)
		return nil, fmt.Errorf("got status %s but expected 2x. body=%s", rsp.Status, string(b))
	}
	err = json.NewDecoder(rsp.Body).Decode(&res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

func currentBranch() (string, error) {
	b, err := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").CombinedOutput()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(b)), nil
}

type statusResponse struct {
	State    string `json:"state"`
	Statuses []*struct {
		State     string    `json:"state,omitempty"`
		URL       string    `json:"url,omitempty"`
		Context   string    `json:"context"`
		TargetURL string    `json:"target_url,omitempty"`
		CreatedAt time.Time `json:"created_at,omitempty"`
		UpdatedAt time.Time `json:"updated_at,omitempty"`
	} `json:"statuses"`
	SHA string `json:"sha"`
}

// to be used to colorize
func dataOn(f *os.File) bool {
	stat, err := f.Stat()
	if err != nil {
		return false
	}
	return (stat.Mode() & os.ModeCharDevice) == 0
}
<commit_msg>gh: exit with != 0 on failures<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/dynport/dgtk/github"
	"github.com/dynport/gocli"
	"github.com/pkg/errors"
)

type Status struct {
	WithURLs bool   `cli:"opt --with-urls"`
	Open     bool   `cli:"opt --open"`
	Branch   string `cli:"opt --branch"`
	Wait     bool   `cli:"opt --wait"`
}

func (r *Status) Run() error {
	var branches []string
	if r.Branch != "" {
		branches = []string{r.Branch}
	} else {
		branches = []string{"master"}
		if cb, err := currentBranch(); err == nil && cb != "master" {
			branches = append([]string{cb}, "master")
		}
	}
	repo, err := githubRepo()
	if err != nil {
		return err
	}
	cl, err := client()
	if err != nil {
		return err
	}

	l := log.New(os.Stderr, "", 0)

	if r.Wait {
		branch := r.Branch
		if branch == "" {
			branch, err = currentBranch()
			if err != nil {
				return err
			}
		}
		var printedURL bool
		for {
			s, err := loadStatus(cl, repo, branch)
			if err != nil {
				l.Printf("error fetching status: %s", err)
			} else {
				if s.State != statePending {
					fmt.Println(s.State)
					if s.State == stateSuccess {
						return nil
					}
					return fmt.Errorf("not successful (%s)", s.State)
				}
				if !printedURL && len(s.Statuses) > 0 {
					l.Printf("url=%s", s.Statuses[0].TargetURL)
					printedURL = true
				}
			}
			time.Sleep(10 * time.Second)
		}
		return nil
	}

	type status struct {
		Time   time.Time
		Branch string
		URL    string
		Status string
		SHA    string
	}

	t := gocli.NewTable()
	all := []*status{}
	failures := 0
	agoFunc := func(t time.Time) string { return strings.Split(time.Since(t).String(), ".")[0] }
	for _, b := range branches {
		st := &status{Branch: b}
		all = append(all, st)
		if s, err := loadStatus(cl, repo, b); err != nil {
			if isNotFound(err) {
				st.Status = "not_found"
			} else {
				return err
			}
		} else {
			st.Status = s.State
			st.SHA = s.SHA
			sm := map[string]int{}
			for _, s := range s.Statuses {
				sm[s.State]++
			}
			if sm["failure"] > 0 {
				st.Status = "failure"
				failures++
			} else if sm["pending"] > 0 {
				st.Status = "pending"
			} else {
				st.Status = "success"
			}
			t.Add(string(b), colorizeStatus(st.Status))
			if len(s.Statuses) > 0 {
				for _, ss := range s.Statuses {
					args := []interface{}{"", colorizeStatus(ss.State), truncate(s.SHA, 8, false), ss.Context, agoFunc(ss.CreatedAt)}
					if r.WithURLs {
						args = append(args, ss.TargetURL)
					}
					t.Add(args...)
				}
			}
		}
	}

	if r.Open {
		if len(all) == 0 {
			return fmt.Errorf("no status found")
		}
		s := all[0]
		if s.URL == "" {
			return fmt.Errorf("status has no url (yet?)")
		}
		return openUrl(s.URL)
	}
	fmt.Println(t)
	if failures > 0 {
		return errors.Errorf("%d failures", failures)
	}
	return nil
}

func isNotFound(err error) bool {
	return err != nil && strings.Contains(err.Error(), "404 Not Found")
}

const (
	stateSuccess  = "success"
	statePending  = "pending"
	stateNotFound = "not_found"
)

func colorizeStatus(in string) string {
	color := gocli.Green
	switch in {
	case stateSuccess:
		color = gocli.Green
	case statePending, stateNotFound:
		color = gocli.Yellow
	default:
		color = gocli.Red
	}
	return color(in)
}

func loadStatus(cl *github.Client, repo, ref string) (res *statusResponse, err error) {
	u := "https://api.github.com/repos/" + repo + "/commits/" + ref + "/status"
	rsp, err := cl.Get(u)
	if err != nil {
		return nil, err
	}
	defer rsp.Body.Close()
	if rsp.Status[0] != '2' {
		b, _ := ioutil.ReadAll(rsp.Body)
		return nil, fmt.Errorf("got status %s but expected 2x. body=%s", rsp.Status, string(b))
	}
	err = json.NewDecoder(rsp.Body).Decode(&res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

func currentBranch() (string, error) {
	b, err := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").CombinedOutput()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(b)), nil
}

type statusResponse struct {
	State    string `json:"state"`
	Statuses []*struct {
		State     string    `json:"state,omitempty"`
		URL       string    `json:"url,omitempty"`
		Context   string    `json:"context"`
		TargetURL string    `json:"target_url,omitempty"`
		CreatedAt time.Time `json:"created_at,omitempty"`
		UpdatedAt time.Time `json:"updated_at,omitempty"`
	} `json:"statuses"`
	SHA string `json:"sha"`
}

// to be used to colorize
func dataOn(f *os.File) bool {
	stat, err := f.Stat()
	if err != nil {
		return false
	}
	return (stat.Mode() & os.ModeCharDevice) == 0
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			cmd.Process.Kill()
			log.Println("\t kill successful...")
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	// avoid librtlsdr error code inconsistency, i.e.
	// error code -2 means the stored value is the same as
	// the PPM value we sent (dev->corr == PPM)
	if freqCorr != globalSettings.PPM
		err = u.dev.SetFreqCorrection(globalSettings.PPM)
		if err != nil{
			// just print a warning
			log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		} else {
			log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
		}
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("doing cleanup...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			log.Println("globalSettings.UAT_Enabled == true")
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				log.Println("\tUATDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						log.Printf("UATDev = &UAT{indexID: id} failed: %s\n", err)
						UATDev = nil
					} else {
						if UATDev == nil {
							log.Println("XXXXXXX UATDev == nil this shouldn't be nil")
						}
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			log.Println("globalSettings.ES_Enabled == true")
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				log.Println("\tESDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						log.Printf("ESDev = &ES{indexID: id} failed: %s\n", err)
						ESDev = nil
					} else {
						if ESDev == nil {
							log.Println("XXXXXXX ESDev == nil this shouldn't be nil")
						}
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<commit_msg>add missing curley brace<commit_after>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			cmd.Process.Kill()
			log.Println("\t kill successful...")
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	// avoid librtlsdr error code inconsistency, i.e.
	// error code -2 means the stored value is the same as
	// the PPM value we sent (dev->corr == PPM)
	if freqCorr != globalSettings.PPM {
		err = u.dev.SetFreqCorrection(globalSettings.PPM)
		if err != nil {
			// just print a warning
			log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		} else {
			log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
		}
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("doing cleanup...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			log.Println("globalSettings.UAT_Enabled == true")
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				log.Println("\tUATDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						log.Printf("UATDev = &UAT{indexID: id} failed: %s\n", err)
						UATDev = nil
					} else {
						if UATDev == nil {
							log.Println("XXXXXXX UATDev == nil this shouldn't be nil")
						}
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			log.Println("globalSettings.ES_Enabled == true")
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				log.Println("\tESDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						log.Printf("ESDev = &ES{indexID: id} failed: %s\n", err)
						ESDev = nil
					} else {
						if ESDev == nil {
							log.Println("XXXXXXX ESDev == nil this shouldn't be nil")
						}
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Editor: 1.7.0; Desktop: 1.0.5"

	app.Flags = []cli.Flag{
		&cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		&cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
		&cli.IntFlag{
			Name: "port",
			Value: 8000,
			Usage: "TCP port to listen on",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Printf("Exposing Maputnik on http://localhost:%d\n", c.Int("port"))
		return http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), corsRouter)
	}

	app.Run(os.Args)
}
<commit_msg>Update desktop version number<commit_after>package main

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/maputnik/desktop/filewatch"
	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "maputnik"
	app.Usage = "Server for integrating Maputnik locally"
	app.Version = "Editor: 1.7.0; Desktop: 1.0.6"

	app.Flags = []cli.Flag{
		&cli.StringFlag{
			Name:  "file, f",
			Usage: "Allow access to JSON style from web client",
		},
		&cli.BoolFlag{
			Name:  "watch",
			Usage: "Notify web client about JSON style file changes",
		},
		&cli.IntFlag{
			Name: "port",
			Value: 8000,
			Usage: "TCP port to listen on",
		},
	}

	app.Action = func(c *cli.Context) error {
		gui := http.FileServer(assetFS())

		router := mux.NewRouter().StrictSlash(true)

		filename := c.String("file")
		if filename != "" {
			fmt.Printf("%s is accessible via Maputnik\n", filename)
			// Allow access to reading and writing file on the local system
			path, _ := filepath.Abs(filename)
			accessor := StyleFileAccessor(path)
			router.Path("/styles").Methods("GET").HandlerFunc(accessor.ListFiles)
			router.Path("/styles/{styleId}").Methods("GET").HandlerFunc(accessor.ReadFile)
			router.Path("/styles/{styleId}").Methods("PUT").HandlerFunc(accessor.SaveFile)

			// Register websocket to notify we clients about file changes
			if c.Bool("watch") {
				router.Path("/ws").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					filewatch.ServeWebsocketFileWatcher(filename, w, r)
				})
			}
		}

		router.PathPrefix("/").Handler(http.StripPrefix("/", gui))
		loggedRouter := handlers.LoggingHandler(os.Stdout, router)
		corsRouter := handlers.CORS(handlers.AllowedHeaders([]string{"Content-Type"}), handlers.AllowedMethods([]string{"GET", "PUT"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowCredentials())(loggedRouter)

		fmt.Printf("Exposing Maputnik on http://localhost:%d\n", c.Int("port"))
		return http.ListenAndServe(fmt.Sprintf(":%d", c.Int("port")), corsRouter)
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
   "fmt"
   "errors"
   "log"
    "./lib/server"
    "./lib/config"
	"./lib/logger"
    "time"
    "os"
	"hash/crc32"
    "strconv"
    "net"
    "runtime"
	"strings"
	"github.com/streamrail/concurrent-map"
)

var(
	conf = new(config.Configuration)
)

type Hash func(data []byte) uint32
type client struct {
    s *server.UDPServer
    load_balancer *net.UDPAddr
    frontend *net.UDPAddr
	lease time.Time
    sCh chan bool
    ttl time.Duration
    index  cmap.ConcurrentMap
	log *log.Logger
	hash Hash
}

func (c *client) Init() (error) {
    var err error

    c.s = new(server.UDPServer)
    c.s.Init(conf.ClientPort)
	c.hash = crc32.ChecksumIEEE

	c.log.Print(conf.LB[0] + conf.LBPort)
    c.load_balancer, err = net.ResolveUDPAddr("udp", conf.LB[0] + conf.LBPort)
    if err != nil {
        return err
    }

    c.sCh = make(chan bool)
    // index data structure
    c.index = cmap.New()

    // start listing to udp stream
    go c.recive()

	c.s.Write([]byte("new_lease"), c.load_balancer)
	c.log.Print("waiting for lb")

	// wait for conformation about frontend
	if ok := <- c.sCh; ok {
		c.log.Print("GOT " , c.frontend.String(), "as frontend")
		c.ttl = time.Duration(conf.ClientInitTTL) * time.Millisecond
		return nil
	} else {
		return errors.New("Could not contact the LoadBalancer")
	}
}

func (c *client) recive() {

    for {
        msg, remoteAddr, err := c.s.Read(64)
        if err != nil {
            c.log.Fatal()
        }
		//log.Print("MSG: ", string(msg))
		if remoteAddr.String() == c.load_balancer.String() {
			lease := strings.Split(string(msg), " ")
			c.frontend, err = net.ResolveUDPAddr("udp", lease[0])
			if err != nil {
				c.log.Fatal(err)
			}
			c.lease, err  = time.Parse(time.UnixDate, strings.Join(lease[1:], " "))
			if err != nil {
				c.log.Fatal(err)
			}
			c.sCh <- true
		} else if remoteAddr.String() == c.frontend.String() {
			t1 := time.Now()
			if val, ok := c.index.Get(string(msg)); ok {

				/* Start a goroutine to remove the key from trie */
				go func() {
					c.index.Remove(string(msg))
				}()

				expire, _ := val.(time.Time)
				if expire.After(t1) {
					c.ttl -= c.ttl/16
					fmt.Printf("\x1b[32;1m■")
					//log.Print(string(fetchedKey), ": ok - current ttl: ", c.ttl)
				} else {
					c.ttl += c.ttl/4
					fmt.Printf("\x1b[0m■")
					//log.Print(string(fetchedKey), "ttl failed by:", t1.Sub(expire))
				}
			}
        }
    }
}

func (c *client) Request(count int) int{
    hostname, err := os.Hostname()
	if err != nil {
		c.log.Fatal(err)
	}
	ip, err := net.LookupIP(hostname)
	if err != nil {
		c.log.Fatal(err)
	}
    timeout := make(chan []byte, 100)
    go c.TimeoutMonitor(timeout)

    for i := count; ;i++{
        key := []byte(strconv.FormatUint(uint64(c.hash(ip[0])), 10) + " " + strconv.Itoa(i))
        ttl := time.Now().Add(c.ttl)
        go func() {
            tKey := key
            time.Sleep(c.ttl)
            timeout <- tKey
        }()

        c.index.Set(string(key),ttl)
        //log.Print("Sent: ", key, "- expire: ", ttl)
        fmt.Printf("\x1b[34;1m■")
        c.s.Write(key, c.frontend)

		time.Sleep(2 * time.Second)

		t1 := time.Now()
		if c.lease.After(t1) {
			continue
		} else {
			return i + 1
		}
    }
}

func(c *client) TimeoutMonitor(ch chan []byte) {
    for {
        signal := <-ch
        if _, ok := c.index.Get(string(signal)); ok {
            fmt.Printf("\x1b[31;1m■")
            c.ttl = c.ttl + c.ttl/10
            //log.Print("TimeOut")
        }
    }
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())

    err := conf.GetConfig("config.json")
    if err != nil {
		log.Fatal(err)
	}

    c := new(client)

	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}

	c.log, err = logger.InitLogger("logs/client/" + hostname)
	if err != nil {
		log.Fatal(err)
	}

	err = c.Init()
	if err != nil {
		c.log.Fatal(err)
	}

    c.log.Print("start requesting")
	count := 0
	for {
		count = c.Request(count)
		c.log.Print("Lease ran out!")
		c.s.Write([]byte("new_lease"), c.load_balancer)
		if ok := <- c.sCh; ok {
			c.log.Print("new frontend: ", c.frontend.String())
			continue
		}
	}

}
<commit_msg>added aliases for color codes<commit_after>package main

import (
   "fmt"
   "errors"
   "log"
    "./lib/server"
    "./lib/config"
	"./lib/logger"
    "time"
    "os"
	"hash/crc32"
    "strconv"
    "net"
    "runtime"
	"strings"
	"github.com/streamrail/concurrent-map"
)

var(
	conf = new(config.Configuration)

	BLUE string = "\033[94m"
	GREEN string = "\033[92m"
	RED string = "\033[91m"
	ENDC string = "\033[0m"
)

type Hash func(data []byte) uint32
type client struct {
    s *server.UDPServer
    load_balancer *net.UDPAddr
    frontend *net.UDPAddr
	lease time.Time
    sCh chan bool
    ttl time.Duration
    index  cmap.ConcurrentMap
	log *log.Logger
	hash Hash
}

func (c *client) Init() (error) {
    var err error

    c.s = new(server.UDPServer)
    c.s.Init(conf.ClientPort)
	c.hash = crc32.ChecksumIEEE

	c.log.Print(conf.LB[0] + conf.LBPort)
    c.load_balancer, err = net.ResolveUDPAddr("udp", conf.LB[0] + conf.LBPort)
    if err != nil {
        return err
    }

    c.sCh = make(chan bool)
    // index data structure
    c.index = cmap.New()

    // start listing to udp stream
    go c.recive()

	c.s.Write([]byte("new_lease"), c.load_balancer)
	c.log.Print("waiting for lb")

	// wait for conformation about frontend
	if ok := <- c.sCh; ok {
		c.log.Print("GOT " , c.frontend.String(), "as frontend")
		c.ttl = time.Duration(conf.ClientInitTTL) * time.Millisecond
		return nil
	} else {
		return errors.New("Could not contact the LoadBalancer")
	}
}

func (c *client) recive() {

    for {
        msg, remoteAddr, err := c.s.Read(64)
        if err != nil {
            c.log.Fatal()
        }
		//log.Print("MSG: ", string(msg))
		if remoteAddr.String() == c.load_balancer.String() {
			lease := strings.Split(string(msg), " ")
			c.frontend, err = net.ResolveUDPAddr("udp", lease[0])
			if err != nil {
				c.log.Fatal(err)
			}
			c.lease, err  = time.Parse(time.UnixDate, strings.Join(lease[1:], " "))
			if err != nil {
				c.log.Fatal(err)
			}
			c.sCh <- true
		} else if remoteAddr.String() == c.frontend.String() {
			t1 := time.Now()
			if val, ok := c.index.Get(string(msg)); ok {

				/* Start a goroutine to remove the key from trie */
				go func() {
					c.index.Remove(string(msg))
				}()

				expire, _ := val.(time.Time)
				if expire.After(t1) {
					c.ttl -= c.ttl/16
					fmt.Printf(GREEN + "■" + ENDC)
					//log.Print(string(fetchedKey), ": ok - current ttl: ", c.ttl)
				} else {
					c.ttl += c.ttl/4
					fmt.Printf("■")
					//log.Print(string(fetchedKey), "ttl failed by:", t1.Sub(expire))
				}
			}
        }
    }
}

func (c *client) Request(count int) int{
    hostname, err := os.Hostname()
	if err != nil {
		c.log.Fatal(err)
	}
	ip, err := net.LookupIP(hostname)
	if err != nil {
		c.log.Fatal(err)
	}
    timeout := make(chan []byte, 100)
    go c.TimeoutMonitor(timeout)

    for i := count; ;i++{
        key := []byte(strconv.FormatUint(uint64(c.hash(ip[0])), 10) + " " + strconv.Itoa(i))
        ttl := time.Now().Add(c.ttl)
        go func() {
            tKey := key
            time.Sleep(c.ttl)
            timeout <- tKey
        }()

        c.index.Set(string(key),ttl)
        //log.Print("Sent: ", key, "- expire: ", ttl)
        fmt.Printf(BLUE + "■" + ENDC)
        c.s.Write(key, c.frontend)

		time.Sleep(2 * time.Second)

		t1 := time.Now()
		if c.lease.After(t1) {
			continue
		} else {
			return i + 1
		}
    }
}

func(c *client) TimeoutMonitor(ch chan []byte) {
    for {
        signal := <-ch
        if _, ok := c.index.Get(string(signal)); ok {
            fmt.Printf(RED + "■" + ENDC)
            c.ttl = c.ttl + c.ttl/10
            //log.Print("TimeOut")
        }
    }
}

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())

    err := conf.GetConfig("config.json")
    if err != nil {
		log.Fatal(err)
	}

    c := new(client)

	hostname, err := os.Hostname()
	if err != nil {
		log.Fatal(err)
	}

	c.log, err = logger.InitLogger("logs/client/" + hostname)
	if err != nil {
		log.Fatal(err)
	}

	err = c.Init()
	if err != nil {
		c.log.Fatal(err)
	}

    c.log.Print("start requesting")
	count := 0
	for {
		count = c.Request(count)
		c.log.Print("Lease ran out!")
		c.s.Write([]byte("new_lease"), c.load_balancer)
		if ok := <- c.sCh; ok {
			c.log.Print("new frontend: ", c.frontend.String())
			continue
		}
	}

}
<|endoftext|>


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

package state

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
	"time"
)

func TestScoreMapSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type ScoreMapSaverTest struct {
	sourceMap  ScoreMap
	sinkMap    ScoreMap
	fileSystem mock_fs.MockFileSystem
	wrapped    mock_backup.MockFileSaver
	now        time.Time
	nowFunc    func () time.Time

	saver      backup.FileSaver

	path   string
	scores []blob.Score
	err    error
}

func init() { RegisterTestSuite(&ScoreMapSaverTest{}) }

func (t *ScoreMapSaverTest) SetUp(i *TestInfo) {
	t.sourceMap = NewScoreMap()
	t.sinkMap = NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.nowFunc = func () time.Time { return t.now }

	t.saver = newScoreMapFileSaver(
		t.sourceMap,
		t.sinkMap,
		t.fileSystem,
		t.wrapped,
		t.nowFunc,
	)
}

func (t *ScoreMapSaverTest) call() {
	t.scores, t.err = t.saver.Save(t.path)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *ScoreMapSaverTest) CallsStat() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")("taco").
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("")))

	// Call
	t.call()
}

func (t *ScoreMapSaverTest) StatReturnsError() {
	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("taco")))

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("Stat")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *ScoreMapSaverTest) ScoreMapContainsEntry() {
	t.path = "taco"

	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// Source map
	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	t.sourceMap.Set(expectedKey, expectedScores)

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, DeepEquals(expectedScores))
	ExpectThat(t.sinkMap.Get(expectedKey), DeepEquals(expectedScores))
}

func (t *ScoreMapSaverTest) CallsWrapped() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, nil))

	// Wrapped
	ExpectCall(t.wrapped, "Save")("taco").
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *ScoreMapSaverTest) WrappedReturnsError() {
	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Wrapped
	ExpectCall(t.wrapped, "Save")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.call()

	AssertThat(t.err, Error(Equals("taco")))
	ExpectEq(nil, t.sinkMap.Get(expectedKey))
}

func (t *ScoreMapSaverTest) WrappedReturnsScores() {
	t.path = "taco"
	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Wrapped
	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	ExpectCall(t.wrapped, "Save")(Any()).
		WillOnce(oglemock.Return(expectedScores, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.sinkMap.Get(expectedKey), DeepEquals(expectedScores))
}
<commit_msg>Added some test stubs.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package state

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
	"time"
)

func TestScoreMapSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type ScoreMapSaverTest struct {
	sourceMap  ScoreMap
	sinkMap    ScoreMap
	fileSystem mock_fs.MockFileSystem
	wrapped    mock_backup.MockFileSaver
	now        time.Time
	nowFunc    func () time.Time

	saver      backup.FileSaver

	path   string
	scores []blob.Score
	err    error
}

func init() { RegisterTestSuite(&ScoreMapSaverTest{}) }

func (t *ScoreMapSaverTest) SetUp(i *TestInfo) {
	t.sourceMap = NewScoreMap()
	t.sinkMap = NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.nowFunc = func () time.Time { return t.now }

	t.saver = newScoreMapFileSaver(
		t.sourceMap,
		t.sinkMap,
		t.fileSystem,
		t.wrapped,
		t.nowFunc,
	)
}

func (t *ScoreMapSaverTest) call() {
	t.scores, t.err = t.saver.Save(t.path)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *ScoreMapSaverTest) CallsStat() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")("taco").
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("")))

	// Call
	t.call()
}

func (t *ScoreMapSaverTest) StatReturnsError() {
	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("taco")))

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("Stat")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *ScoreMapSaverTest) MTimeInFuture() {
	ExpectEq("TODO", "")
}

func (t *ScoreMapSaverTest) MTimeInRecentPast() {
	ExpectEq("TODO", "")
}

func (t *ScoreMapSaverTest) ScoreMapContainsEntry() {
	t.path = "taco"

	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// Source map
	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	t.sourceMap.Set(expectedKey, expectedScores)

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, DeepEquals(expectedScores))
	ExpectThat(t.sinkMap.Get(expectedKey), DeepEquals(expectedScores))
}

func (t *ScoreMapSaverTest) CallsWrapped() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, nil))

	// Wrapped
	ExpectCall(t.wrapped, "Save")("taco").
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *ScoreMapSaverTest) WrappedReturnsError() {
	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Wrapped
	ExpectCall(t.wrapped, "Save")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	t.call()

	AssertThat(t.err, Error(Equals("taco")))
	ExpectEq(nil, t.sinkMap.Get(expectedKey))
}

func (t *ScoreMapSaverTest) WrappedReturnsScores() {
	t.path = "taco"
	expectedKey := ScoreMapKey{
		Path:        "taco",
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       time.Now(),
		Inode:       23,
		Size:        29,
	}

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid:         17,
		Gid:         19,
		MTime:       expectedKey.MTime,
		Inode:       23,
		Size:        29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Wrapped
	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	ExpectCall(t.wrapped, "Save")(Any()).
		WillOnce(oglemock.Return(expectedScores, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.sinkMap.Get(expectedKey), DeepEquals(expectedScores))
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/dag"
)

// GraphNodeExapndable is an interface that nodes can implement to
// signal that they can be expanded. Expanded nodes turn into
// GraphNodeSubgraph nodes within the graph.
type GraphNodeExpandable interface {
	Expand(GraphBuilder) (GraphNodeSubgraph, error)
}

// GraphNodeDynamicExpandable is an interface that nodes can implement
// to signal that they can be expanded at eval-time (hence dynamic).
// These nodes are given the eval context and are expected to return
// a new subgraph.
type GraphNodeDynamicExpandable interface {
	DynamicExpand(EvalContext) (*Graph, error)
}

// GraphNodeSubgraph is an interface a node can implement if it has
// a larger subgraph that should be walked.
type GraphNodeSubgraph interface {
	Subgraph() dag.Grapher
}

// ExpandTransform is a transformer that does a subgraph expansion
// at graph transform time (vs. at eval time). The benefit of earlier
// subgraph expansion is that errors with the graph build can be detected
// at an earlier stage.
type ExpandTransform struct {
	Builder GraphBuilder
}

func (t *ExpandTransform) Transform(v dag.Vertex) (dag.Vertex, error) {
	ev, ok := v.(GraphNodeExpandable)
	if !ok {
		// This isn't an expandable vertex, so just ignore it.
		return v, nil
	}

	// Expand the subgraph!
	log.Printf("[DEBUG] vertex %q: static expanding", dag.VertexName(ev))
	return ev.Expand(t.Builder)
}

type GraphNodeBasicSubgraph struct {
	NameValue string
	Graph     *Graph
}

func (n *GraphNodeBasicSubgraph) Name() string {
	return n.NameValue
}

func (n *GraphNodeBasicSubgraph) Subgraph() dag.Grapher {
	return n.Graph
}

func (n *GraphNodeBasicSubgraph) FlattenGraph() *Graph {
	return n.Graph
}
<commit_msg>terraform: more dead code removal<commit_after>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/dag"
)

// GraphNodeExapndable is an interface that nodes can implement to
// signal that they can be expanded. Expanded nodes turn into
// GraphNodeSubgraph nodes within the graph.
type GraphNodeExpandable interface {
	Expand(GraphBuilder) (GraphNodeSubgraph, error)
}

// GraphNodeDynamicExpandable is an interface that nodes can implement
// to signal that they can be expanded at eval-time (hence dynamic).
// These nodes are given the eval context and are expected to return
// a new subgraph.
type GraphNodeDynamicExpandable interface {
	DynamicExpand(EvalContext) (*Graph, error)
}

// GraphNodeSubgraph is an interface a node can implement if it has
// a larger subgraph that should be walked.
type GraphNodeSubgraph interface {
	Subgraph() dag.Grapher
}

// ExpandTransform is a transformer that does a subgraph expansion
// at graph transform time (vs. at eval time). The benefit of earlier
// subgraph expansion is that errors with the graph build can be detected
// at an earlier stage.
type ExpandTransform struct {
	Builder GraphBuilder
}

func (t *ExpandTransform) Transform(v dag.Vertex) (dag.Vertex, error) {
	ev, ok := v.(GraphNodeExpandable)
	if !ok {
		// This isn't an expandable vertex, so just ignore it.
		return v, nil
	}

	// Expand the subgraph!
	log.Printf("[DEBUG] vertex %q: static expanding", dag.VertexName(ev))
	return ev.Expand(t.Builder)
}
<|endoftext|>