Skip to content

Commit

Permalink
Merge latest changes from feature-resources.
Browse files Browse the repository at this point in the history
  • Loading branch information
kat-co committed Feb 10, 2016
2 parents 803ff65 + fb530c0 commit 51f277b
Show file tree
Hide file tree
Showing 35 changed files with 851 additions and 256 deletions.
14 changes: 14 additions & 0 deletions api/facadeversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

package api

import (
"github.com/juju/errors"
)

// facadeVersions lists the best version of facades that we know about. This
// will be used to pick out a default version for communication, given the list
// of known versions that the API server tells us it is capable of supporting.
Expand Down Expand Up @@ -68,6 +72,16 @@ var facadeVersions = map[string]int{
"Undertaker": 1,
}

// RegisterFacadeVersion sets the API client to prefer the given version
// for the facade.
func RegisterFacadeVersion(name string, version int) error {
if ver, ok := facadeVersions[name]; ok && ver != version {
return errors.Errorf("facade %q already registered", name)
}
facadeVersions[name] = version
return nil
}

// bestVersion tries to find the newest version in the version list that we can
// use.
func bestVersion(desiredVersion int, versions []int) int {
Expand Down
46 changes: 46 additions & 0 deletions cmd/juju/charmcmd/charm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charmcmd

import (
"github.com/juju/cmd"
)

var charmDoc = `
"juju charm" is the the juju CLI equivalent of the "charm" command used
by charm authors, though only applicable functionality is mirrored.
`

const charmPurpose = "interact with charms"

// Command is the top-level command wrapping all backups functionality.
type Command struct {
cmd.SuperCommand
}

// NewSuperCommand returns a new charm super-command.
func NewSuperCommand() *Command {
charmCmd := &Command{
SuperCommand: *cmd.NewSuperCommand(
cmd.SuperCommandParams{
Name: "charm",
Doc: charmDoc,
UsagePrefix: "juju",
Purpose: charmPurpose,
},
),
}
spec := newCharmstoreSpec()

// Sub-commands may be registered directly here, like so:
//charmCmd.Register(newXXXCommand(spec))

// ...or externally via RegisterSubCommand().
for _, newSubCommand := range registeredSubCommands {
command := newSubCommand(spec)
charmCmd.Register(command)
}

return charmCmd
}
32 changes: 32 additions & 0 deletions cmd/juju/charmcmd/charm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charmcmd_test

import (
"github.com/juju/testing"
jc "github.com/juju/testing/checkers"
gc "gopkg.in/check.v1"

"github.com/juju/juju/cmd/juju/charmcmd"
)

type CharmSuite struct {
testing.IsolationSuite
}

var _ = gc.Suite(&CharmSuite{})

func (s *CharmSuite) SetUpTest(c *gc.C) {
s.IsolationSuite.SetUpTest(c)
}

// TODO(ericsnow) Copy some tests from cmd/juju/commands/main_test.go?

func (s *CharmSuite) Test(c *gc.C) {
return
// TODO(ericsnow) Finish!
chCmd := charmcmd.NewSuperCommand()

c.Check(chCmd, jc.DeepEquals, nil)
}
14 changes: 14 additions & 0 deletions cmd/juju/charmcmd/package_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charmcmd_test

import (
"testing"

gc "gopkg.in/check.v1"
)

func TestPackage(t *testing.T) {
gc.TestingT(t)
}
153 changes: 153 additions & 0 deletions cmd/juju/charmcmd/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charmcmd

import (
"io"
"net/http"
"os"

"github.com/juju/errors"
"github.com/juju/persistent-cookiejar"
"gopkg.in/juju/charmrepo.v2-unstable"
"gopkg.in/juju/charmrepo.v2-unstable/csclient"
"gopkg.in/macaroon-bakery.v1/httpbakery"
)

// TODO(ericsnow) Factor out code from cmd/juju/commands/common.go and
// cmd/envcmd/base.go into cmd/charmstore.go and cmd/apicontext.go. Then
// use those here instead of copy-and-pasting here.

// CharmstoreClient exposes the functionality of the charm store client.
type CharmstoreClient interface {
io.Closer
}

///////////////////
// The charmstoreSpec code is based loosely on code in cmd/juju/commands/deploy.go.

// CharmstoreSpec provides the functionality needed to open a charm
// store client.
type CharmstoreSpec interface {
// Connect connects to the specified charm store.
Connect() (CharmstoreClient, error)
}

type charmstoreSpec struct {
params charmrepo.NewCharmStoreParams
}

// newCharmstoreSpec creates a new charm store spec with default
// settings.
func newCharmstoreSpec() CharmstoreSpec {
return &charmstoreSpec{
params: charmrepo.NewCharmStoreParams{
//URL: We use the default.
//HTTPClient: We set it later.
VisitWebPage: httpbakery.OpenWebBrowser,
},
}
}

// Connect implements CharmstoreSpec.
func (cs charmstoreSpec) Connect() (CharmstoreClient, error) {
params, apiContext, err := cs.connect()
if err != nil {
return nil, errors.Trace(err)
}

baseClient := csclient.New(csclient.Params{
URL: params.URL,
HTTPClient: params.HTTPClient,
VisitWebPage: params.VisitWebPage,
})

csClient := &charmstoreClient{
Client: baseClient,
apiContext: apiContext,
}
return csClient, nil
}

// TODO(ericsnow) Also add charmstoreSpec.Repo() -> charmrepo.Interface?

func (cs charmstoreSpec) connect() (charmrepo.NewCharmStoreParams, *apiContext, error) {
apiContext, err := newAPIContext()
if err != nil {
return charmrepo.NewCharmStoreParams{}, nil, errors.Trace(err)
}

params := cs.params // a copy
params.HTTPClient = apiContext.HTTPClient()
return params, apiContext, nil
}

///////////////////
// charmstoreClient is based loosely on cmd/juju/commands/common.go.

type charmstoreClient struct {
*csclient.Client
*apiContext
}

// Close implements io.Closer.
func (cs *charmstoreClient) Close() error {
return cs.apiContext.Close()
}

///////////////////
// For the most part, apiContext is copied directly from cmd/envcmd/base.go.

// newAPIContext returns a new api context, which should be closed
// when done with.
func newAPIContext() (*apiContext, error) {
jar, err := cookiejar.New(&cookiejar.Options{
Filename: cookieFile(),
})
if err != nil {
return nil, errors.Trace(err)
}
client := httpbakery.NewClient()
client.Jar = jar
client.VisitWebPage = httpbakery.OpenWebBrowser

return &apiContext{
jar: jar,
client: client,
}, nil
}

// apiContext is a convenience type that can be embedded wherever
// we need an API connection.
// It also stores a bakery bakery client allowing the API
// to be used using macaroons to authenticate. It stores
// obtained macaroons and discharges in a cookie jar file.
type apiContext struct {
jar *cookiejar.Jar
client *httpbakery.Client
}

// Close saves the embedded cookie jar.
func (c *apiContext) Close() error {
if err := c.jar.Save(); err != nil {
return errors.Annotatef(err, "cannot save cookie jar")
}
return nil
}

// HTTPClient returns an http.Client that contains the loaded
// persistent cookie jar.
func (ctx *apiContext) HTTPClient() *http.Client {
return ctx.client.Client
}

// cookieFile returns the path to the cookie used to store authorization
// macaroons. The returned value can be overridden by setting the
// JUJU_COOKIEFILE or GO_COOKIEFILE environment variables.
func cookieFile() string {
if file := os.Getenv("JUJU_COOKIEFILE"); file != "" {
return file
}
return cookiejar.DefaultCookieFile()
}
45 changes: 45 additions & 0 deletions cmd/juju/charmcmd/sub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package charmcmd

import (
"github.com/juju/cmd"
"github.com/juju/errors"
)

var registeredSubCommands []func(CharmstoreSpec) cmd.Command

// RegisterSubCommand adds the provided func to the set of those that
// will be called when the juju command runs. Each returned command will
// be registered with the identified "juju" sub-supercommand.
func RegisterSubCommand(newCommand func(CharmstoreSpec) cmd.Command) {
registeredSubCommands = append(registeredSubCommands, newCommand)
}

// NewCommandBase returns a new CommandBase.
func NewCommandBase(spec CharmstoreSpec) *CommandBase {
return &CommandBase{
spec: newCharmstoreSpec(),
}
}

// CommandBase is the type that should be embedded in "juju charm"
// sub-commands.
type CommandBase struct {
cmd.CommandBase
spec CharmstoreSpec
}

// Connect implements CommandBase.
func (c *CommandBase) Connect() (CharmstoreClient, error) {
if c.spec == nil {
return nil, errors.Errorf("missing charm store spec")
}
client, err := c.spec.Connect()
if err != nil {
return nil, errors.Trace(err)
}

return client, nil
}
2 changes: 1 addition & 1 deletion cmd/juju/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func RegisterCommand(newCommand func() cmd.Command) {
registeredCommands = append(registeredCommands, newCommand)
}

// RegisterCommand adds the provided func to the set of those that will
// RegisterEnvCommand adds the provided func to the set of those that will
// be called when the juju command runs. Each returned command will be
// wrapped in envCmdWrapper, which is what gets registered with the
// "juju" supercommand.
Expand Down
2 changes: 2 additions & 0 deletions cmd/juju/commands/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/juju/juju/cmd/juju/backups"
"github.com/juju/juju/cmd/juju/block"
"github.com/juju/juju/cmd/juju/cachedimages"
"github.com/juju/juju/cmd/juju/charmcmd"
"github.com/juju/juju/cmd/juju/controller"
"github.com/juju/juju/cmd/juju/helptopics"
"github.com/juju/juju/cmd/juju/machine"
Expand Down Expand Up @@ -158,6 +159,7 @@ func registerCommands(r commandRegistry, ctx *cmd.Context) {

// Charm tool commands.
r.Register(newHelpToolCommand())
r.Register(charmcmd.NewSuperCommand())

// Manage backups.
r.Register(backups.NewSuperCommand())
Expand Down
7 changes: 3 additions & 4 deletions cmd/juju/commands/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,9 @@ var commandNames = []string{
"bootstrap",
"cached-images",
"change-user-password",
"collect-metrics",
"create-backup",
"create-budget",
"create-model",
"charm",
"create-environment",
"create-model", // alias for create-environment
"debug-hooks",
"debug-log",
"debug-metrics",
Expand Down
Loading

0 comments on commit 51f277b

Please sign in to comment.