Skip to content

Commit a0ab402

Browse files
Add beginnings of plugin install command
1 parent 293e010 commit a0ab402

File tree

9 files changed

+277
-3
lines changed

9 files changed

+277
-3
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mc
2+
server.yml
23
*.exe
34
*.*~
45
*.swp

command.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import (
99
)
1010

1111
type Command struct {
12-
Run func(cmd *Command, args []string)
13-
Flag flag.FlagSet
12+
Run func(cmd *Command, args []string)
13+
Flag flag.FlagSet
14+
NeedsServer bool
1415

1516
Usage string // first word must be command name
1617
Category string

config.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
7+
"github.com/the-obsidian/mc/plugin"
8+
9+
"gopkg.in/yaml.v2"
10+
)
11+
12+
type Config struct {
13+
Plugins []*plugin.Plugin
14+
15+
unknownKeys []string
16+
}
17+
18+
func NewConfigFromString(data string) (*Config, error) {
19+
c := Config{}
20+
21+
err := yaml.Unmarshal([]byte(data), &c)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
for _, plugin := range c.Plugins {
27+
err = plugin.Init()
28+
if err != nil {
29+
return nil, err
30+
}
31+
}
32+
33+
return &c, nil
34+
}
35+
36+
func NewConfigFromFile(path string) (*Config, error) {
37+
data, err := ioutil.ReadFile(path)
38+
if err != nil {
39+
return nil, err
40+
}
41+
42+
return NewConfigFromString(string(data))
43+
}
44+
45+
func (c *Config) InstallPlugins() error {
46+
err := os.MkdirAll("plugins", 0755)
47+
if err != nil {
48+
return err
49+
}
50+
51+
for _, plugin := range c.Plugins {
52+
err = plugin.Install()
53+
if err != nil {
54+
return err
55+
}
56+
}
57+
58+
return nil
59+
}

install.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package main
2+
3+
import "os"
4+
5+
var cmdInstall = &Command{
6+
NeedsServer: true,
7+
Usage: "install",
8+
Category: "app",
9+
Short: "install dependencies",
10+
Long: `
11+
Install installs any required dependencies.
12+
13+
Examples:
14+
15+
$ mc install
16+
`,
17+
}
18+
19+
func init() {
20+
cmdInstall.Run = runInstall
21+
}
22+
23+
func runInstall(cmd *Command, args []string) {
24+
if len(args) != 0 {
25+
printUsageTo(os.Stderr)
26+
os.Exit(2)
27+
}
28+
29+
config, err := NewConfigFromFile("server.yml")
30+
if err != nil {
31+
printFatal("Error reading config file: %v", err)
32+
}
33+
34+
err = config.InstallPlugins()
35+
if err != nil {
36+
printFatal("failed to install plugins: %v", err)
37+
}
38+
}

main.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
var commands = []*Command{
16-
//cmdInstall,
16+
cmdInstall,
1717
//cmdVersion,
1818
cmdHelp,
1919

@@ -56,6 +56,13 @@ func main() {
5656
cmd.Flag.Usage = func() {
5757
cmd.PrintUsage()
5858
}
59+
60+
if cmd.NeedsServer {
61+
if exists, err := fileExists("server.yml"); err != nil || !exists {
62+
printFatal("server.yml not found - is this a server directory?")
63+
}
64+
}
65+
5966
if err := cmd.Flag.Parse(args[1:]); err == flag.ErrHelp {
6067
cmdHelp.Run(cmdHelp, args[:1])
6168
} else if err != nil {

plugin/plugin.go

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package plugin
2+
3+
import (
4+
"crypto/sha1"
5+
"fmt"
6+
"os"
7+
"path"
8+
9+
"github.com/hashicorp/go-getter"
10+
"github.com/the-obsidian/mc/util"
11+
)
12+
13+
type Plugin struct {
14+
Name string
15+
URI string
16+
Sha string
17+
Processors []Processor `yaml:"-"`
18+
19+
originalProcessors []map[string]interface{} `yaml:"processors"`
20+
}
21+
22+
func (p *Plugin) Init() error {
23+
for _, pr := range p.originalProcessors {
24+
processor, err := NewProcessorFromConfig(p, pr)
25+
if err != nil {
26+
return err
27+
}
28+
p.Processors = append(p.Processors, processor)
29+
}
30+
31+
return nil
32+
}
33+
34+
func (p *Plugin) Install() error {
35+
dest := path.Join(".", "plugins", p.Name+".jar")
36+
tmpDir := path.Join(".", ".tmp", "plugins", p.Name)
37+
tmpDownload := path.Join(tmpDir, "download")
38+
hash := sha1.New()
39+
40+
checksumValue, err := decodeChecksum(p.Sha)
41+
if err != nil {
42+
return err
43+
}
44+
45+
if exists, err := util.FileExists(dest); err != nil {
46+
return err
47+
} else if exists {
48+
err = checksum(dest, hash, checksumValue)
49+
if err == nil {
50+
return nil
51+
}
52+
}
53+
54+
err = os.MkdirAll(tmpDir, 0755)
55+
if err != nil {
56+
return err
57+
}
58+
59+
err = getter.GetFile(tmpDownload, p.URI)
60+
if err != nil {
61+
return err
62+
}
63+
64+
err = checksum(tmpDownload, hash, checksumValue)
65+
if err != nil {
66+
return fmt.Errorf("failed to checksum download: %v", err)
67+
}
68+
69+
err = os.Rename(tmpDownload, dest)
70+
if err != nil {
71+
return err
72+
}
73+
74+
return nil
75+
}
76+
77+
type Processor interface {
78+
Process()
79+
}
80+
81+
func NewProcessorFromConfig(p *Plugin, config map[string]interface{}) (Processor, error) {
82+
switch config["type"] {
83+
case "unzip":
84+
pr := &UnzipProcessor{
85+
Type: "unzip",
86+
Files: config["files"].([]string),
87+
}
88+
return pr, nil
89+
default:
90+
return nil, fmt.Errorf("invalid processor type: %v", config["type"])
91+
}
92+
93+
return nil, nil
94+
}
95+
96+
type UnzipProcessor struct {
97+
Type string
98+
Files []string
99+
}
100+
101+
func (pr *UnzipProcessor) Process() {}

plugin/util.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package plugin
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"fmt"
7+
"hash"
8+
"io"
9+
"os"
10+
)
11+
12+
func decodeChecksum(data string) ([]byte, error) {
13+
b, err := hex.DecodeString(data)
14+
if err != nil {
15+
return nil, fmt.Errorf("invalid checksum: %s", err)
16+
}
17+
return b, nil
18+
}
19+
20+
func checksum(source string, h hash.Hash, v []byte) error {
21+
f, err := os.Open(source)
22+
if err != nil {
23+
return fmt.Errorf("Failed to open file for checksum: %s", err)
24+
}
25+
defer f.Close()
26+
27+
if _, err := io.Copy(h, f); err != nil {
28+
return fmt.Errorf("Failed to hash: %s", err)
29+
}
30+
31+
if actual := h.Sum(nil); !bytes.Equal(actual, v) {
32+
return fmt.Errorf(
33+
"Checksums did not match.\nExpected: %s\nGot: %s",
34+
hex.EncodeToString(v),
35+
hex.EncodeToString(actual),
36+
)
37+
}
38+
39+
return nil
40+
}

util.go

+13
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,23 @@ package main
33
import (
44
"fmt"
55
"log"
6+
"os"
67

78
"github.com/mgutz/ansi"
89
)
910

11+
// exists returns whether the given file or directory exists or not
12+
func fileExists(path string) (bool, error) {
13+
_, err := os.Stat(path)
14+
if err == nil {
15+
return true, nil
16+
}
17+
if os.IsNotExist(err) {
18+
return false, nil
19+
}
20+
return false, err
21+
}
22+
1023
func printError(message string, args ...interface{}) {
1124
log.Println(colorizeMessage("red", "error:", message, args...))
1225
}

util/util.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package util
2+
3+
import "os"
4+
5+
func FileExists(path string) (bool, error) {
6+
_, err := os.Stat(path)
7+
if err == nil {
8+
return true, nil
9+
}
10+
if os.IsNotExist(err) {
11+
return false, nil
12+
}
13+
return false, err
14+
}

0 commit comments

Comments
 (0)