// CmdServiceInfo handles service info UI
489766
func (cli *NetworkCli) CmdServiceInfo(chain string, args ...string) error {
	cmd := cli.Subcmd(chain, "info", "SERVICE[.NETWORK]", "Displays detailed information about a service", false)
	cmd.Require(flag.Min, 1)

	err := cmd.ParseFlags(args, true)
	if err != nil {
		return err
	}

	sn, nn := parseServiceName(cmd.Arg(0))
	serviceID, err := lookupServiceID(cli, nn, sn)
	if err != nil {
		return err
	}

	obj, _, err := readBody(cli.call("GET", "/services/"+serviceID, nil, nil))
	if err != nil {
		return err
	}

	sr := &serviceResource{}
	if err := json.NewDecoder(bytes.NewReader(obj)).Decode(sr); err != nil {
		return err
	}

	fmt.Fprintf(cli.out, "Service Id: %s\n", sr.ID)
	fmt.Fprintf(cli.out, "\tName: %s\n", sr.Name)
	fmt.Fprintf(cli.out, "\tNetwork: %s\n", sr.Network)

	return nil
}
835411
func (c *removeCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "remove-user",
		Args:    "<user name>",
		Purpose: removeUsageSummary,
		Doc:     removeUsageDetails,
	})
}
495917
func (c *showCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "show-offer",
		Args:    "[<controller>:]<offer url>",
		Purpose: "Shows extended information about the offered application.",
		Doc:     showCommandDoc,
	})
}
377060
func (c *ServicedCli) cmdServiceConfigList(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) < 1 {
		fmt.Printf("Incorrect Usage.\n\n")
		cli.ShowCommandHelp(ctx, "list")
		c.exit(1)
		return
	}

	svcDetails, _, err := c.searchForService(args[0], ctx.Bool("no-prefix-match"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	service, err := c.driver.GetService(svcDetails.ID)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	configs := service.ConfigFiles

	if len(args) < 2 {
		configList := make([]string, 0)

		for filename := range configs {
			configList = append(configList, filename)
		}
		configJson := map[string]([]string){
			"ConfigFiles": configList,
		}
		if configJsonOut, err := json.MarshalIndent(configJson, " ", "  "); err != nil {
			fmt.Fprintln(os.Stderr, err)
			c.exit(1)
			return
		} else {
			fmt.Printf("%s\n\n", configJsonOut)
			return
		}
	} else {
		filename := args[1]
		if _, found := configs[filename]; found {
			fmt.Printf("%s", configs[filename].Content)
		} else {
			fmt.Printf("Config file %s not found.\n", filename)
			c.exit(1)
			return
		}
	}
	return
}
731197
func (Actor) CommandInfos(commandList interface{}) map[string]CommandInfo {
	handler := reflect.TypeOf(commandList)

	infos := make(map[string]CommandInfo, handler.NumField())
	for i := 0; i < handler.NumField(); i++ {
		fieldTag := handler.Field(i).Tag
		commandName := fieldTag.Get("command")
		infos[commandName] = CommandInfo{
			Name:        commandName,
			Description: fieldTag.Get("description"),
			Alias:       fieldTag.Get("alias"),
		}
	}

	return infos
}
1373645
func (c *ServicedCli) cmdServiceAction(ctx *cli.Context) error {
	// verify args
	args := ctx.Args()
	if len(args) < 1 {
		if !ctx.Bool("help") {
			fmt.Fprintf(os.Stderr, "Incorrect Usage.\n\n")
		}
		cli.ShowSubcommandHelp(ctx)
		c.exit(1)
		return nil
	}

	// Bash completion
	if args[len(args)-1] == "--generate-bash-completion" {
		// CC-892
		// if a tab is pressed after serviced service SERVICE_ID and the
		// service is found
		if len(args) == 2 {
			svc, _, err := c.searchForService(ctx.Args().First(), ctx.Bool("no-prefix-match"))
			if err == nil {
				actions := c.serviceActions(svc.ID)
				fmt.Println(strings.Join(actions, "\n"))
			} else {
				c.exit(1)
			}
		}
		return c.exit(0)
	}

	svc, instanceID, err := c.searchForService(ctx.Args().First(), ctx.Bool("no-prefix-match"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return err
	}

	switch len(args) {
	case 1:
		actions := c.serviceActions(svc.ID)
		if len(actions) > 0 {
			fmt.Println(strings.Join(actions, "\n"))
		} else {
			fmt.Fprintln(os.Stderr, "no actions found")
			c.exit(1)
		}
	default:
		if instanceID < 0 {
			instanceID = 0
		}
		action := ""
		argv := []string{}
		if len(args) > 1 {
			action = args[1]
			argv = args[2:]
		}

		if err := c.driver.SendDockerAction(svc.ID, instanceID, action, argv); err != nil {
			fmt.Fprintln(os.Stderr, err)
			c.exit(1)
		}
	}

	return fmt.Errorf("serviced service action")
}
1196291
func (c *loginCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "login",
		Args:    "[controller host name or alias]",
		Purpose: "Logs a user in to a controller.",
		Doc:     loginDoc,
	})
}
1162851
func (c GetCmd) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    GetCmdName,
		Args:    "<resource name>",
		Purpose: "get the path to the locally cached resource file",
		Doc: `
"resource-get" is used while a hook is running to get the local path
to the file for the identified resource. This file is an fs-local copy,
unique to the unit for which the hook is running. It is downloaded from
the controller, if necessary.

If "resource-get" for a resource has not been run before (for the unit)
then the resource is downloaded from the controller at the revision
associated with the unit's application. That file is stored in the unit's
local cache. If "resource-get" *has* been run before then each
subsequent run syncs the resource with the controller. This ensures
that the revision of the unit-local copy of the resource matches the
revision of the resource associated with the unit's application.

Either way, the path provided by "resource-get" references the
up-to-date file for the resource. Note that the resource may get
updated on the controller for the application at any time, meaning the
cached copy *may* be out of date at any time after you call
"resource-get". Consequently, the command should be run at every
point where it is critical that the resource be up to date.

The "upgrade-charm" hook is useful for keeping your charm's resources
on a unit up to date.  Run "resource-get" there for each of your
charm's resources to do so. The hook fires whenever the the file for
one of the application's resources changes on the controller (in addition
to when the charm itself changes). That means it happens in response
to "juju upgrade-charm" as well as to "juju push-resource".

Note that the "upgrade-charm" hook does not run when the unit is
started up. So be sure to run "resource-get" for your resources in the
"install" hook (or "config-changed", etc.).

Note that "resource-get" only provides an FS path to the resource file.
It does not provide any information about the resource (e.g. revision).
`,
	})
}
218766
func (c *MetricsCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "metrics",
		Args:    "[tag1[...tagN]]",
		Purpose: "Retrieve metrics collected by specified entities.",
		Doc:     metricsDoc,
	})
}
63183
func (c *modelCredentialCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "set-credential",
		Args:    "<cloud name> <credential name>",
		Purpose: "Relates a remote credential to a model.",
		Doc:     modelCredentialDoc,
	})
}
744801
func cmdInfo(cmd *cobra.Command, args []string) error {
	var version string
	if len(args) == 1 {
		version = args[0]
	}
	res, err := client.InfoSync(types.RequestInfo{Version: version})
	if err != nil {
		return err
	}
	printResponse(cmd, args, response{
		Data: []byte(res.Data),
	})
	return nil
}
685637
func (c *ServicedCli) cmdServiceEdit(ctx *cli.Context) {
	args := ctx.Args()
	if len(args) < 1 {
		fmt.Printf("Incorrect Usage.\n\n")
		cli.ShowCommandHelp(ctx, "edit")
		c.exit(1)
		return
	}

	svcDetails, _, err := c.searchForService(args[0], ctx.Bool("no-prefix-match"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	service, err := c.driver.GetService(svcDetails.ID)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	jsonService, err := json.MarshalIndent(service, " ", "  ")
	if err != nil {
		fmt.Fprintf(os.Stderr, "error marshalling service: %s\n", err)
		c.exit(1)
		return
	}

	name := fmt.Sprintf("serviced_service_edit_%s", service.ID)
	reader, err := openEditor(jsonService, name, ctx.String("editor"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	if service, err := c.driver.UpdateService(reader); err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
	} else if service == nil {
		fmt.Fprintln(os.Stderr, "received nil service")
		c.exit(1)
	} else {
		fmt.Println(service.ID)
	}
	return
}
371753
func (c *addCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "add-user",
		Args:    "<user name> [<display name>]",
		Purpose: usageSummary,
		Doc:     usageDetails,
	})
}
312656
func (c *disableCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "disable-user",
		Args:    "<user name>",
		Purpose: usageDisableUserSummary,
		Doc:     usageDisableUserDetails,
	})
}
1353514
func (c *updateCredentialCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "update-credential",
		Args:    "<cloud-name> <credential-name>",
		Purpose: usageUpdateCredentialSummary,
		Doc:     usageUpdateCredentialDetails,
	})
}
259238
func (c *ServicedCli) cmdServiceClearEmergency(ctx *cli.Context) {
	// verify args
	args := ctx.Args()
	if len(args) < 1 {
		fmt.Printf("Incorrect Usage.\n\n")
		cli.ShowCommandHelp(ctx, "clear-emergency")
		c.exit(1)
		return
	}

	svc, _, err := c.searchForService(ctx.Args().First(), ctx.Bool("no-prefix-match"))
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	count, err := c.driver.ClearEmergency(svc.ID)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		c.exit(1)
		return
	}

	fmt.Printf("Cleared emergency status for %d services\n", count)
	return
}
45586
func (c *trustCommand) Info() *cmd.Info {
	return jujucmd.Info(&cmd.Info{
		Name:    "trust",
		Args:    "<application name>",
		Purpose: trustSummary,
		Doc:     trustDetails,
	})
}