mirror of
https://github.com/zyedidia/micro.git
synced 2026-03-29 22:27:13 +09:00
Start plugin support and plugin manager
This commit is contained in:
149
cmd/micro/manager/parser.go
Normal file
149
cmd/micro/manager/parser.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package manager
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
|
||||
"github.com/blang/semver"
|
||||
"github.com/zyedidia/micro/cmd/micro/config"
|
||||
git "gopkg.in/src-d/go-git.v4"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMissingName = errors.New("Missing or empty name field")
|
||||
ErrMissingDesc = errors.New("Missing or empty description field")
|
||||
ErrMissingSite = errors.New("Missing or empty website field")
|
||||
ErrMissingRepo = errors.New("Missing or empty repository field")
|
||||
ErrMissingVersions = errors.New("Missing or empty versions field")
|
||||
ErrMissingTag = errors.New("Missing or empty tag field")
|
||||
ErrMissingRequire = errors.New("Missing or empty require field")
|
||||
)
|
||||
|
||||
type Plugin struct {
|
||||
info *PluginInfo
|
||||
dir string
|
||||
repo *git.Repository
|
||||
// Index into info.Versions showing the current version of this plugin
|
||||
Version int
|
||||
}
|
||||
|
||||
// PluginVersion describes a version for a plugin as well as any dependencies that
|
||||
// version might have
|
||||
// This marks a tag that corresponds to the version in the git repo
|
||||
type PluginVersion struct {
|
||||
Vers semver.Version
|
||||
Vstr string `json:"version"`
|
||||
Tag string `json:"tag"`
|
||||
Require map[string]string `json:"require"`
|
||||
}
|
||||
|
||||
// PluginInfo contains all the needed info about a plugin
|
||||
type PluginInfo struct {
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"description"`
|
||||
Site string `json:"website"`
|
||||
Repo string `json:"repository"`
|
||||
Versions []PluginVersion `json:"versions"`
|
||||
}
|
||||
|
||||
// NewPluginInfo parses a JSON input into a valid PluginInfo struct
|
||||
// Returns an error if there are any missing fields or any invalid fields
|
||||
// There are no optional fields in a plugin info json file
|
||||
func NewPluginInfo(data []byte) (*PluginInfo, error) {
|
||||
var info PluginInfo
|
||||
|
||||
dec := json.NewDecoder(bytes.NewReader(data))
|
||||
dec.DisallowUnknownFields() // Force errors
|
||||
|
||||
if err := dec.Decode(&info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(info.Name) == 0 {
|
||||
return nil, ErrMissingName
|
||||
} else if len(info.Desc) == 0 {
|
||||
return nil, ErrMissingDesc
|
||||
} else if len(info.Site) == 0 {
|
||||
return nil, ErrMissingSite
|
||||
} else if len(info.Repo) == 0 {
|
||||
return nil, ErrMissingRepo
|
||||
} else if err := info.makeVersions(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (i *PluginInfo) makeVersions() error {
|
||||
if len(i.Versions) == 0 {
|
||||
return ErrMissingVersions
|
||||
}
|
||||
|
||||
for _, v := range i.Versions {
|
||||
sv, err := semver.Make(v.Vstr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Vers = sv
|
||||
if len(v.Tag) == 0 {
|
||||
return ErrMissingTag
|
||||
} else if v.Require == nil {
|
||||
return ErrMissingRequire
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstalledPlugins searches the config directory for all installed plugins
|
||||
// and returns the list of plugin infos corresponding to them
|
||||
func ListInstalledPlugins() ([]*Plugin, error) {
|
||||
pdir := path.Join(config.ConfigDir, "plugin")
|
||||
|
||||
files, err := ioutil.ReadDir(pdir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var plugins []*Plugin
|
||||
|
||||
for _, dir := range files {
|
||||
if dir.IsDir() {
|
||||
files, err := ioutil.ReadDir(path.Join(pdir, dir.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
if f.Name() == "repo.json" {
|
||||
dat, err := ioutil.ReadFile(path.Join(pdir, dir.Name(), "repo.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := NewPluginInfo(dat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dirname := path.Join(pdir, dir.Name())
|
||||
r, err := git.PlainOpen(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := &Plugin{
|
||||
info: info,
|
||||
dir: dirname,
|
||||
repo: r,
|
||||
}
|
||||
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
Reference in New Issue
Block a user