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

package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/names"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/state/api/params"
)

type DeployCommand struct {
	cmd.EnvCommandBase
	UnitCommandBase
	CharmName    string
	ServiceName  string
	Config       cmd.FileVar
	Constraints  constraints.Value
	Networks     string
	NoNetworks   string
	BumpRevision bool   // Remove this once the 1.16 support is dropped.
	RepoPath     string // defaults to JUJU_REPOSITORY
}

const deployDoc = `
<charm name> can be a charm URL, or an unambiguously condensed form of it;
assuming a current default series of "precise", the following forms will be
accepted.

For cs:precise/mysql
  mysql
  precise/mysql

For cs:~user/precise/mysql
  cs:~user/mysql

For local:precise/mysql
  local:mysql

In all cases, a versioned charm URL will be expanded as expected (for example,
mysql-33 becomes cs:precise/mysql-33).

<service name>, if omitted, will be derived from <charm name>.

Constraints can be specified when using deploy by specifying the --constraints
flag.  When used with deploy, service-specific constraints are set so that later
machines provisioned with add-unit will use the same constraints (unless changed
by set-constraints).

Charms can be deployed to a specific machine using the --to argument.

Like constraints, service-specific network requirements can be specified with
--networks and --no-networks arguments, both can take a comma-delimited list
of provider-specific network names/labels. These instruct juju to ensure all
new machines deployed to host units of the service should be on all networks
specified with --networks and should not be on any networks specified with
--no-networks. Only supported when using the MaaS provider.

Examples:
   juju deploy mysql --to 23       (Deploy to machine 23)
   juju deploy mysql --to 24/lxc/3 (Deploy to lxc container 3 on host machine 24)
   juju deploy mysql --to lxc:25   (Deploy to a new lxc container on host machine 25)

   juju deploy mysql -n 5 --constraints mem=8G (deploy 5 instances of mysql with at least 8 GB of RAM each)

   juju deploy mysql --networks=storage,mynet --no-networks=logging

See Also:
   juju help constraints
   juju help set-constraints
   juju help get-constraints
`

func (c *DeployCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "deploy",
		Args:    "<charm name> [<service name>]",
		Purpose: "deploy a new service",
		Doc:     deployDoc,
	}
}

func (c *DeployCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	c.UnitCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to deploy for principal charms")
	f.BoolVar(&c.BumpRevision, "u", false, "increment local charm directory revision (DEPRECATED)")
	f.BoolVar(&c.BumpRevision, "upgrade", false, "")
	f.Var(&c.Config, "config", "path to yaml-formatted service config")
	f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "set service constraints")
	f.StringVar(&c.Networks, "networks", "", "enable networks for service")
	f.StringVar(&c.NoNetworks, "no-networks", "", "disable networks for service")
	f.StringVar(&c.RepoPath, "repository", os.Getenv(osenv.JujuRepositoryEnvKey), "local charm repository")
}

func (c *DeployCommand) Init(args []string) error {
	switch len(args) {
	case 2:
		if !names.IsService(args[1]) {
			return fmt.Errorf("invalid service name %q", args[1])
		}
		c.ServiceName = args[1]
		fallthrough
	case 1:
		if _, err := charm.InferURL(args[0], "fake"); err != nil {
			return fmt.Errorf("invalid charm name %q", args[0])
		}
		c.CharmName = args[0]
	case 0:
		return errors.New("no charm specified")
	default:
		return cmd.CheckEmpty(args[2:])
	}
	return c.UnitCommandBase.Init(args)
}

func (c *DeployCommand) Run(ctx *cmd.Context) error {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()

	attrs, err := client.EnvironmentGet()
	if params.IsCodeNotImplemented(err) {
		logger.Infof("EnvironmentGet not supported by the API server, " +
			"falling back to 1.16 compatibility mode (direct DB access)")
		return c.run1dot16(ctx)
	}
	if err != nil {
		return err
	}
	conf, err := config.New(config.NoDefaults, attrs)
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}

	repo = config.SpecializeCharmRepo(repo, conf)

	curl, err = addCharmViaAPI(client, ctx, curl, repo)
	if err != nil {
		return err
	}

	if c.BumpRevision {
		ctx.Infof("--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.")
	}
	var includeNetworks []string
	var excludeNetworks []string
	if c.Networks != "" {
		includeNetworks = parseNetworks(c.Networks)
	}
	if c.NoNetworks != "" {
		excludeNetworks = parseNetworks(c.NoNetworks)
	}

	charmInfo, err := client.CharmInfo(curl.String())
	if err != nil {
		return err
	}

	numUnits := c.NumUnits
	if charmInfo.Meta.Subordinate {
		if !constraints.IsEmpty(&c.Constraints) {
			return errors.New("cannot use --constraints with subordinate service")
		}
		if numUnits == 1 && c.ToMachineSpec == "" {
			numUnits = 0
		} else {
			return errors.New("cannot use --num-units or --to with subordinate service")
		}
	}
	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = charmInfo.Meta.Name
	}

	var configYAML []byte
	if c.Config.Path != "" {
		configYAML, err = c.Config.Read(ctx)
		if err != nil {
			return err
		}
	}
	err = client.ServiceDeployWithNetworks(
		curl.String(),
		serviceName,
		numUnits,
		string(configYAML),
		c.Constraints,
		c.ToMachineSpec,
		includeNetworks,
		excludeNetworks,
	)
	if params.IsCodeNotImplemented(err) {
		ctx.Infof("ignoring --networks/--no-networks as it is not supported by the API server")
		err = client.ServiceDeploy(
			curl.String(),
			serviceName,
			numUnits,
			string(configYAML),
			c.Constraints,
			c.ToMachineSpec,
		)
	}
	return err
}

// run1dot16 implements the deploy command in 1.16 compatibility mode,
// with direct state access. Remove this when support for 1.16 is
// dropped.
func (c *DeployCommand) run1dot16(ctx *cmd.Context) error {
	conn, err := juju.NewConnFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer conn.Close()
	conf, err := conn.State.EnvironConfig()
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}

	repo = config.SpecializeCharmRepo(repo, conf)

	// TODO(fwereade) it's annoying to roundtrip the bytes through the client
	// here, but it's the original behaviour and not convenient to change.
	// PutCharm will always be required in some form for local charms; and we
	// will need an EnsureStoreCharm method somewhere that gets the state.Charm
	// for use in the following checks.
	ch, err := conn.PutCharm(curl, repo, c.BumpRevision)
	if err != nil {
		return err
	}
	numUnits := c.NumUnits
	if ch.Meta().Subordinate {
		if !constraints.IsEmpty(&c.Constraints) {
			return errors.New("cannot use --constraints with subordinate service")
		}
		if numUnits == 1 && c.ToMachineSpec == "" {
			numUnits = 0
		} else {
			return errors.New("cannot use --num-units or --to with subordinate service")
		}
	}

	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = ch.Meta().Name
	}
	var settings charm.Settings
	if c.Config.Path != "" {
		configYAML, err := c.Config.Read(ctx)
		if err != nil {
			return err
		}
		settings, err = ch.Config().ParseSettingsYAML(configYAML, serviceName)
		if err != nil {
			return err
		}
	}
	_, err = juju.DeployService(conn.State,
		juju.DeployServiceParams{
			ServiceName:    serviceName,
			Charm:          ch,
			NumUnits:       numUnits,
			ConfigSettings: settings,
			Constraints:    c.Constraints,
			ToMachineSpec:  c.ToMachineSpec,
		})
	return err
}

// addCharmViaAPI calls the appropriate client API calls to add the
// given charm URL to state. Also displays the charm URL of the added
// charm on stdout.
func addCharmViaAPI(client *api.Client, ctx *cmd.Context, curl *charm.URL, repo charm.Repository) (*charm.URL, error) {
	if curl.Revision < 0 {
		latest, err := charm.Latest(repo, curl)
		if err != nil {
			return nil, err
		}
		curl = curl.WithRevision(latest)
	}
	switch curl.Schema {
	case "local":
		ch, err := repo.Get(curl)
		if err != nil {
			return nil, err
		}
		stateCurl, err := client.AddLocalCharm(curl, ch)
		if err != nil {
			return nil, err
		}
		curl = stateCurl
	case "cs":
		err := client.AddCharm(curl)
		if err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("unsupported charm URL schema: %q", curl.Schema)
	}
	ctx.Infof("Added charm %q to the environment.", curl)
	return curl, nil
}

// parseNetworks returns a list of networks by parsing the
// comma-delimited string value of --networks or --no-networks
// arguments.
func parseNetworks(networksValue string) (networks []string) {
	parts := strings.Split(networksValue, ",")
	for _, part := range parts {
		network := strings.TrimSpace(part)
		if network != "" {
			networks = append(networks, network)
		}
	}
	return networks
}
<commit_msg>Improved early checking for networks support<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/charm"
	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/constraints"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/names"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/state/api/params"
)

type DeployCommand struct {
	cmd.EnvCommandBase
	UnitCommandBase
	CharmName    string
	ServiceName  string
	Config       cmd.FileVar
	Constraints  constraints.Value
	Networks     string
	NoNetworks   string
	BumpRevision bool   // Remove this once the 1.16 support is dropped.
	RepoPath     string // defaults to JUJU_REPOSITORY
}

const deployDoc = `
<charm name> can be a charm URL, or an unambiguously condensed form of it;
assuming a current default series of "precise", the following forms will be
accepted.

For cs:precise/mysql
  mysql
  precise/mysql

For cs:~user/precise/mysql
  cs:~user/mysql

For local:precise/mysql
  local:mysql

In all cases, a versioned charm URL will be expanded as expected (for example,
mysql-33 becomes cs:precise/mysql-33).

<service name>, if omitted, will be derived from <charm name>.

Constraints can be specified when using deploy by specifying the --constraints
flag.  When used with deploy, service-specific constraints are set so that later
machines provisioned with add-unit will use the same constraints (unless changed
by set-constraints).

Charms can be deployed to a specific machine using the --to argument.

Like constraints, service-specific network requirements can be specified with
--networks and --no-networks arguments, both can take a comma-delimited list
of provider-specific network names/labels. These instruct juju to ensure all
new machines deployed to host units of the service should be on all networks
specified with --networks and should not be on any networks specified with
--no-networks. Only supported when using the MaaS provider.

Examples:
   juju deploy mysql --to 23       (Deploy to machine 23)
   juju deploy mysql --to 24/lxc/3 (Deploy to lxc container 3 on host machine 24)
   juju deploy mysql --to lxc:25   (Deploy to a new lxc container on host machine 25)

   juju deploy mysql -n 5 --constraints mem=8G (deploy 5 instances of mysql with at least 8 GB of RAM each)

   juju deploy mysql --networks=storage,mynet --no-networks=logging

See Also:
   juju help constraints
   juju help set-constraints
   juju help get-constraints
`

func (c *DeployCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "deploy",
		Args:    "<charm name> [<service name>]",
		Purpose: "deploy a new service",
		Doc:     deployDoc,
	}
}

func (c *DeployCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	c.UnitCommandBase.SetFlags(f)
	f.IntVar(&c.NumUnits, "n", 1, "number of service units to deploy for principal charms")
	f.BoolVar(&c.BumpRevision, "u", false, "increment local charm directory revision (DEPRECATED)")
	f.BoolVar(&c.BumpRevision, "upgrade", false, "")
	f.Var(&c.Config, "config", "path to yaml-formatted service config")
	f.Var(constraints.ConstraintsValue{&c.Constraints}, "constraints", "set service constraints")
	f.StringVar(&c.Networks, "networks", "", "enable networks for service")
	f.StringVar(&c.NoNetworks, "no-networks", "", "disable networks for service")
	f.StringVar(&c.RepoPath, "repository", os.Getenv(osenv.JujuRepositoryEnvKey), "local charm repository")
}

func (c *DeployCommand) Init(args []string) error {
	switch len(args) {
	case 2:
		if !names.IsService(args[1]) {
			return fmt.Errorf("invalid service name %q", args[1])
		}
		c.ServiceName = args[1]
		fallthrough
	case 1:
		if _, err := charm.InferURL(args[0], "fake"); err != nil {
			return fmt.Errorf("invalid charm name %q", args[0])
		}
		c.CharmName = args[0]
	case 0:
		return errors.New("no charm specified")
	default:
		return cmd.CheckEmpty(args[2:])
	}
	return c.UnitCommandBase.Init(args)
}

func (c *DeployCommand) Run(ctx *cmd.Context) error {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()

	attrs, err := client.EnvironmentGet()
	if params.IsCodeNotImplemented(err) {
		logger.Infof("EnvironmentGet not supported by the API server, " +
			"falling back to 1.16 compatibility mode (direct DB access)")
		return c.run1dot16(ctx)
	}
	if err != nil {
		return err
	}
	conf, err := config.New(config.NoDefaults, attrs)
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}

	repo = config.SpecializeCharmRepo(repo, conf)

	curl, err = addCharmViaAPI(client, ctx, curl, repo)
	if err != nil {
		return err
	}

	if c.BumpRevision {
		ctx.Infof("--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.")
	}
	var includeNetworks []string
	var excludeNetworks []string
	haveNetworks := false
	if c.Networks != "" {
		includeNetworks = parseNetworks(c.Networks)
		haveNetworks = true
	}
	if c.NoNetworks != "" {
		excludeNetworks = parseNetworks(c.NoNetworks)
		haveNetworks = true
	}
	if haveNetworks {
		env, err := environs.New(conf)
		if err != nil {
			return err
		}
		if !env.SupportNetworks() {
			return errors.New("cannot use --networks/--no-networks: not supported by the environment")
		}
	}

	charmInfo, err := client.CharmInfo(curl.String())
	if err != nil {
		return err
	}

	numUnits := c.NumUnits
	if charmInfo.Meta.Subordinate {
		if !constraints.IsEmpty(&c.Constraints) {
			return errors.New("cannot use --constraints with subordinate service")
		}
		if numUnits == 1 && c.ToMachineSpec == "" {
			numUnits = 0
		} else {
			return errors.New("cannot use --num-units or --to with subordinate service")
		}
	}
	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = charmInfo.Meta.Name
	}

	var configYAML []byte
	if c.Config.Path != "" {
		configYAML, err = c.Config.Read(ctx)
		if err != nil {
			return err
		}
	}
	err = client.ServiceDeployWithNetworks(
		curl.String(),
		serviceName,
		numUnits,
		string(configYAML),
		c.Constraints,
		c.ToMachineSpec,
		includeNetworks,
		excludeNetworks,
	)
	if params.IsCodeNotImplemented(err) && haveNetworks {
		return errors.New("cannot use --networks/--no-networks: not supported by the API server")
	}
	return client.ServiceDeploy(
		curl.String(),
		serviceName,
		numUnits,
		string(configYAML),
		c.Constraints,
		c.ToMachineSpec)
}

// run1dot16 implements the deploy command in 1.16 compatibility mode,
// with direct state access. Remove this when support for 1.16 is
// dropped.
func (c *DeployCommand) run1dot16(ctx *cmd.Context) error {
	conn, err := juju.NewConnFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer conn.Close()
	conf, err := conn.State.EnvironConfig()
	if err != nil {
		return err
	}
	curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())
	if err != nil {
		return err
	}
	repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}

	repo = config.SpecializeCharmRepo(repo, conf)

	// TODO(fwereade) it's annoying to roundtrip the bytes through the client
	// here, but it's the original behaviour and not convenient to change.
	// PutCharm will always be required in some form for local charms; and we
	// will need an EnsureStoreCharm method somewhere that gets the state.Charm
	// for use in the following checks.
	ch, err := conn.PutCharm(curl, repo, c.BumpRevision)
	if err != nil {
		return err
	}
	numUnits := c.NumUnits
	if ch.Meta().Subordinate {
		if !constraints.IsEmpty(&c.Constraints) {
			return errors.New("cannot use --constraints with subordinate service")
		}
		if numUnits == 1 && c.ToMachineSpec == "" {
			numUnits = 0
		} else {
			return errors.New("cannot use --num-units or --to with subordinate service")
		}
	}

	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = ch.Meta().Name
	}
	var settings charm.Settings
	if c.Config.Path != "" {
		configYAML, err := c.Config.Read(ctx)
		if err != nil {
			return err
		}
		settings, err = ch.Config().ParseSettingsYAML(configYAML, serviceName)
		if err != nil {
			return err
		}
	}
	_, err = juju.DeployService(conn.State,
		juju.DeployServiceParams{
			ServiceName:    serviceName,
			Charm:          ch,
			NumUnits:       numUnits,
			ConfigSettings: settings,
			Constraints:    c.Constraints,
			ToMachineSpec:  c.ToMachineSpec,
		})
	return err
}

// addCharmViaAPI calls the appropriate client API calls to add the
// given charm URL to state. Also displays the charm URL of the added
// charm on stdout.
func addCharmViaAPI(client *api.Client, ctx *cmd.Context, curl *charm.URL, repo charm.Repository) (*charm.URL, error) {
	if curl.Revision < 0 {
		latest, err := charm.Latest(repo, curl)
		if err != nil {
			return nil, err
		}
		curl = curl.WithRevision(latest)
	}
	switch curl.Schema {
	case "local":
		ch, err := repo.Get(curl)
		if err != nil {
			return nil, err
		}
		stateCurl, err := client.AddLocalCharm(curl, ch)
		if err != nil {
			return nil, err
		}
		curl = stateCurl
	case "cs":
		err := client.AddCharm(curl)
		if err != nil {
			return nil, err
		}
	default:
		return nil, fmt.Errorf("unsupported charm URL schema: %q", curl.Schema)
	}
	ctx.Infof("Added charm %q to the environment.", curl)
	return curl, nil
}

// parseNetworks returns a list of networks by parsing the
// comma-delimited string value of --networks or --no-networks
// arguments.
func parseNetworks(networksValue string) (networks []string) {
	parts := strings.Split(networksValue, ",")
	for _, part := range parts {
		network := strings.TrimSpace(part)
		if network != "" {
			networks = append(networks, network)
		}
	}
	return networks
}
<|endoftext|>


<commit_before>//
// Copyright 2017 Pedro Salgado
//
// 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 resque

import (
	"encoding/json"
	"fmt"

	"gopkg.in/redis.v5"
)

const (
	// Queues name of the key for the set where Resque stores the currently available queues.
	Queues = "resque:queues"
)

// Queue a job queue.
type Queue struct {
	redis        *redis.Client
	jobClassName string
	Name         string
}

// newQueue initializes a Queue struct and updates the set of available Resque queues.
func newQueue(jcn string, c *redis.Client) (*Queue, error) {
	q := &Queue{
		redis:        c,
		jobClassName: jcn,
		Name:         fmt.Sprintf("resque:queue:%s", jcn),
	}

	exists, err := c.SIsMember(Queues, q.Name).Result()
	if err != nil {
		return nil, err
	}
	if !exists {
		_, err := c.SAdd(Queues, q.Name).Result()
		if err != nil {
			return nil, err
		}
	}

	return q, nil
}

// Receive gets a job from the queue.
func (q Queue) Receive() (*Job, error) {
	cmd := q.redis.LPop(q.Name)
	if cmd.Err() != nil {
		if cmd.Err().Error() == "redis: nil" {
			return nil, nil
		}
		return nil, cmd.Err()
	}

	jsonStr, err := cmd.Bytes()
	if err != nil {
		return nil, err
	}

	job := &Job{}
	err = json.Unmarshal(jsonStr, job)
	if err != nil {
		return nil, err
	}

	return job, err
}

// Send places a job on the queue.
func (q Queue) Send(args []JobArgument) error {
	jsonStr, err := json.Marshal(Job{Class: q.jobClassName, Args: args})
	if err != nil {
		return err
	}

	return q.redis.RPush(q.Name, jsonStr).Err()
}
<commit_msg>test/integration: register queue name not full FQDN.<commit_after>//
// Copyright 2017 Pedro Salgado
//
// 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 resque

import (
	"encoding/json"
	"fmt"

	"gopkg.in/redis.v5"
)

const (
	// Queues name of the key for the set where Resque stores the currently available queues.
	Queues = "resque:queues"
)

// Queue a job queue.
type Queue struct {
	redis        *redis.Client
	jobClassName string
	Name         string
}

// newQueue initializes a Queue struct and updates the set of available Resque queues.
func newQueue(jcn string, c *redis.Client) (*Queue, error) {
	q := &Queue{
		redis:        c,
		jobClassName: jcn,
		Name:         fmt.Sprintf("resque:queue:%s", jcn),
	}

	exists, err := c.SIsMember(Queues, jcn).Result()
	if err != nil {
		return nil, err
	}
	if !exists {
		_, err := c.SAdd(Queues, jcn).Result()
		if err != nil {
			return nil, err
		}
	}

	return q, nil
}

// Receive gets a job from the queue.
func (q Queue) Receive() (*Job, error) {
	cmd := q.redis.LPop(q.Name)
	if cmd.Err() != nil {
		if cmd.Err().Error() == "redis: nil" {
			return nil, nil
		}
		return nil, cmd.Err()
	}

	jsonStr, err := cmd.Bytes()
	if err != nil {
		return nil, err
	}

	job := &Job{}
	err = json.Unmarshal(jsonStr, job)
	if err != nil {
		return nil, err
	}

	return job, err
}

// Send places a job on the queue.
func (q Queue) Send(args []JobArgument) error {
	jsonStr, err := json.Marshal(Job{Class: q.jobClassName, Args: args})
	if err != nil {
		return err
	}

	return q.redis.RPush(q.Name, jsonStr).Err()
}
<|endoftext|>


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

package main

import (
	"fmt"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/utils/set"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/configstore"
)

type SwitchCommand struct {
	cmd.CommandBase
	EnvName string
	List    bool
}

var switchDoc = `
Show or change the default juju environment or system name.

If no command line parameters are passed, switch will output the current
environment as defined by the file $JUJU_HOME/current-environment.

If a command line parameter is passed in, that value will is stored in the
current environment file if it represents a valid environment name as
specified in the environments.yaml file.
`

const systemSuffix = " (system)"

func (c *SwitchCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "switch",
		Args:    "[environment name]",
		Purpose: "show or change the default juju environment or system name",
		Doc:     switchDoc,
		Aliases: []string{"env"},
	}
}

func (c *SwitchCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.List, "l", false, "list the environment names")
	f.BoolVar(&c.List, "list", false, "")
}

func (c *SwitchCommand) Init(args []string) (err error) {
	c.EnvName, err = cmd.ZeroOrOneArgs(args)
	return
}

func getConfigstoreOptions() (set.Strings, set.Strings, error) {
	store, err := configstore.Default()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to get config store")
	}
	environmentNames, err := store.List()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to list environments in config store")
	}
	systemNames, err := store.ListSystems()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to list systems in config store")
	}
	// Also include the systems.
	return set.NewStrings(environmentNames...), set.NewStrings(systemNames...), nil
}

func (c *SwitchCommand) Run(ctx *cmd.Context) error {
	// Switch is an alternative way of dealing with environments than using
	// the JUJU_ENV environment setting, and as such, doesn't play too well.
	// If JUJU_ENV is set we should report that as the current environment,
	// and not allow switching when it is set.

	// Passing through the empty string reads the default environments.yaml file.
	environments, err := environs.ReadEnvirons("")
	if err != nil {
		return errors.Errorf("couldn't read the environment")
	}

	names := set.NewStrings(environments.Names()...)
	configEnvirons, configSystems, err := getConfigstoreOptions()
	if err != nil {
		return err
	}
	names = names.Union(configEnvirons)
	names = names.Union(configSystems)

	if c.List {
		// List all environments and systems.
		if c.EnvName != "" {
			return errors.New("cannot switch and list at the same time")
		}
		for _, name := range names.SortedValues() {
			if configSystems.Contains(name) && !configEnvirons.Contains(name) {
				name += systemSuffix
			}
			fmt.Fprintf(ctx.Stdout, "%s\n", name)
		}
		return nil
	}

	jujuEnv := os.Getenv("JUJU_ENV")
	if jujuEnv != "" {
		if c.EnvName == "" {
			fmt.Fprintf(ctx.Stdout, "%s\n", jujuEnv)
			return nil
		} else {
			return errors.Errorf("cannot switch when JUJU_ENV is overriding the environment (set to %q)", jujuEnv)
		}
	}

	current, isSystem, err := envcmd.CurrentConnectionName()
	if current == "" {
		current = environments.Default
	} else if isSystem {
		current += systemSuffix
	}

	// Handle the different operation modes.
	switch {
	case c.EnvName == "" && current == "":
		// Nothing specified and nothing to switch to.
		return errors.New("no currently specified environment")
	case c.EnvName == "":
		// Simply print the current environment.
		fmt.Fprintf(ctx.Stdout, "%s\n", current)
	default:
		// Switch the environment.
		if !names.Contains(c.EnvName) {
			return errors.Errorf("%q is not a name of an existing defined environment or system", c.EnvName)
		}
		// If the name is not in the environment set, but is in the system
		// set, then write the name into the current system file.
		logger.Debugf("systems: %v", configSystems)
		logger.Debugf("environs: %v", configEnvirons)
		newEnv := c.EnvName
		if configSystems.Contains(newEnv) && !configEnvirons.Contains(newEnv) {
			if err := envcmd.SetCurrentSystem(ctx, newEnv); err != nil {
				return err
			}
		} else {
			if err := envcmd.SetCurrentEnvironment(ctx, newEnv); err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>Clean up returns.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"fmt"
	"os"

	"github.com/juju/cmd"
	"github.com/juju/errors"
	"github.com/juju/utils/set"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/environs"
	"github.com/juju/juju/environs/configstore"
)

type SwitchCommand struct {
	cmd.CommandBase
	EnvName string
	List    bool
}

var switchDoc = `
Show or change the default juju environment or system name.

If no command line parameters are passed, switch will output the current
environment as defined by the file $JUJU_HOME/current-environment.

If a command line parameter is passed in, that value will is stored in the
current environment file if it represents a valid environment name as
specified in the environments.yaml file.
`

const systemSuffix = " (system)"

func (c *SwitchCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "switch",
		Args:    "[environment name]",
		Purpose: "show or change the default juju environment or system name",
		Doc:     switchDoc,
		Aliases: []string{"env"},
	}
}

func (c *SwitchCommand) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.List, "l", false, "list the environment names")
	f.BoolVar(&c.List, "list", false, "")
}

func (c *SwitchCommand) Init(args []string) (err error) {
	c.EnvName, err = cmd.ZeroOrOneArgs(args)
	return
}

func getConfigstoreOptions() (set.Strings, set.Strings, error) {
	store, err := configstore.Default()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to get config store")
	}
	environmentNames, err := store.List()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to list environments in config store")
	}
	systemNames, err := store.ListSystems()
	if err != nil {
		return nil, nil, errors.Annotate(err, "failed to list systems in config store")
	}
	// Also include the systems.
	return set.NewStrings(environmentNames...), set.NewStrings(systemNames...), nil
}

func (c *SwitchCommand) Run(ctx *cmd.Context) error {
	// Switch is an alternative way of dealing with environments than using
	// the JUJU_ENV environment setting, and as such, doesn't play too well.
	// If JUJU_ENV is set we should report that as the current environment,
	// and not allow switching when it is set.

	// Passing through the empty string reads the default environments.yaml file.
	environments, err := environs.ReadEnvirons("")
	if err != nil {
		return errors.Errorf("couldn't read the environment")
	}

	names := set.NewStrings(environments.Names()...)
	configEnvirons, configSystems, err := getConfigstoreOptions()
	if err != nil {
		return err
	}
	names = names.Union(configEnvirons)
	names = names.Union(configSystems)

	if c.List {
		// List all environments and systems.
		if c.EnvName != "" {
			return errors.New("cannot switch and list at the same time")
		}
		for _, name := range names.SortedValues() {
			if configSystems.Contains(name) && !configEnvirons.Contains(name) {
				name += systemSuffix
			}
			fmt.Fprintf(ctx.Stdout, "%s\n", name)
		}
		return nil
	}

	jujuEnv := os.Getenv("JUJU_ENV")
	if jujuEnv != "" {
		if c.EnvName == "" {
			fmt.Fprintf(ctx.Stdout, "%s\n", jujuEnv)
			return nil
		} else {
			return errors.Errorf("cannot switch when JUJU_ENV is overriding the environment (set to %q)", jujuEnv)
		}
	}

	current, isSystem, err := envcmd.CurrentConnectionName()
	if err != nil {
		return errors.Trace(err)
	}
	if current == "" {
		current = environments.Default
	} else if isSystem {
		current += systemSuffix
	}

	// Handle the different operation modes.
	switch {
	case c.EnvName == "" && current == "":
		// Nothing specified and nothing to switch to.
		return errors.New("no currently specified environment")
	case c.EnvName == "":
		// Simply print the current environment.
		fmt.Fprintf(ctx.Stdout, "%s\n", current)
		return nil
	default:
		// Switch the environment.
		if !names.Contains(c.EnvName) {
			return errors.Errorf("%q is not a name of an existing defined environment or system", c.EnvName)
		}
		// If the name is not in the environment set, but is in the system
		// set, then write the name into the current system file.
		logger.Debugf("systems: %v", configSystems)
		logger.Debugf("environs: %v", configEnvirons)
		newEnv := c.EnvName
		if configSystems.Contains(newEnv) && !configEnvirons.Contains(newEnv) {
			return envcmd.SetCurrentSystem(ctx, newEnv)
		}
		return envcmd.SetCurrentEnvironment(ctx, newEnv)
	}
}
<|endoftext|>


<commit_before>package main

//go:generate xb cat -o licenses.go xzLicense:github.com/uli-go/xz/LICENSE
//go:generate xb version-file -o version.go

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/uli-go/xz/gflag"
	"github.com/uli-go/xz/term"
)

const (
	lzmaExt  = ".lzma"
	usageStr = `Usage: lzmago [OPTION]... [FILE]...
Compress or uncompress FILEs in the .lzma format (by default, compress FILES
in place).

  -c, --stdout      write to standard output and don't delete input files
  -d, --decompress  force decompression
  -f, --force       force overwrite of output file and compress links
  -h, --help        give this help
  -k, --keep        keep (don't delete) input files
  -L, --license     display software license
  -q, --quiet       suppress all warnings
  -v, --verbose     verbose mode
  -V, --version     display version string
  -z, --compress    force compression
  -0 ... -9         compression preset; default is 6

With no file, or when FILE is -, read standard input.

Report bugs using <https://github.com/uli-go/xz/issues>.
`
)

func usage(w io.Writer) {
	fmt.Fprint(w, usageStr)
}

func licenses(w io.Writer) {
	out := `
github.com/uli-go/xz -- xz for Go
=================================

{{.xz}}
`
	out = strings.TrimLeft(out, " \n")
	tmpl, err := template.New("licenses").Parse(out)
	if err != nil {
		log.Panicf("error %s parsing licenses template", err)
	}
	lmap := map[string]string{
		"xz": strings.TrimSpace(xzLicense),
	}
	if err = tmpl.Execute(w, lmap); err != nil {
		log.Fatalf("error %s writing licenses template", err)
	}
}

func main() {
	// setup logger
	cmdName := filepath.Base(os.Args[0])
	log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
	log.SetFlags(0)

	// initialize flags
	gflag.CommandLine = gflag.NewFlagSet(cmdName, gflag.ExitOnError)
	gflag.Usage = func() { usage(os.Stderr); os.Exit(1) }
	var (
		help        = gflag.BoolP("help", "h", false, "")
		stdout      = gflag.BoolP("stdout", "c", false, "")
		decompress  = gflag.BoolP("decompress", "d", false, "")
		force       = gflag.BoolP("force", "f", false, "")
		keep        = gflag.BoolP("keep", "k", false, "")
		license     = gflag.BoolP("license", "L", false, "")
		versionFlag = gflag.BoolP("version", "V", false, "")
		preset      = gflag.Preset(0, 9, 6, "")
	)

	// process arguments
	gflag.Parse()

	if *help {
		usage(os.Stdout)
		os.Exit(0)
	}
	if *license {
		licenses(os.Stdout)
		os.Exit(0)
	}
	if *versionFlag {
		log.Printf("version %s\n", version)
		os.Exit(0)
	}
	var args []string
	if gflag.NArg() == 0 {
		if !*stdout {
			log.Fatal("For help, type lzmago -h.")
		}
		args = []string{"-"}
	} else {
		args = gflag.Args()
	}

	if *stdout && !*decompress && !*force && term.IsTerminal(os.Stdout.Fd()) {
		log.Print("Compressed data will not be written to a terminal.")
		log.SetPrefix("")
		log.Fatal("Use -f to force compression." +
			" For help type lzmago -h.")
	}

	log.Printf("decompress %t", *decompress)
	log.Printf("force %t", *force)
	log.Printf("keep %t", *keep)
	log.Printf("preset %d", *preset)
	log.Printf("stdout %t", *stdout)
	log.Printf("args %v", args)
}
<commit_msg>lzmago: added quiet and verbose flags<commit_after>package main

//go:generate xb cat -o licenses.go xzLicense:github.com/uli-go/xz/LICENSE
//go:generate xb version-file -o version.go

import (
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/uli-go/xz/gflag"
	"github.com/uli-go/xz/term"
)

const (
	lzmaExt  = ".lzma"
	usageStr = `Usage: lzmago [OPTION]... [FILE]...
Compress or uncompress FILEs in the .lzma format (by default, compress FILES
in place).

  -c, --stdout      write to standard output and don't delete input files
  -d, --decompress  force decompression
  -f, --force       force overwrite of output file and compress links
  -h, --help        give this help
  -k, --keep        keep (don't delete) input files
  -L, --license     display software license
  -q, --quiet       suppress all warnings
  -v, --verbose     verbose mode
  -V, --version     display version string
  -z, --compress    force compression
  -0 ... -9         compression preset; default is 6

With no file, or when FILE is -, read standard input.

Report bugs using <https://github.com/uli-go/xz/issues>.
`
)

func usage(w io.Writer) {
	fmt.Fprint(w, usageStr)
}

func licenses(w io.Writer) {
	out := `
github.com/uli-go/xz -- xz for Go
=================================

{{.xz}}
`
	out = strings.TrimLeft(out, " \n")
	tmpl, err := template.New("licenses").Parse(out)
	if err != nil {
		log.Panicf("error %s parsing licenses template", err)
	}
	lmap := map[string]string{
		"xz": strings.TrimSpace(xzLicense),
	}
	if err = tmpl.Execute(w, lmap); err != nil {
		log.Fatalf("error %s writing licenses template", err)
	}
}

func main() {
	// setup logger
	cmdName := filepath.Base(os.Args[0])
	log.SetPrefix(fmt.Sprintf("%s: ", cmdName))
	log.SetFlags(0)

	// initialize flags
	gflag.CommandLine = gflag.NewFlagSet(cmdName, gflag.ExitOnError)
	gflag.Usage = func() { usage(os.Stderr); os.Exit(1) }
	var (
		help        = gflag.BoolP("help", "h", false, "")
		stdout      = gflag.BoolP("stdout", "c", false, "")
		decompress  = gflag.BoolP("decompress", "d", false, "")
		force       = gflag.BoolP("force", "f", false, "")
		keep        = gflag.BoolP("keep", "k", false, "")
		license     = gflag.BoolP("license", "L", false, "")
		versionFlag = gflag.BoolP("version", "V", false, "")
		quiet       = gflag.CounterP("quiet", "q", 0, "")
		verbose     = gflag.CounterP("verbose", "v", 0, "")
		preset      = gflag.Preset(0, 9, 6, "")
	)

	// process arguments
	gflag.Parse()

	if *help {
		usage(os.Stdout)
		os.Exit(0)
	}
	if *license {
		licenses(os.Stdout)
		os.Exit(0)
	}
	if *versionFlag {
		log.Printf("version %s\n", version)
		os.Exit(0)
	}
	var args []string
	if gflag.NArg() == 0 {
		if !*stdout {
			log.Fatal("For help, type lzmago -h.")
		}
		args = []string{"-"}
	} else {
		args = gflag.Args()
	}

	if *stdout && !*decompress && !*force && term.IsTerminal(os.Stdout.Fd()) {
		log.Print("Compressed data will not be written to a terminal.")
		log.SetPrefix("")
		log.Fatal("Use -f to force compression." +
			" For help type lzmago -h.")
	}

	log.Printf("decompress %t", *decompress)
	log.Printf("force %t", *force)
	log.Printf("keep %t", *keep)
	log.Printf("preset %d", *preset)
	log.Printf("stdout %t", *stdout)
	log.Printf("quiet %d", *quiet)
	log.Printf("verbose %d", *verbose)
	log.Printf("args %v", args)
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Jeffrey Wilcke <i@jev.io>
 */
package main

import (
	"io/ioutil"
	"path"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/eth"
	"github.com/ethereum/go-ethereum/event/filter"
	"github.com/ethereum/go-ethereum/xeth"
	"github.com/obscuren/qml"
)

type memAddr struct {
	Num   string
	Value string
}

// UI Library that has some basic functionality exposed
type UiLib struct {
	*xeth.XEth
	engine    *qml.Engine
	eth       *eth.Ethereum
	connected bool
	assetPath string
	// The main application window
	win *qml.Window

	filterCallbacks map[int][]int
	filterManager   *filter.FilterManager
}

func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath, libPath string) *UiLib {
	x := xeth.New(eth, nil)
	lib := &UiLib{
		XEth:            x,
		engine:          engine,
		eth:             eth,
		assetPath:       assetPath,
		filterCallbacks: make(map[int][]int),
	}
	lib.filterManager = filter.NewFilterManager(eth.EventMux())
	go lib.filterManager.Start()

	return lib
}

func (self *UiLib) Notef(args []interface{}) {
	guilogger.Infoln(args...)
}

func (self *UiLib) ImportTx(rlpTx string) {
	tx := types.NewTransactionFromBytes(common.Hex2Bytes(rlpTx))
	err := self.eth.TxPool().Add(tx)
	if err != nil {
		guilogger.Infoln("import tx failed ", err)
	}
}

func (ui *UiLib) Muted(content string) {
	component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
	if err != nil {
		guilogger.Debugln(err)

		return
	}
	win := component.CreateWindow(nil)
	go func() {
		path := "file://" + ui.AssetPath("muted/index.html")
		win.Set("url", path)

		win.Show()
		win.Wait()
	}()
}

func (ui *UiLib) Connect(button qml.Object) {
	if !ui.connected {
		ui.eth.Start()
		ui.connected = true
		button.Set("enabled", false)
	}
}

func (ui *UiLib) ConnectToPeer(nodeURL string) {
	if err := ui.eth.AddPeer(nodeURL); err != nil {
		guilogger.Infoln("TrustPeer error: " + err.Error())
	}
}

func (ui *UiLib) AssetPath(p string) string {
	return path.Join(ui.assetPath, p)
}

func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
	object := mapToTxParams(params)

	return self.XEth.Transact(
		object["from"],
		object["to"],
		object["value"],
		object["gas"],
		object["gasPrice"],
		object["data"],
	)
}

func (self *UiLib) Call(params map[string]interface{}) (string, error) {
	object := mapToTxParams(params)

	return self.XEth.Call(
		object["from"],
		object["to"],
		object["value"],
		object["gas"],
		object["gasPrice"],
		object["data"],
	)
}

func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
	return 0
	/*
		return self.miner.AddLocalTx(&miner.LocalTx{
			To:       common.Hex2Bytes(to),
			Data:     common.Hex2Bytes(data),
			Gas:      gas,
			GasPrice: gasPrice,
			Value:    value,
		}) - 1
	*/
}

func (self *UiLib) RemoveLocalTransaction(id int) {
	//self.miner.RemoveLocalTx(id)
}

func (self *UiLib) ToggleMining() bool {
	if !self.eth.IsMining() {
		err := self.eth.StartMining()
		return err == nil
	} else {
		self.eth.StopMining()
		return false
	}
}

func (self *UiLib) ToHex(data string) string {
	return "0x" + common.Bytes2Hex([]byte(data))
}

func (self *UiLib) ToAscii(data string) string {
	start := 0
	if len(data) > 1 && data[0:2] == "0x" {
		start = 2
	}
	return string(common.Hex2Bytes(data[start:]))
}

/// Ethereum filter methods
func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) {
	/* TODO remove me
	filter := qt.NewFilterFromMap(object, self.eth)
	filter.MessageCallback = func(messages state.Messages) {
		view.Call("messages", xeth.ToMessages(messages), id)
	}
	id = self.filterManager.InstallFilter(filter)
	return id
	*/
	return 0
}

func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
	/* TODO remove me
	filter := core.NewFilter(self.eth)
	filter.BlockCallback = func(block *types.Block) {
		view.Call("messages", "{}", id)
	}
	id = self.filterManager.InstallFilter(filter)
	return id
	*/
	return 0
}

func (self *UiLib) Messages(id int) *common.List {
	/* TODO remove me
	filter := self.filterManager.GetFilter(id)
	if filter != nil {
		messages := xeth.ToMessages(filter.Find())

		return messages
	}
	*/

	return common.EmptyList()
}

func (self *UiLib) ReadFile(p string) string {
	content, err := ioutil.ReadFile(self.AssetPath(path.Join("ext", p)))
	if err != nil {
		guilogger.Infoln("error reading file", p, ":", err)
	}
	return string(content)
}

func (self *UiLib) UninstallFilter(id int) {
	self.filterManager.UninstallFilter(id)
}

func mapToTxParams(object map[string]interface{}) map[string]string {
	// Default values
	if object["from"] == nil {
		object["from"] = ""
	}
	if object["to"] == nil {
		object["to"] = ""
	}
	if object["value"] == nil {
		object["value"] = ""
	}
	if object["gas"] == nil {
		object["gas"] = ""
	}
	if object["gasPrice"] == nil {
		object["gasPrice"] = ""
	}

	var dataStr string
	var data []string
	if list, ok := object["data"].(*qml.List); ok {
		list.Convert(&data)
	} else if str, ok := object["data"].(string); ok {
		data = []string{str}
	}

	for _, str := range data {
		if common.IsHex(str) {
			str = str[2:]

			if len(str) != 64 {
				str = common.LeftPadString(str, 64)
			}
		} else {
			str = common.Bytes2Hex(common.LeftPadBytes(common.Big(str).Bytes(), 32))
		}

		dataStr += str
	}
	object["data"] = dataStr

	conv := make(map[string]string)
	for key, value := range object {
		if v, ok := value.(string); ok {
			conv[key] = v
		}
	}

	return conv
}
<commit_msg>cmd/mist: fix a stale error message<commit_after>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @authors
 * 	Jeffrey Wilcke <i@jev.io>
 */
package main

import (
	"io/ioutil"
	"path"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/eth"
	"github.com/ethereum/go-ethereum/event/filter"
	"github.com/ethereum/go-ethereum/xeth"
	"github.com/obscuren/qml"
)

type memAddr struct {
	Num   string
	Value string
}

// UI Library that has some basic functionality exposed
type UiLib struct {
	*xeth.XEth
	engine    *qml.Engine
	eth       *eth.Ethereum
	connected bool
	assetPath string
	// The main application window
	win *qml.Window

	filterCallbacks map[int][]int
	filterManager   *filter.FilterManager
}

func NewUiLib(engine *qml.Engine, eth *eth.Ethereum, assetPath, libPath string) *UiLib {
	x := xeth.New(eth, nil)
	lib := &UiLib{
		XEth:            x,
		engine:          engine,
		eth:             eth,
		assetPath:       assetPath,
		filterCallbacks: make(map[int][]int),
	}
	lib.filterManager = filter.NewFilterManager(eth.EventMux())
	go lib.filterManager.Start()

	return lib
}

func (self *UiLib) Notef(args []interface{}) {
	guilogger.Infoln(args...)
}

func (self *UiLib) ImportTx(rlpTx string) {
	tx := types.NewTransactionFromBytes(common.Hex2Bytes(rlpTx))
	err := self.eth.TxPool().Add(tx)
	if err != nil {
		guilogger.Infoln("import tx failed ", err)
	}
}

func (ui *UiLib) Muted(content string) {
	component, err := ui.engine.LoadFile(ui.AssetPath("qml/muted.qml"))
	if err != nil {
		guilogger.Debugln(err)

		return
	}
	win := component.CreateWindow(nil)
	go func() {
		path := "file://" + ui.AssetPath("muted/index.html")
		win.Set("url", path)

		win.Show()
		win.Wait()
	}()
}

func (ui *UiLib) Connect(button qml.Object) {
	if !ui.connected {
		ui.eth.Start()
		ui.connected = true
		button.Set("enabled", false)
	}
}

func (ui *UiLib) ConnectToPeer(nodeURL string) {
	if err := ui.eth.AddPeer(nodeURL); err != nil {
		guilogger.Infoln("AddPeer error: " + err.Error())
	}
}

func (ui *UiLib) AssetPath(p string) string {
	return path.Join(ui.assetPath, p)
}

func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
	object := mapToTxParams(params)

	return self.XEth.Transact(
		object["from"],
		object["to"],
		object["value"],
		object["gas"],
		object["gasPrice"],
		object["data"],
	)
}

func (self *UiLib) Call(params map[string]interface{}) (string, error) {
	object := mapToTxParams(params)

	return self.XEth.Call(
		object["from"],
		object["to"],
		object["value"],
		object["gas"],
		object["gasPrice"],
		object["data"],
	)
}

func (self *UiLib) AddLocalTransaction(to, data, gas, gasPrice, value string) int {
	return 0
	/*
		return self.miner.AddLocalTx(&miner.LocalTx{
			To:       common.Hex2Bytes(to),
			Data:     common.Hex2Bytes(data),
			Gas:      gas,
			GasPrice: gasPrice,
			Value:    value,
		}) - 1
	*/
}

func (self *UiLib) RemoveLocalTransaction(id int) {
	//self.miner.RemoveLocalTx(id)
}

func (self *UiLib) ToggleMining() bool {
	if !self.eth.IsMining() {
		err := self.eth.StartMining()
		return err == nil
	} else {
		self.eth.StopMining()
		return false
	}
}

func (self *UiLib) ToHex(data string) string {
	return "0x" + common.Bytes2Hex([]byte(data))
}

func (self *UiLib) ToAscii(data string) string {
	start := 0
	if len(data) > 1 && data[0:2] == "0x" {
		start = 2
	}
	return string(common.Hex2Bytes(data[start:]))
}

/// Ethereum filter methods
func (self *UiLib) NewFilter(object map[string]interface{}, view *qml.Common) (id int) {
	/* TODO remove me
	filter := qt.NewFilterFromMap(object, self.eth)
	filter.MessageCallback = func(messages state.Messages) {
		view.Call("messages", xeth.ToMessages(messages), id)
	}
	id = self.filterManager.InstallFilter(filter)
	return id
	*/
	return 0
}

func (self *UiLib) NewFilterString(typ string, view *qml.Common) (id int) {
	/* TODO remove me
	filter := core.NewFilter(self.eth)
	filter.BlockCallback = func(block *types.Block) {
		view.Call("messages", "{}", id)
	}
	id = self.filterManager.InstallFilter(filter)
	return id
	*/
	return 0
}

func (self *UiLib) Messages(id int) *common.List {
	/* TODO remove me
	filter := self.filterManager.GetFilter(id)
	if filter != nil {
		messages := xeth.ToMessages(filter.Find())

		return messages
	}
	*/

	return common.EmptyList()
}

func (self *UiLib) ReadFile(p string) string {
	content, err := ioutil.ReadFile(self.AssetPath(path.Join("ext", p)))
	if err != nil {
		guilogger.Infoln("error reading file", p, ":", err)
	}
	return string(content)
}

func (self *UiLib) UninstallFilter(id int) {
	self.filterManager.UninstallFilter(id)
}

func mapToTxParams(object map[string]interface{}) map[string]string {
	// Default values
	if object["from"] == nil {
		object["from"] = ""
	}
	if object["to"] == nil {
		object["to"] = ""
	}
	if object["value"] == nil {
		object["value"] = ""
	}
	if object["gas"] == nil {
		object["gas"] = ""
	}
	if object["gasPrice"] == nil {
		object["gasPrice"] = ""
	}

	var dataStr string
	var data []string
	if list, ok := object["data"].(*qml.List); ok {
		list.Convert(&data)
	} else if str, ok := object["data"].(string); ok {
		data = []string{str}
	}

	for _, str := range data {
		if common.IsHex(str) {
			str = str[2:]

			if len(str) != 64 {
				str = common.LeftPadString(str, 64)
			}
		} else {
			str = common.Bytes2Hex(common.LeftPadBytes(common.Big(str).Bytes(), 32))
		}

		dataStr += str
	}
	object["data"] = dataStr

	conv := make(map[string]string)
	for key, value := range object {
		if v, ok := value.(string); ok {
			conv[key] = v
		}
	}

	return conv
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"flag"
	"log"
	"net/http"

	"comail.io/go/colog"
	"golang.org/x/net/http2"

	"github.com/ninibe/bigduration"
	"github.com/ninibe/netlog"
	"github.com/ninibe/netlog/transport"
)

var (
	debug         = flag.Bool("debug", false, "Start on debug mode")
	listen        = flag.String("listen", ":7200", "Listen address")
	dataDir       = flag.String("dir", "./data", "Data folder")
	logLevel      = flag.String("loglevel", "info", "Logging level")
	monInterval   = flag.String("monitor_interval", "10s", "Interval for segment size and age checks")
	segAge        = flag.String("segment_age", "30day", "Time since the last write in a segment until it gets discarded")
	segSize       = flag.Int64("segment_size", 1024*1024*1024, "Maximum topic segment size in bytes")
	batchNum      = flag.Int("batch_num_messages", 100, "Default maximum number of messages to be batched")
	batchInterval = flag.String("batch_interval", "200ms", "Default interval at which batched messages are flushed to disk.")
	compression   = flag.Int("compression", 1, "Default compression for batches: 0 = none, 1 = gzip, 2 = snappy")
)

func main() {
	flag.Parse()
	colog.Register()

	ll, err := colog.ParseLevel(*logLevel)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}
	colog.SetMinLevel(ll)

	if *debug {
		colog.SetFlags(log.LstdFlags | log.Lshortfile)
		colog.SetMinLevel(colog.LTrace)
	}

	var server http.Server
	server.Addr = *listen
	http2.ConfigureServer(&server, nil)

	segAge, err := bigduration.ParseBigDuration(*segAge)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	mIterval, err := bigduration.ParseBigDuration(*monInterval)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	bInterval, err := bigduration.ParseBigDuration(*batchInterval)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	topSettings := netlog.TopicSettings{
		SegAge:           segAge,
		SegSize:          *segSize,
		BatchNumMessages: *batchNum,
		BatchInterval:    bInterval,
		CompressionType:  netlog.CompressionType(*compression),
	}

	nl, err := netlog.NewNetLog(*dataDir,
		netlog.DefaultTopicSettings(topSettings),
		netlog.MonitorInterval(mIterval))
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	http.Handle("/", transport.NewHTTPTransport(nl))
	log.Printf("info: listening on %q", server.Addr)
	log.Printf("info: data dir on %q", *dataDir)
	log.Fatalf("alert: %s\n", server.ListenAndServe())
	//	log.Fatal(server.ListenAndServeTLS(GenCertificate()))
}
<commit_msg>cmd: change flag value for no compression<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"flag"
	"log"
	"net/http"

	"comail.io/go/colog"
	"golang.org/x/net/http2"

	"github.com/ninibe/bigduration"
	"github.com/ninibe/netlog"
	"github.com/ninibe/netlog/transport"
)

var (
	debug         = flag.Bool("debug", false, "Start on debug mode")
	listen        = flag.String("listen", ":7200", "Listen address")
	dataDir       = flag.String("dir", "./data", "Data folder")
	logLevel      = flag.String("loglevel", "info", "Logging level")
	monInterval   = flag.String("monitor_interval", "10s", "Interval for segment size and age checks")
	segAge        = flag.String("segment_age", "30day", "Time since the last write in a segment until it gets discarded")
	segSize       = flag.Int64("segment_size", 1024*1024*1024, "Maximum topic segment size in bytes")
	batchNum      = flag.Int("batch_num_messages", 100, "Default maximum number of messages to be batched")
	batchInterval = flag.String("batch_interval", "200ms", "Default interval at which batched messages are flushed to disk.")
	compression   = flag.Int("compression", 1, "Default compression for batches: 1 = gzip, 2 = snappy, 3 = none")
)

func main() {
	flag.Parse()
	colog.Register()

	ll, err := colog.ParseLevel(*logLevel)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}
	colog.SetMinLevel(ll)

	if *debug {
		colog.SetFlags(log.LstdFlags | log.Lshortfile)
		colog.SetMinLevel(colog.LTrace)
	}

	var server http.Server
	server.Addr = *listen
	http2.ConfigureServer(&server, nil)

	segAge, err := bigduration.ParseBigDuration(*segAge)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	mIterval, err := bigduration.ParseBigDuration(*monInterval)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	bInterval, err := bigduration.ParseBigDuration(*batchInterval)
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	topSettings := netlog.TopicSettings{
		SegAge:           segAge,
		SegSize:          *segSize,
		BatchNumMessages: *batchNum,
		BatchInterval:    bInterval,
		CompressionType:  netlog.CompressionType(*compression),
	}

	nl, err := netlog.NewNetLog(*dataDir,
		netlog.DefaultTopicSettings(topSettings),
		netlog.MonitorInterval(mIterval))
	if err != nil {
		log.Fatalf("alert: %s\n", err)
	}

	http.Handle("/", transport.NewHTTPTransport(nl))
	log.Printf("info: listening on %q", server.Addr)
	log.Printf("info: data dir on %q", *dataDir)
	log.Fatalf("alert: %s\n", server.ListenAndServe())
	//	log.Fatal(server.ListenAndServeTLS(GenCertificate()))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/applidget/psdock"
	"log"
)

/*aletrnative main using the process type */

func main() {
	conf, err := psdock.ParseConfig()
	if err != nil {
		log.Fatal(err)
	}

	ps := psdock.NewProcess(conf)
	if err = ps.SetUser(); err != nil {
		log.Fatal(err)
	}
	ps.SetEnvVars()

	if err = ps.Start(); err != nil {
		log.Fatal(err)
	}

	for {
		status := <-ps.StatusChannel
		if status.Err != nil {
			//Should an error occur, we want to kill the process
			ps.Status = psdock.PROCESS_STOPPED
			ps.NotifyStatusChanged()
			termErr := ps.Terminate(5)
			log.Println(status.Err)
			log.Println(termErr)
			return
		}
		switch status.Status {
		case psdock.PROCESS_STARTED:
			go psdock.ManageSignals(ps)
		case psdock.PROCESS_RUNNING:

		case psdock.PROCESS_STOPPED:
			//If we arrive here, process is already stopped, and this has been notified
			return
		}
	}
}
<commit_msg>Deleted comment<commit_after>package main

import (
	"github.com/applidget/psdock"
	"log"
)

func main() {
	conf, err := psdock.ParseConfig()
	if err != nil {
		log.Fatal(err)
	}

	ps := psdock.NewProcess(conf)
	if err = ps.SetUser(); err != nil {
		log.Fatal(err)
	}
	ps.SetEnvVars()

	if err = ps.Start(); err != nil {
		log.Fatal(err)
	}

	for {
		status := <-ps.StatusChannel
		if status.Err != nil {
			//Should an error occur, we want to kill the process
			ps.Status = psdock.PROCESS_STOPPED
			ps.NotifyStatusChanged()
			termErr := ps.Terminate(5)
			log.Println(status.Err)
			log.Println(termErr)
			return
		}
		switch status.Status {
		case psdock.PROCESS_STARTED:
			go psdock.ManageSignals(ps)
		case psdock.PROCESS_RUNNING:

		case psdock.PROCESS_STOPPED:
			//If we arrive here, process is already stopped, and this has been notified
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

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

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/cri-o/server"
	"github.com/opencontainers/runc/libcontainer/selinux"
	"github.com/urfave/cli"
	"google.golang.org/grpc"
	"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

const (
	ocidRoot   = "/var/lib/ocid"
	conmonPath = "/usr/libexec/ocid/conmon"
	pausePath  = "/usr/libexec/ocid/pause"
)

// DefaultConfig returns the default configuration for ocid.
func DefaultConfig() *server.Config {
	return &server.Config{
		RootConfig: server.RootConfig{
			Root:         ocidRoot,
			SandboxDir:   filepath.Join(ocidRoot, "sandboxes"),
			ContainerDir: filepath.Join(ocidRoot, "containers"),
		},
		APIConfig: server.APIConfig{
			Listen: "/var/run/ocid.sock",
		},
		RuntimeConfig: server.RuntimeConfig{
			Runtime: "/usr/bin/runc",
			Conmon:  conmonPath,
			SELinux: selinux.SelinuxEnabled(),
		},
		ImageConfig: server.ImageConfig{
			Pause:      pausePath,
			ImageStore: filepath.Join(ocidRoot, "store"),
		},
	}
}

func mergeConfig(config *server.Config, ctx *cli.Context) error {
	// Override options set with the CLI.
	if ctx.GlobalIsSet("conmon") {
		config.Conmon = ctx.GlobalString("conmon")
	}
	if ctx.GlobalIsSet("pause") {
		config.Pause = ctx.GlobalString("pause")
	}
	if ctx.GlobalIsSet("root") {
		config.Root = ctx.GlobalString("root")
	}
	if ctx.GlobalIsSet("sandboxdir") {
		config.SandboxDir = ctx.GlobalString("sandboxdir")
	}
	if ctx.GlobalIsSet("containerdir") {
		config.ContainerDir = ctx.GlobalString("containerdir")
	}
	if ctx.GlobalIsSet("listen") {
		config.Listen = ctx.GlobalString("listen")
	}
	if ctx.GlobalIsSet("runtime") {
		config.Runtime = ctx.GlobalString("runtime")
	}
	if ctx.GlobalIsSet("selinux") {
		config.SELinux = ctx.GlobalBool("selinux")
	}
	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "ocid"
	app.Usage = "ocid server"
	app.Version = "0.0.1"
	app.Metadata = map[string]interface{}{
		"config": DefaultConfig(),
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "conmon",
			Usage: "path to the conmon executable",
		},
		cli.StringFlag{
			Name:  "pause",
			Usage: "path to the pause executable",
		},
		cli.StringFlag{
			Name:  "root",
			Usage: "ocid root dir",
		},
		cli.StringFlag{
			Name:  "sandboxdir",
			Usage: "ocid pod sandbox dir",
		},
		cli.StringFlag{
			Name:  "containerdir",
			Usage: "ocid container dir",
		},
		cli.StringFlag{
			Name:  "listen",
			Usage: "path to ocid socket",
		},
		cli.StringFlag{
			Name:  "runtime",
			Usage: "OCI runtime path",
		},
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug output for logging",
		},
		cli.BoolFlag{
			Name:  "selinux",
			Usage: "enable selinux support",
		},
		cli.StringFlag{
			Name:  "log",
			Value: "",
			Usage: "set the log file path where internal debug information is written",
		},
		cli.StringFlag{
			Name:  "log-format",
			Value: "text",
			Usage: "set the format used by logs ('text' (default), or 'json')",
		},
	}

	app.Before = func(c *cli.Context) error {
		// Load the configuration file.
		config := c.App.Metadata["config"].(*server.Config)
		if err := mergeConfig(config, c); err != nil {
			return err
		}

		if c.GlobalBool("debug") {
			logrus.SetLevel(logrus.DebugLevel)
		}

		if path := c.GlobalString("log"); path != "" {
			f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
			if err != nil {
				return err
			}
			logrus.SetOutput(f)
		}

		switch c.GlobalString("log-format") {
		case "text":
			// retain logrus's default.
		case "json":
			logrus.SetFormatter(new(logrus.JSONFormatter))
		default:
			return fmt.Errorf("unknown log-format %q", c.GlobalString("log-format"))
		}

		return nil
	}

	app.Action = func(c *cli.Context) error {
		config := c.App.Metadata["config"].(*server.Config)

		if !config.SELinux {
			selinux.SetDisabled()
		}

		if _, err := os.Stat(config.Runtime); os.IsNotExist(err) {
			// path to runtime does not exist
			return fmt.Errorf("invalid --runtime value %q", err)
		}

		// Remove the socket if it already exists
		if _, err := os.Stat(config.Listen); err == nil {
			if err := os.Remove(config.Listen); err != nil {
				logrus.Fatal(err)
			}
		}
		lis, err := net.Listen("unix", config.Listen)
		if err != nil {
			logrus.Fatalf("failed to listen: %v", err)
		}

		s := grpc.NewServer()

		service, err := server.New(config)
		if err != nil {
			logrus.Fatal(err)
		}

		runtime.RegisterRuntimeServiceServer(s, service)
		runtime.RegisterImageServiceServer(s, service)
		if err := s.Serve(lis); err != nil {
			logrus.Fatal(err)
		}
		return nil
	}

	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}
<commit_msg>ocid: add TOML configuration file<commit_after>package main

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

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/cri-o/server"
	"github.com/opencontainers/runc/libcontainer/selinux"
	"github.com/urfave/cli"
	"google.golang.org/grpc"
	"k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

const (
	ocidRoot      = "/var/lib/ocid"
	conmonPath    = "/usr/libexec/ocid/conmon"
	pausePath     = "/usr/libexec/ocid/pause"
	ociConfigPath = "/etc/ocid.conf"
)

// DefaultConfig returns the default configuration for ocid.
func DefaultConfig() *server.Config {
	return &server.Config{
		RootConfig: server.RootConfig{
			Root:         ocidRoot,
			SandboxDir:   filepath.Join(ocidRoot, "sandboxes"),
			ContainerDir: filepath.Join(ocidRoot, "containers"),
		},
		APIConfig: server.APIConfig{
			Listen: "/var/run/ocid.sock",
		},
		RuntimeConfig: server.RuntimeConfig{
			Runtime: "/usr/bin/runc",
			Conmon:  conmonPath,
			SELinux: selinux.SelinuxEnabled(),
		},
		ImageConfig: server.ImageConfig{
			Pause:      pausePath,
			ImageStore: filepath.Join(ocidRoot, "store"),
		},
	}
}

func mergeConfig(config *server.Config, ctx *cli.Context) error {
	// Don't parse the config if the user explicitly set it to "".
	if path := ctx.GlobalString("config"); path != "" {
		if err := config.FromFile(path); err != nil {
			if ctx.GlobalIsSet("config") || !os.IsNotExist(err) {
				return err
			}

			// We don't error out if --config wasn't explicitly set and the
			// default doesn't exist. But we will log a warning about it, so
			// the user doesn't miss it.
			logrus.Warnf("default configuration file does not exist: %s", ociConfigPath)
		}
	}

	// Override options set with the CLI.
	if ctx.GlobalIsSet("conmon") {
		config.Conmon = ctx.GlobalString("conmon")
	}
	if ctx.GlobalIsSet("pause") {
		config.Pause = ctx.GlobalString("pause")
	}
	if ctx.GlobalIsSet("root") {
		config.Root = ctx.GlobalString("root")
	}
	if ctx.GlobalIsSet("sandboxdir") {
		config.SandboxDir = ctx.GlobalString("sandboxdir")
	}
	if ctx.GlobalIsSet("containerdir") {
		config.ContainerDir = ctx.GlobalString("containerdir")
	}
	if ctx.GlobalIsSet("listen") {
		config.Listen = ctx.GlobalString("listen")
	}
	if ctx.GlobalIsSet("runtime") {
		config.Runtime = ctx.GlobalString("runtime")
	}
	if ctx.GlobalIsSet("selinux") {
		config.SELinux = ctx.GlobalBool("selinux")
	}
	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "ocid"
	app.Usage = "ocid server"
	app.Version = "0.0.1"
	app.Metadata = map[string]interface{}{
		"config": DefaultConfig(),
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config",
			Value: ociConfigPath,
			Usage: "path to configuration file",
		},
		cli.StringFlag{
			Name:  "conmon",
			Usage: "path to the conmon executable",
		},
		cli.StringFlag{
			Name:  "pause",
			Usage: "path to the pause executable",
		},
		cli.StringFlag{
			Name:  "root",
			Usage: "ocid root dir",
		},
		cli.StringFlag{
			Name:  "sandboxdir",
			Usage: "ocid pod sandbox dir",
		},
		cli.StringFlag{
			Name:  "containerdir",
			Usage: "ocid container dir",
		},
		cli.StringFlag{
			Name:  "listen",
			Usage: "path to ocid socket",
		},
		cli.StringFlag{
			Name:  "runtime",
			Usage: "OCI runtime path",
		},
		cli.BoolFlag{
			Name:  "debug",
			Usage: "enable debug output for logging",
		},
		cli.BoolFlag{
			Name:  "selinux",
			Usage: "enable selinux support",
		},
		cli.StringFlag{
			Name:  "log",
			Value: "",
			Usage: "set the log file path where internal debug information is written",
		},
		cli.StringFlag{
			Name:  "log-format",
			Value: "text",
			Usage: "set the format used by logs ('text' (default), or 'json')",
		},
	}

	app.Before = func(c *cli.Context) error {
		// Load the configuration file.
		config := c.App.Metadata["config"].(*server.Config)
		if err := mergeConfig(config, c); err != nil {
			return err
		}

		if c.GlobalBool("debug") {
			logrus.SetLevel(logrus.DebugLevel)
		}

		if path := c.GlobalString("log"); path != "" {
			f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
			if err != nil {
				return err
			}
			logrus.SetOutput(f)
		}

		switch c.GlobalString("log-format") {
		case "text":
			// retain logrus's default.
		case "json":
			logrus.SetFormatter(new(logrus.JSONFormatter))
		default:
			return fmt.Errorf("unknown log-format %q", c.GlobalString("log-format"))
		}

		return nil
	}

	app.Action = func(c *cli.Context) error {
		config := c.App.Metadata["config"].(*server.Config)

		if !config.SELinux {
			selinux.SetDisabled()
		}

		if _, err := os.Stat(config.Runtime); os.IsNotExist(err) {
			// path to runtime does not exist
			return fmt.Errorf("invalid --runtime value %q", err)
		}

		// Remove the socket if it already exists
		if _, err := os.Stat(config.Listen); err == nil {
			if err := os.Remove(config.Listen); err != nil {
				logrus.Fatal(err)
			}
		}
		lis, err := net.Listen("unix", config.Listen)
		if err != nil {
			logrus.Fatalf("failed to listen: %v", err)
		}

		s := grpc.NewServer()

		service, err := server.New(config)
		if err != nil {
			logrus.Fatal(err)
		}

		runtime.RegisterRuntimeServiceServer(s, service)
		runtime.RegisterImageServiceServer(s, service)
		if err := s.Serve(lis); err != nil {
			logrus.Fatal(err)
		}
		return nil
	}

	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// shade presents a fuse filesystem interface.
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"time"

	_ "expvar"
	_ "net/http/pprof"

	"bazil.org/fuse"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/config"
	"github.com/asjoyner/shade/drive"
	"github.com/asjoyner/shade/fusefs"

	_ "github.com/asjoyner/shade/drive/amazon"
	_ "github.com/asjoyner/shade/drive/cache"
	_ "github.com/asjoyner/shade/drive/encrypt"
	_ "github.com/asjoyner/shade/drive/google"
	_ "github.com/asjoyner/shade/drive/local"
	_ "github.com/asjoyner/shade/drive/memory"
)

var (
	defaultConfig = path.Join(shade.ConfigDir(), "config.json")

	readOnly   = flag.Bool("readonly", false, "Mount the filesystem read only.")
	allowOther = flag.Bool("allow_other", false, "If other users are allowed to view the mounted filesystem.")
	configFile = flag.String("config", defaultConfig, fmt.Sprintf("The shade config file. Defaults to %q", defaultConfig))
	treeDebug  = flag.Bool("treeDebug", false, "Print Node tree debugging traces")
	port       = flag.Int("port", 33247, "HTTP port to listen on (exposes debug and monitoring handlers).")
)

func main() {
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() != 1 {
		usage()
		os.Exit(2)
	}

	// initialize the webserver
	go func() { log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)) }()

	// read in the config
	config, err := config.Read(*configFile)
	if err != nil {
		log.Fatalf("could not read configuration: %s\n", err)
	}

	// initialize client
	client, err := drive.NewClient(config)
	if err != nil {
		log.Fatalf("could not initialize client: %s\n", err)
	}

	// Setup fuse FS
	conn, err := mountFuse(flag.Arg(0))
	if err != nil {
		log.Fatalf("failed to mount: %s", err)
	}
	fmt.Printf("Mounting Shade FuseFS at %s...\n", flag.Arg(0))

	if err := serviceFuse(conn, client); err != nil {
		log.Fatalf("failed to service mount: %s", err)
	}

	return
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s <mountpoint>\n", os.Args[0])
	flag.PrintDefaults()
}

func mountFuse(mountPoint string) (*fuse.Conn, error) {
	if err := sanityCheck(mountPoint); err != nil {
		return nil, fmt.Errorf("sanityCheck failed: %s", err)
	}

	options := []fuse.MountOption{
		fuse.FSName("Shade"),
		//fuse.Subtype(""),
		//fuse.VolumeName(<iterate clients?>),
	}

	if *allowOther {
		options = append(options, fuse.AllowOther())
	}
	if *readOnly {
		options = append(options, fuse.ReadOnly())
	}
	options = append(options, fuse.NoAppleDouble())
	c, err := fuse.Mount(mountPoint, options...)
	if err != nil {
		fmt.Println("Is the mount point busy?")
		return nil, err
	}

	// Trap control-c (sig INT) and unmount
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt)
	go func() {
		for range sig {
			if err := fuse.Unmount(mountPoint); err != nil {
				log.Printf("fuse.Unmount failed: %v", err)
			}
		}
	}()

	return c, nil
}

// serviceFuse initializes fusefs, the shade implementation of a fuse file
// server, and services requests from the fuse kernel filesystem until it is
// unmounted.
func serviceFuse(conn *fuse.Conn, client drive.Client) error {
	refresh := time.NewTicker(5 * time.Minute)
	ffs, err := fusefs.New(client, conn, refresh)
	if err != nil {
		return fmt.Errorf("fuse server initialization failed: %s", err)
	}

	http.HandleFunc("/refresh", func(w http.ResponseWriter, r *http.Request) {
		ffs.Refresh()
		fmt.Fprintf(w, "Ok")
	})

	go func() {
		<-conn.Ready // block until the fuse FS is mounted and ready
		if err := conn.MountError; err != nil {
			fmt.Printf("mounting fuse fs failed: %s", err)
		}
		fmt.Println("Shade FuseFS mounted and ready to serve.")
	}()

	err = ffs.Serve()
	if err != nil {
		return fmt.Errorf("serving fuse connection failed: %s", err)
	}
	return nil

}

func sanityCheck(mountPoint string) error {
	fileInfo, err := os.Stat(mountPoint)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(mountPoint, 0777); err != nil {
			return fmt.Errorf("mountpoint does not exist, could not create it")
		}
		return nil
	}
	if err != nil {
		return fmt.Errorf("error stat()ing mountpoint: %s", err)
	}
	if !fileInfo.IsDir() {
		return fmt.Errorf("the mountpoint is not a directory")
	}
	return nil
}
<commit_msg>Optimize FUSE mount options<commit_after>// shade presents a fuse filesystem interface.
package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"time"

	_ "expvar"
	_ "net/http/pprof"

	"bazil.org/fuse"

	"github.com/asjoyner/shade"
	"github.com/asjoyner/shade/config"
	"github.com/asjoyner/shade/drive"
	"github.com/asjoyner/shade/fusefs"

	_ "github.com/asjoyner/shade/drive/amazon"
	_ "github.com/asjoyner/shade/drive/cache"
	_ "github.com/asjoyner/shade/drive/encrypt"
	_ "github.com/asjoyner/shade/drive/google"
	_ "github.com/asjoyner/shade/drive/local"
	_ "github.com/asjoyner/shade/drive/memory"
)

var (
	defaultConfig = path.Join(shade.ConfigDir(), "config.json")

	readOnly   = flag.Bool("readonly", false, "Mount the filesystem read only.")
	allowOther = flag.Bool("allow_other", false, "If other users are allowed to view the mounted filesystem.")
	configFile = flag.String("config", defaultConfig, fmt.Sprintf("The shade config file. Defaults to %q", defaultConfig))
	treeDebug  = flag.Bool("treeDebug", false, "Print Node tree debugging traces")
	port       = flag.Int("port", 33247, "HTTP port to listen on (exposes debug and monitoring handlers).")
)

func main() {
	flag.Usage = usage
	flag.Parse()

	if flag.NArg() != 1 {
		usage()
		os.Exit(2)
	}

	// initialize the webserver
	go func() { log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)) }()

	// read in the config
	config, err := config.Read(*configFile)
	if err != nil {
		log.Fatalf("could not read configuration: %s\n", err)
	}

	// initialize client
	client, err := drive.NewClient(config)
	if err != nil {
		log.Fatalf("could not initialize client: %s\n", err)
	}

	// Setup fuse FS
	conn, err := mountFuse(flag.Arg(0))
	if err != nil {
		log.Fatalf("failed to mount: %s", err)
	}
	fmt.Printf("Mounting Shade FuseFS at %s...\n", flag.Arg(0))

	if err := serviceFuse(conn, client); err != nil {
		log.Fatalf("failed to service mount: %s", err)
	}

	return
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s <mountpoint>\n", os.Args[0])
	flag.PrintDefaults()
}

func mountFuse(mountPoint string) (*fuse.Conn, error) {
	if err := sanityCheck(mountPoint); err != nil {
		return nil, fmt.Errorf("sanityCheck failed: %s", err)
	}

	options := []fuse.MountOption{
		fuse.FSName("Shade"),
		fuse.MaxReadahead(64 * 1024 * 1024), // in bytes
		fuse.AsyncRead(),
		fuse.WritebackCache(),
	}

	if *allowOther {
		options = append(options, fuse.AllowOther())
	}
	if *readOnly {
		options = append(options, fuse.ReadOnly())
	}
	options = append(options, fuse.NoAppleDouble())
	c, err := fuse.Mount(mountPoint, options...)
	if err != nil {
		fmt.Println("Is the mount point busy?")
		return nil, err
	}

	// Trap control-c (sig INT) and unmount
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt)
	go func() {
		for range sig {
			if err := fuse.Unmount(mountPoint); err != nil {
				log.Printf("fuse.Unmount failed: %v", err)
			}
		}
	}()

	return c, nil
}

// serviceFuse initializes fusefs, the shade implementation of a fuse file
// server, and services requests from the fuse kernel filesystem until it is
// unmounted.
func serviceFuse(conn *fuse.Conn, client drive.Client) error {
	refresh := time.NewTicker(5 * time.Minute)
	ffs, err := fusefs.New(client, conn, refresh)
	if err != nil {
		return fmt.Errorf("fuse server initialization failed: %s", err)
	}

	http.HandleFunc("/refresh", func(w http.ResponseWriter, r *http.Request) {
		ffs.Refresh()
		fmt.Fprintf(w, "Ok")
	})

	go func() {
		<-conn.Ready // block until the fuse FS is mounted and ready
		if err := conn.MountError; err != nil {
			fmt.Printf("mounting fuse fs failed: %s", err)
		}
		fmt.Println("Shade FuseFS mounted and ready to serve.")
	}()

	err = ffs.Serve()
	if err != nil {
		return fmt.Errorf("serving fuse connection failed: %s", err)
	}
	return nil

}

func sanityCheck(mountPoint string) error {
	fileInfo, err := os.Stat(mountPoint)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(mountPoint, 0777); err != nil {
			return fmt.Errorf("mountpoint does not exist, could not create it")
		}
		return nil
	}
	if err != nil {
		return fmt.Errorf("error stat()ing mountpoint: %s", err)
	}
	if !fileInfo.IsDir() {
		return fmt.Errorf("the mountpoint is not a directory")
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
tchaik creates a webserver which serves the web UI.

It is assumed that tchaik is run relatively local to the user (i.e. serving pages to the local machine, or a local
network).

All configuration is done through command line parameters.

A common use case is to begin by use using an existing iTunes Library file:

  tchaik -itlXML /path/to/iTunesMusicLibrary.xml

*/
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"tchaik.com/index"
	"tchaik.com/index/attr"
	"tchaik.com/index/checklist"
	"tchaik.com/index/cursor"
	"tchaik.com/index/favourite"
	"tchaik.com/index/history"
	"tchaik.com/index/itl"
	"tchaik.com/index/playlist"
	"tchaik.com/index/walk"
	"tchaik.com/store"
	"tchaik.com/store/cmdflag"
)

var debug bool
var itlXML, tchLib, walkPath string

var playHistoryPath, favouritesPath, checklistPath, playlistPath, cursorPath string

var listenAddr string
var uiDir string
var certFile, keyFile string

var authUser, authPassword string

var traceListenAddr string

func init() {
	flag.BoolVar(&debug, "debug", false, "print debugging information")

	flag.StringVar(&listenAddr, "listen", "localhost:8080", "bind `address` for main HTTP server")
	flag.StringVar(&certFile, "tls-cert", "", "certificate `file`, must also specify -tls-key")
	flag.StringVar(&keyFile, "tls-key", "", "certificate key `file`, must also specify -tls-cert")

	flag.StringVar(&itlXML, "itlXML", "", "iTunes Library XML `file`")
	flag.StringVar(&tchLib, "lib", "", "Tchaik library `file`")
	flag.StringVar(&walkPath, "path", "", "`directory` containing music files")

	flag.StringVar(&playHistoryPath, "play-history", "history.json", "play history `file`")
	flag.StringVar(&favouritesPath, "favourites", "favourites.json", "favourites `file`")
	flag.StringVar(&checklistPath, "checklist", "checklist.json", "checklist `file`")
	flag.StringVar(&playlistPath, "playlists", "playlists.json", "playlists `file`")
	flag.StringVar(&cursorPath, "cursors", "cursors.json", "cursors `file`")

	flag.StringVar(&uiDir, "ui-dir", "ui", "UI asset `directory`")

	flag.StringVar(&authUser, "auth-user", "", "`user` to use for HTTP authentication (set to enable)")
	flag.StringVar(&authPassword, "auth-password", "", "`password` to use for HTTP authentication")

	flag.StringVar(&traceListenAddr, "trace-listen", "", "bind `address` for trace HTTP server")
}

func readLibrary() (index.Library, error) {
	var count int
	check := func(x string) {
		if x != "" {
			count++
		}
	}
	check(itlXML)
	check(tchLib)
	check(walkPath)

	switch {
	case count == 0:
		return nil, fmt.Errorf("must specify one library file or a path to build one from (-itlXML, -lib or -path)")
	case count > 1:
		return nil, fmt.Errorf("must only specify one library file or a path to build one from (-itlXML, -lib or -path)")
	}

	var lib index.Library
	switch {
	case tchLib != "":
		f, err := os.Open(tchLib)
		if err != nil {
			return nil, fmt.Errorf("could not open Tchaik library file: %v", err)
		}
		defer f.Close()

		fmt.Printf("Parsing %v...", tchLib)
		lib, err = index.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing Tchaik library file: %v\n", err)
		}
		fmt.Println("done.")
		return lib, nil

	case itlXML != "":
		f, err := os.Open(itlXML)
		if err != nil {
			return nil, fmt.Errorf("could open iTunes library file: %v", err)
		}
		defer f.Close()

		lib, err = itl.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing iTunes library file: %v", err)
		}

	case walkPath != "":
		fmt.Printf("Walking %v...\n", walkPath)
		lib = walk.NewLibrary(walkPath)
		fmt.Println("Finished walking.")
	}

	fmt.Printf("Building Tchaik Library...")
	lib = index.Convert(lib, "ID")
	fmt.Println("done.")
	return lib, nil
}

func buildRootCollection(l index.Library) index.Collection {
	root := index.Collect(l, index.By(attr.String("Album")))
	index.SortKeysByGroupName(root)
	return root
}

func buildSearchIndex(c index.Collection) index.Searcher {
	wi := index.BuildCollectionWordIndex(c, []string{"Composer", "Artist", "Album", "Name"})
	return index.FlatSearcher{
		Searcher: index.WordsIntersectSearcher(index.BuildPrefixExpandSearcher(wi, wi, 10)),
	}
}

func main() {
	flag.Parse()
	l, err := readLibrary()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Building root collection...")
	root := buildRootCollection(l)
	fmt.Println("done.")

	fmt.Printf("Processing artist names and composers...")
	rootSplit := index.SubTransform(root, index.SplitList("Artist", "Composer"))
	fmt.Println("done.")

	fmt.Printf("Building artists filter...")
	artists := index.Filter(rootSplit, attr.Strings("Artist"))
	fmt.Println("done.")

	fmt.Printf("Building composers filter...")
	composers := index.Filter(rootSplit, attr.Strings("Composer"))
	fmt.Println("done.")

	fmt.Printf("Building recent index...")
	recent := index.Recent(root, 150)
	fmt.Println("done.")

	fmt.Printf("Building search index...")
	searcher := buildSearchIndex(root)
	fmt.Println("done.")

	fmt.Printf("Loading play history...")
	playHistoryStore, err := history.NewStore(playHistoryPath)
	if err != nil {
		fmt.Printf("\nerror loading play history: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading favourites...")
	favouriteStore, err := favourite.NewStore(favouritesPath)
	if err != nil {
		fmt.Printf("\nerror loading favourites: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading checklist...")
	checklistStore, err := checklist.NewStore(checklistPath)
	if err != nil {
		fmt.Printf("\nerror loading checklist: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading playlists...")
	playlistStore, err := playlist.NewStore(playlistPath)
	if err != nil {
		fmt.Printf("\nerror loading playlists: %v", err)
		os.Exit(1)
	}
	// TODO(dhowden): remove this once we can better intialise the "Default" playlist
	if p := playlistStore.Get("Default"); p == nil {
		playlistStore.Set("Default", &playlist.Playlist{})
	}
	fmt.Println("done")

	fmt.Printf("Loading cursors...")
	cursorStore, err := cursor.NewStore(cursorPath)
	if err != nil {
		fmt.Printf("\nerror loading cursor: %v", err)
		os.Exit(1)
	}
	fmt.Println("done")

	mediaFileSystem, artworkFileSystem, err := cmdflag.Stores()
	if err != nil {
		fmt.Println("error setting up stores:", err)
		os.Exit(1)
	}

	if debug {
		mediaFileSystem = store.LogFileSystem("Media", mediaFileSystem)
		artworkFileSystem = store.LogFileSystem("Artwork", artworkFileSystem)
	}

	if traceListenAddr != "" {
		fmt.Printf("Starting trace server on http://%v\n", traceListenAddr)
		go func() {
			log.Fatal(http.ListenAndServe(traceListenAddr, nil))
		}()
	}

	lib := Library{
		Library: l,
		collections: map[string]index.Collection{
			"Root": root,
		},
		filters: map[string][]index.FilterItem{
			"Artist":   artists,
			"Composer": composers,
		},
		recent:   recent,
		searcher: searcher,
	}

	meta := &Meta{
		history:    playHistoryStore,
		favourites: favouriteStore,
		checklist:  checklistStore,
		playlists:  playlistStore,
		cursors:    cursorStore,
	}

	h := NewHandler(lib, meta, mediaFileSystem, artworkFileSystem)

	if certFile != "" && keyFile != "" {
		fmt.Printf("Web server is running on https://%v\n", listenAddr)
		fmt.Println("Quit the server with CTRL-C.")

		tlsConfig := &tls.Config{MinVersion: tls.VersionTLS10}
		server := &http.Server{Addr: listenAddr, Handler: h, TLSConfig: tlsConfig}
		log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
	}

	fmt.Printf("Web server is running on http://%v\n", listenAddr)
	fmt.Println("Quit the server with CTRL-C.")

	log.Fatal(http.ListenAndServe(listenAddr, h))
}
<commit_msg>Expand struct formatting.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
tchaik creates a webserver which serves the web UI.

It is assumed that tchaik is run relatively local to the user (i.e. serving pages to the local machine, or a local
network).

All configuration is done through command line parameters.

A common use case is to begin by use using an existing iTunes Library file:

  tchaik -itlXML /path/to/iTunesMusicLibrary.xml

*/
package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"

	"tchaik.com/index"
	"tchaik.com/index/attr"
	"tchaik.com/index/checklist"
	"tchaik.com/index/cursor"
	"tchaik.com/index/favourite"
	"tchaik.com/index/history"
	"tchaik.com/index/itl"
	"tchaik.com/index/playlist"
	"tchaik.com/index/walk"
	"tchaik.com/store"
	"tchaik.com/store/cmdflag"
)

var debug bool
var itlXML, tchLib, walkPath string

var playHistoryPath, favouritesPath, checklistPath, playlistPath, cursorPath string

var listenAddr string
var uiDir string
var certFile, keyFile string

var authUser, authPassword string

var traceListenAddr string

func init() {
	flag.BoolVar(&debug, "debug", false, "print debugging information")

	flag.StringVar(&listenAddr, "listen", "localhost:8080", "bind `address` for main HTTP server")
	flag.StringVar(&certFile, "tls-cert", "", "certificate `file`, must also specify -tls-key")
	flag.StringVar(&keyFile, "tls-key", "", "certificate key `file`, must also specify -tls-cert")

	flag.StringVar(&itlXML, "itlXML", "", "iTunes Library XML `file`")
	flag.StringVar(&tchLib, "lib", "", "Tchaik library `file`")
	flag.StringVar(&walkPath, "path", "", "`directory` containing music files")

	flag.StringVar(&playHistoryPath, "play-history", "history.json", "play history `file`")
	flag.StringVar(&favouritesPath, "favourites", "favourites.json", "favourites `file`")
	flag.StringVar(&checklistPath, "checklist", "checklist.json", "checklist `file`")
	flag.StringVar(&playlistPath, "playlists", "playlists.json", "playlists `file`")
	flag.StringVar(&cursorPath, "cursors", "cursors.json", "cursors `file`")

	flag.StringVar(&uiDir, "ui-dir", "ui", "UI asset `directory`")

	flag.StringVar(&authUser, "auth-user", "", "`user` to use for HTTP authentication (set to enable)")
	flag.StringVar(&authPassword, "auth-password", "", "`password` to use for HTTP authentication")

	flag.StringVar(&traceListenAddr, "trace-listen", "", "bind `address` for trace HTTP server")
}

func readLibrary() (index.Library, error) {
	var count int
	check := func(x string) {
		if x != "" {
			count++
		}
	}
	check(itlXML)
	check(tchLib)
	check(walkPath)

	switch {
	case count == 0:
		return nil, fmt.Errorf("must specify one library file or a path to build one from (-itlXML, -lib or -path)")
	case count > 1:
		return nil, fmt.Errorf("must only specify one library file or a path to build one from (-itlXML, -lib or -path)")
	}

	var lib index.Library
	switch {
	case tchLib != "":
		f, err := os.Open(tchLib)
		if err != nil {
			return nil, fmt.Errorf("could not open Tchaik library file: %v", err)
		}
		defer f.Close()

		fmt.Printf("Parsing %v...", tchLib)
		lib, err = index.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing Tchaik library file: %v\n", err)
		}
		fmt.Println("done.")
		return lib, nil

	case itlXML != "":
		f, err := os.Open(itlXML)
		if err != nil {
			return nil, fmt.Errorf("could open iTunes library file: %v", err)
		}
		defer f.Close()

		lib, err = itl.ReadFrom(f)
		if err != nil {
			return nil, fmt.Errorf("error parsing iTunes library file: %v", err)
		}

	case walkPath != "":
		fmt.Printf("Walking %v...\n", walkPath)
		lib = walk.NewLibrary(walkPath)
		fmt.Println("Finished walking.")
	}

	fmt.Printf("Building Tchaik Library...")
	lib = index.Convert(lib, "ID")
	fmt.Println("done.")
	return lib, nil
}

func buildRootCollection(l index.Library) index.Collection {
	root := index.Collect(l, index.By(attr.String("Album")))
	index.SortKeysByGroupName(root)
	return root
}

func buildSearchIndex(c index.Collection) index.Searcher {
	wi := index.BuildCollectionWordIndex(c, []string{"Composer", "Artist", "Album", "Name"})
	return index.FlatSearcher{
		Searcher: index.WordsIntersectSearcher(index.BuildPrefixExpandSearcher(wi, wi, 10)),
	}
}

func main() {
	flag.Parse()
	l, err := readLibrary()
	if err != nil {
		fmt.Printf("error: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Building root collection...")
	root := buildRootCollection(l)
	fmt.Println("done.")

	fmt.Printf("Processing artist names and composers...")
	rootSplit := index.SubTransform(root, index.SplitList("Artist", "Composer"))
	fmt.Println("done.")

	fmt.Printf("Building artists filter...")
	artists := index.Filter(rootSplit, attr.Strings("Artist"))
	fmt.Println("done.")

	fmt.Printf("Building composers filter...")
	composers := index.Filter(rootSplit, attr.Strings("Composer"))
	fmt.Println("done.")

	fmt.Printf("Building recent index...")
	recent := index.Recent(root, 150)
	fmt.Println("done.")

	fmt.Printf("Building search index...")
	searcher := buildSearchIndex(root)
	fmt.Println("done.")

	fmt.Printf("Loading play history...")
	playHistoryStore, err := history.NewStore(playHistoryPath)
	if err != nil {
		fmt.Printf("\nerror loading play history: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading favourites...")
	favouriteStore, err := favourite.NewStore(favouritesPath)
	if err != nil {
		fmt.Printf("\nerror loading favourites: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading checklist...")
	checklistStore, err := checklist.NewStore(checklistPath)
	if err != nil {
		fmt.Printf("\nerror loading checklist: %v", err)
		os.Exit(1)
	}
	fmt.Println("done.")

	fmt.Printf("Loading playlists...")
	playlistStore, err := playlist.NewStore(playlistPath)
	if err != nil {
		fmt.Printf("\nerror loading playlists: %v", err)
		os.Exit(1)
	}
	// TODO(dhowden): remove this once we can better intialise the "Default" playlist
	if p := playlistStore.Get("Default"); p == nil {
		playlistStore.Set("Default", &playlist.Playlist{})
	}
	fmt.Println("done")

	fmt.Printf("Loading cursors...")
	cursorStore, err := cursor.NewStore(cursorPath)
	if err != nil {
		fmt.Printf("\nerror loading cursor: %v", err)
		os.Exit(1)
	}
	fmt.Println("done")

	mediaFileSystem, artworkFileSystem, err := cmdflag.Stores()
	if err != nil {
		fmt.Println("error setting up stores:", err)
		os.Exit(1)
	}

	if debug {
		mediaFileSystem = store.LogFileSystem("Media", mediaFileSystem)
		artworkFileSystem = store.LogFileSystem("Artwork", artworkFileSystem)
	}

	if traceListenAddr != "" {
		fmt.Printf("Starting trace server on http://%v\n", traceListenAddr)
		go func() {
			log.Fatal(http.ListenAndServe(traceListenAddr, nil))
		}()
	}

	lib := Library{
		Library: l,
		collections: map[string]index.Collection{
			"Root": root,
		},
		filters: map[string][]index.FilterItem{
			"Artist":   artists,
			"Composer": composers,
		},
		recent:   recent,
		searcher: searcher,
	}

	meta := &Meta{
		history:    playHistoryStore,
		favourites: favouriteStore,
		checklist:  checklistStore,
		playlists:  playlistStore,
		cursors:    cursorStore,
	}

	h := NewHandler(lib, meta, mediaFileSystem, artworkFileSystem)

	if certFile != "" && keyFile != "" {
		fmt.Printf("Web server is running on https://%v\n", listenAddr)
		fmt.Println("Quit the server with CTRL-C.")

		tlsConfig := &tls.Config{
			MinVersion: tls.VersionTLS10,
		}
		server := &http.Server{
			Addr:      listenAddr,
			Handler:   h,
			TLSConfig: tlsConfig,
		}
		log.Fatal(server.ListenAndServeTLS(certFile, keyFile))
	}

	fmt.Printf("Web server is running on http://%v\n", listenAddr)
	fmt.Println("Quit the server with CTRL-C.")

	log.Fatal(http.ListenAndServe(listenAddr, h))
}
<|endoftext|>