<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"syscall"
	"time"

	"github.com/ansel1/merry"
	"github.com/dickeyxxx/golock"
)

func init() {
	CLITopics = append(CLITopics, &Topic{
		Name:        "plugins",
		Description: "manage plugins",
		Commands: Commands{
			{
				Topic:            "plugins",
				Description:      "lists installed plugins",
				DisableAnalytics: true,
				Flags: []Flag{
					{Name: "core", Description: "show core plugins", Hidden: true},
				},
				Help: `
Example:
  $ heroku plugins`,

				Run: pluginsList,
			},
			{
				Topic:        "plugins",
				Command:      "install",
				VariableArgs: true,
				Description:  "installs a plugin",
				Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install heroku-production-status`,

				Run: pluginsInstall,
			},
			{
				Topic:       "plugins",
				Command:     "link",
				Description: "link a local plugin for development",
				Args:        []Arg{{Name: "path", Optional: true}},
				Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into the plugins directory
	and parses the plugin.

  Example:
	$ heroku plugins:link .`,

				Run: pluginsLink,
			},
			{
				Topic:       "plugins",
				Command:     "uninstall",
				Args:        []Arg{{Name: "name"}},
				Description: "uninstalls a plugin",
				Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

				Run: pluginsUninstall,
			},
		},
	})
}

func pluginsList(ctx *Context) {
	var names []string
	for _, plugin := range UserPlugins.Plugins() {
		symlinked := ""
		if UserPlugins.isPluginSymlinked(plugin.Name) {
			symlinked = " (symlinked)"
		}
		names = append(names, fmt.Sprintf("%s %s%s", plugin.Name, plugin.Version, symlinked))
	}
	if ctx.Flags["core"] != nil {
		UserPluginNames := UserPlugins.PluginNames()
		for _, plugin := range CorePlugins.Plugins() {
			if contains(UserPluginNames, plugin.Name) {
				continue
			}
			names = append(names, fmt.Sprintf("%s %s (core)", plugin.Name, plugin.Version))
		}
	}
	sort.Strings(names)
	for _, plugin := range names {
		Println(plugin)
	}<commit_msg>Add plugins --json, closes #392 (#421)<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"syscall"
	"time"

	"github.com/ansel1/merry"
	"github.com/dickeyxxx/golock"
)

func init() {
	CLITopics = append(CLITopics, &Topic{
		Name:        "plugins",
		Description: "manage plugins",
		Commands: Commands{
			{
				Topic:            "plugins",
				Description:      "lists installed plugins",
				DisableAnalytics: true,
				Flags: []Flag{
					{Name: "core", Description: "show core plugins", Hidden: true},
					{Name: "json", Description: "show core plugins as json"},
				},
				Help: `
Example:
  $ heroku plugins`,

				Run: pluginsList,
			},
			{
				Topic:        "plugins",
				Command:      "install",
				VariableArgs: true,
				Description:  "installs a plugin",
				Help: `Install a Heroku plugin

  Example:
  $ heroku plugins:install heroku-production-status`,

				Run: pluginsInstall,
			},
			{
				Topic:       "plugins",
				Command:     "link",
				Description: "link a local plugin for development",
				Args:        []Arg{{Name: "path", Optional: true}},
				Help: `Links a local plugin into CLI.
	This is useful when developing plugins locally.
	It simply symlinks the specified path into the plugins directory
	and parses the plugin.

  Example:
	$ heroku plugins:link .`,

				Run: pluginsLink,
			},
			{
				Topic:       "plugins",
				Command:     "uninstall",
				Args:        []Arg{{Name: "name"}},
				Description: "uninstalls a plugin",
				Help: `Uninstalls a Heroku plugin

  Example:
  $ heroku plugins:uninstall heroku-production-status`,

				Run: pluginsUninstall,
			},
		},
	})
}

type PluginPresenter struct {
	Name	  	string `json:"name"`
	Version 	string `json:"version"`
}
// Sorts PluginPresenters by Name
type NameSorter []PluginPresenter
func (a NameSorter) Len() int           { return len(a) }
func (a NameSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name }

func pluginsList(ctx *Context) {
	var names []string
	var pluginPresenters []PluginPresenter
	for _, plugin := range UserPlugins.Plugins() {
		symlinked := ""
		if UserPlugins.isPluginSymlinked(plugin.Name) {
			symlinked = " (symlinked)"
		}
		names = append(names, fmt.Sprintf("%s %s%s", plugin.Name, plugin.Version, symlinked))
		pluginPresenter := PluginPresenter{plugin.Name, fmt.Sprintf("%s%s", plugin.Version, symlinked)}
		pluginPresenters = append(pluginPresenters, pluginPresenter)
	}
	if ctx.Flags["core"] != nil {
		UserPluginNames := UserPlugins.PluginNames()
		for _, plugin := range CorePlugins.Plugins() {
			if contains(UserPluginNames, plugin.Name) {
				continue
			}
			names = append(names, fmt.Sprintf("%s %s (core)", plugin.Name, plugin.Version))
			pluginPresenter := PluginPresenter{plugin.Name, fmt.Sprintf("%s (core)", plugin.Version)}
			pluginPresenters = append(pluginPresenters, pluginPresenter)
		}
	}

	if ctx.Flags["json"] != nil {
		sort.Sort(NameSorter(pluginPresenters))
		pluginsJSON, _ := json.Marshal(pluginPresenters)
		Println(string(pluginsJSON))
	} else {
		sort.Strings(names)
		for _, plugin := range names {
			Println(plugin)
		}
	}
{'fraction_non_alphanumeric': 0.13766139298054192, 'fraction_numerical': 0.0014548099654482633, 'mean_word_length': 3.260263361735089, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5948472', 'n_tokens_mistral': 2094, 'n_tokens_neox': 1809, 'n_words': 465}