Exemple #1
0
func updatePlugins() {
	l := log.New("")
	l.SetFlags(0)
	l.SetDebug(os.Getenv("ABOT_DEBUG") == "true")

	if err := core.LoadConf(); err != nil {
		l.Fatal(err)
	}
	plugins := buildPluginFile(l)

	l.Info("Updating plugins...")
	for path, version := range plugins.Dependencies {
		if version != "*" {
			continue
		}
		l.Infof("Updating %s...\n", path)
		outC, err := exec.
			Command("/bin/sh", "-c", "go get -u "+path).
			CombinedOutput()
		if err != nil {
			l.Info(string(outC))
			l.Fatal(err)
		}
	}
	embedPluginConfs(plugins, l)
	updateGlockfileAndInstall(l)
	l.Info("Success!")
}
Exemple #2
0
func TestPluginGenerate(t *testing.T) {
	defer func() {
		if err := os.RemoveAll("__test"); err != nil {
			log.Info("failed to clean up __test dir.", err)
		}
		if err := os.RemoveAll("test_here"); err != nil {
			log.Info("failed to clean up __test dir.", err)
		}
	}()

	// generate plugin
	l := log.New("")
	l.SetFlags(0)
	if err := generatePlugin(l, "__test"); err != nil {
		t.Fatal(err)
	}
	if err := generatePlugin(l, "TestHere"); err != nil {
		t.Fatal(err)
	}
}
Exemple #3
0
func publishPlugin(c *cli.Context) error {
	p := filepath.Join(os.Getenv("HOME"), ".abot.conf")
	fi, err := os.Open(p)
	if err != nil {
		if err.Error() == fmt.Sprintf("open %s: no such file or directory", p) {
			login()
			publishPlugin(c)
			return nil
		}
		log.Fatal(err)
	}
	defer func() {
		if err = fi.Close(); err != nil {
			log.Fatal(err)
		}
	}()

	// Prepare request
	if len(c.Args().First()) == 0 {
		log.Fatal("missing plugin's `go get` path")
	}
	reqData := struct {
		Path   string
		Secret string
	}{
		Path:   c.Args().First(),
		Secret: core.RandSeq(24),
	}
	byt, err := json.Marshal(reqData)
	if err != nil {
		log.Fatal(err)
	}
	u := os.Getenv("ITSABOT_URL") + "/api/plugins.json"
	req, err := http.NewRequest("POST", u, bytes.NewBuffer(byt))
	if err != nil {
		log.Fatal(err)
	}

	// Populate req with login credentials from ~/.abot.conf
	scn := bufio.NewScanner(fi)
	var lineNum int
	for scn.Scan() {
		line := scn.Text()
		cookie := &http.Cookie{}
		switch lineNum {
		case 0:
			cookie.Name = "iaID"
		case 1:
			cookie.Name = "iaEmail"
		case 2:
			req.Header.Set("Authorization", "Bearer "+line)
		case 3:
			cookie.Name = "iaIssuedAt"
		default:
			log.Fatal("unknown line in abot.conf")
		}
		if lineNum != 2 {
			cookie.Value = url.QueryEscape(line)
			req.AddCookie(cookie)
		}
		lineNum++
	}
	if err = scn.Err(); err != nil {
		log.Fatal(err)
	}
	cookie := &http.Cookie{}
	cookie.Name = "iaScopes"
	req.AddCookie(cookie)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		if err = resp.Body.Close(); err != nil {
			log.Fatal(err)
		}
	}()
	if resp.StatusCode == 401 {
		login()
		publishPlugin(c)
	} else if resp.StatusCode != 202 {
		log.Info("something went wrong. status code", resp.StatusCode)
		var msg string
		if err = json.NewDecoder(resp.Body).Decode(&msg); err != nil {
			log.Fatal(err)
		}
		log.Fatal(msg)
	}

	// Make a websocket request to get updates about the publishing process
	uri, err := url.Parse(os.Getenv("ITSABOT_URL"))
	if err != nil {
		log.Fatal(err)
	}
	ws, err := websocket.Dial("ws://"+uri.Host+"/api/ws", "",
		os.Getenv("ABOT_URL"))
	if err != nil {
		log.Fatal(err)
	}
	if err = websocket.Message.Send(ws, reqData.Secret); err != nil {
		log.Fatal(err)
	}
	var msg socket.Msg
	l := log.New("")
	l.SetFlags(0)
	l.Info("> Establishing connection with server...")
	var established bool
	var lastMsg string
	for {
		websocket.JSON.Receive(ws, &msg)
		if !established {
			l.Info("OK")
			established = true
		}
		if msg.Content == lastMsg {
			log.Info("server hung up. please try again")
			if err = ws.Close(); err != nil {
				log.Info("failed to close socket.", err)
			}
			return nil
		}
		lastMsg = msg.Content
		if msg.Type == socket.MsgTypeFinishedSuccess ||
			msg.Type == socket.MsgTypeFinishedFailed {
			if err = ws.Close(); err != nil {
				log.Info("failed to close socket.", err)
			}
			return nil
		}
		if len(msg.Content) < 2 {
			l.Info(msg.Content)
			continue
		}
		tmp := msg.Content[0:2]
		if tmp == "> " || tmp == "==" {
			l.Info("")
		}
		l.Info(msg.Content)
	}
}
Exemple #4
0
func main() {
	rand.Seed(time.Now().UnixNano())
	log.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
	if err := core.LoadEnvVars(); err != nil {
		log.Fatal(err)
	}
	app := cli.NewApp()
	app.Commands = []cli.Command{
		{
			Name:  "new",
			Usage: "generate a new abot",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				if len(c.Args()) != 1 {
					l.Fatal("usage: abot new {name}")
				}
				if strings.Contains(c.Args().First(), " ") {
					l.Fatal("name cannot include a space. use camelCase")
				}
				err := newAbot(l, c.Args().First(), c.Args().Get(1))
				if err != nil {
					l.Fatalf("could not build new abot. %s", err)
				}
				l.Info("Success. Created " + c.Args().First())
				return nil
			},
		},
		{
			Name:    "server",
			Aliases: []string{"s"},
			Usage:   "run server",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				cmd := exec.Command("/bin/sh", "-c", "go build")
				out, err := cmd.CombinedOutput()
				if err != nil {
					l.Info(string(out))
					return err
				}
				dir, err := os.Getwd()
				if err != nil {
					return err
				}
				_, file := filepath.Split(dir)
				cmd = exec.Command("/bin/sh", "-c", "./"+file)
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				if err = cmd.Start(); err != nil {
					return err
				}
				return cmd.Wait()
			},
		},
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "download and install plugins listed in plugins.json",
			Action: func(c *cli.Context) error {
				errChan := make(chan errMsg)
				l := log.New("")
				l.SetFlags(0)
				l.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
				go func() {
					select {
					case errC := <-errChan:
						if errC.err == nil {
							// Success
							l.Info(errC.msg)
							os.Exit(0)
						}

						// Plugins install failed, so remove incomplete plugins.go file
						errR := os.Remove("plugins.go")
						if errR != nil && !os.IsNotExist(errR) {
							l.Info("could not remove plugins.go file.", errR)
						}
						if len(errC.msg) > 0 {
							l.Fatalf("could not install plugins.\n%s\n%s", errC.msg, errC.err)
						}
						l.Fatalf("could not install plugins.\n%s", errC.err)
					}
				}()
				installPlugins(l, errChan)
				for {
					// Keep process running until a message is received
				}
			},
		},
		{
			Name:  "search",
			Usage: "search plugins indexed on itsabot.org",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				args := c.Args()
				if len(args) == 0 || len(args) > 2 {
					l.Fatal(errors.New(`usage: abot plugin search {term}`))
				}
				if err := searchPlugins(args.First()); err != nil {
					l.Fatalf("could not start console\n%s", err)
				}
				return nil
			},
		},
		{
			Name:    "update",
			Aliases: []string{"u", "upgrade"},
			Usage:   "update and install plugins listed in plugins.json",
			Action: func(c *cli.Context) error {
				updatePlugins()
				return nil
			},
		},
		{
			Name:    "publish",
			Aliases: []string{"p"},
			Usage:   "publish a plugin to itsabot.org",
			Action: func(c *cli.Context) error {
				publishPlugin(c)
				return nil
			},
		},
		{
			Name:    "test",
			Aliases: []string{"t"},
			Usage:   "tests plugins",
			Action: func(c *cli.Context) error {
				lg.SetFlags(0)
				count, err := testPlugin()
				if err != nil {
					return err
				}
				if count == 0 {
					lg.Println("No tests found. Did you run \"abot install\"?")
					return nil
				}
				lg.Printf("Success (%d tests).\n", count)
				return nil
			},
		},
		{
			Name:    "generate",
			Aliases: []string{"g"},
			Usage:   "generate plugin scaffolding",
			Action: func(c *cli.Context) error {
				l := log.New("")
				l.SetFlags(0)
				args := c.Args()
				if len(args) != 1 {
					l.Fatal(errors.New(`usage: abot generate {name}`))
				}
				generatePlugin(l, args.First())
				l.Info("Created", args.First(), "in",
					filepath.Join(os.Getenv("PWD"), args.First()))
				return nil
			},
		},
		{
			Name:    "login",
			Aliases: []string{"l"},
			Usage:   "log into itsabot.org to enable publishing plugins",
			Action: func(c *cli.Context) error {
				login()
				return nil
			},
		},
		{
			Name:    "console",
			Aliases: []string{"c"},
			Usage:   "communicate with a running abot server",
			Action: func(c *cli.Context) error {
				if err := startConsole(c); err != nil {
					l := log.New("")
					l.SetFlags(0)
					l.Fatalf("could not start console\n%s", err)
				}
				return nil
			},
		},
		{
			Name:    "dbconsole",
			Aliases: []string{"dbc"},
			Usage:   "communicate with a running abot server",
			Action: func(c *cli.Context) error {
				cmd := exec.Command("/bin/sh", "-c", "psql "+os.Getenv("ABOT_DATABASE_URL"))
				cmd.Stdout = os.Stdout
				cmd.Stdin = os.Stdin
				if err := cmd.Start(); err != nil {
					return err
				}
				return cmd.Wait()
			},
		},
	}
	app.Action = func(c *cli.Context) error {
		cli.ShowAppHelp(c)
		return nil
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}
Exemple #5
0
// New builds a Plugin with its trigger, RPC, and configuration settings from
// its plugin.json.
func New(url string) (*dt.Plugin, error) {
	if err := core.LoadEnvVars(); err != nil {
		log.Fatal(err)
	}
	db, err := core.ConnectDB("")
	if err != nil {
		return nil, err
	}

	// Read plugin.json data from within plugins.go, unmarshal into struct
	c := dt.PluginConfig{}
	if len(os.Getenv("ABOT_PATH")) > 0 {
		p := filepath.Join(os.Getenv("ABOT_PATH"), "plugins.go")
		var scn *bufio.Scanner
		fi, err := os.OpenFile(p, os.O_RDONLY, 0666)
		if os.IsNotExist(err) {
			goto makePlugin
		}
		if err != nil {
			return nil, err
		}
		defer func() {
			if err = fi.Close(); err != nil {
				log.Info("failed to close file", fi.Name())
				return
			}
		}()
		var found bool
		var data string
		scn = bufio.NewScanner(fi)
		for scn.Scan() {
			t := scn.Text()
			if !found && t != url {
				continue
			} else if t == url {
				found = true
				continue
			} else if len(t) >= 1 && t[0] == '}' {
				data += t
				break
			}
			data += t
		}
		if err = scn.Err(); err != nil {
			return nil, err
		}
		if len(data) > 0 {
			if err = json.Unmarshal([]byte(data), &c); err != nil {
				return nil, err
			}
			if len(c.Name) == 0 {
				return nil, ErrMissingPluginName
			}
		}
	}
makePlugin:
	l := log.New(c.Name)
	l.SetDebug(os.Getenv("ABOT_DEBUG") == "true")
	plg := &dt.Plugin{
		Trigger:     &dt.StructuredInput{},
		SetBranches: func(in *dt.Msg) [][]dt.State { return nil },
		Events: &dt.PluginEvents{
			PostReceive:    func(cmd *string) {},
			PreProcessing:  func(cmd *string, u *dt.User) {},
			PostProcessing: func(in *dt.Msg) {},
			PreResponse:    func(in *dt.Msg, resp *string) {},
		},
		Config: c,
		DB:     db,
		Log:    l,
	}
	plg.SM = dt.NewStateMachine(plg)
	return plg, nil
}