217 lines
5.3 KiB
Go
217 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const pluginIDGoFileTemplate = `// This file is automatically generated. Do not modify it manually.
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
)
|
|
|
|
var manifest *model.Manifest
|
|
|
|
const manifestStr = ` + "`" + `
|
|
%s
|
|
` + "`" + `
|
|
|
|
func init() {
|
|
_ = json.NewDecoder(strings.NewReader(manifestStr)).Decode(&manifest)
|
|
}
|
|
`
|
|
|
|
const pluginIDJSFileTemplate = `// This file is automatically generated. Do not modify it manually.
|
|
|
|
const manifest = JSON.parse(` + "`" + `
|
|
%s
|
|
` + "`" + `);
|
|
|
|
export default manifest;
|
|
`
|
|
|
|
// These build-time vars are read from shell commands and populated in ../setup.mk
|
|
var (
|
|
BuildHashShort string
|
|
BuildTagLatest string
|
|
BuildTagCurrent string
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) <= 1 {
|
|
panic("no cmd specified")
|
|
}
|
|
|
|
manifest, err := findManifest()
|
|
if err != nil {
|
|
panic("failed to find manifest: " + err.Error())
|
|
}
|
|
|
|
cmd := os.Args[1]
|
|
switch cmd {
|
|
case "id":
|
|
dumpPluginID(manifest)
|
|
|
|
case "version":
|
|
dumpPluginVersion(manifest)
|
|
|
|
case "has_server":
|
|
if manifest.HasServer() {
|
|
fmt.Printf("true")
|
|
}
|
|
|
|
case "has_webapp":
|
|
if manifest.HasWebapp() {
|
|
fmt.Printf("true")
|
|
}
|
|
|
|
case "apply":
|
|
if err := applyManifest(manifest); err != nil {
|
|
panic("failed to apply manifest: " + err.Error())
|
|
}
|
|
|
|
case "dist":
|
|
if err := distManifest(manifest); err != nil {
|
|
panic("failed to write manifest to dist directory: " + err.Error())
|
|
}
|
|
|
|
case "check":
|
|
if err := manifest.IsValid(); err != nil {
|
|
panic("failed to check manifest: " + err.Error())
|
|
}
|
|
|
|
default:
|
|
panic("unrecognized command: " + cmd)
|
|
}
|
|
}
|
|
|
|
func findManifest() (*model.Manifest, error) {
|
|
_, manifestFilePath, err := model.FindManifest(".")
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to find manifest in current working directory")
|
|
}
|
|
manifestFile, err := os.Open(manifestFilePath)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "failed to open %s", manifestFilePath)
|
|
}
|
|
defer manifestFile.Close()
|
|
|
|
// Re-decode the manifest, disallowing unknown fields. When we write the manifest back out,
|
|
// we don't want to accidentally clobber anything we won't preserve.
|
|
var manifest model.Manifest
|
|
decoder := json.NewDecoder(manifestFile)
|
|
decoder.DisallowUnknownFields()
|
|
if err = decoder.Decode(&manifest); err != nil {
|
|
return nil, errors.Wrap(err, "failed to parse manifest")
|
|
}
|
|
|
|
// If no version is listed in the manifest, generate one based on the state of the current
|
|
// commit, and use the first version we find (to prevent causing errors)
|
|
if manifest.Version == "" {
|
|
var version string
|
|
tags := strings.Fields(BuildTagCurrent)
|
|
for _, t := range tags {
|
|
if strings.HasPrefix(t, "v") {
|
|
version = t
|
|
break
|
|
}
|
|
}
|
|
if version == "" {
|
|
if BuildTagLatest != "" {
|
|
version = BuildTagLatest + "+" + BuildHashShort
|
|
} else {
|
|
version = "v0.0.0+" + BuildHashShort
|
|
}
|
|
}
|
|
manifest.Version = strings.TrimPrefix(version, "v")
|
|
}
|
|
|
|
// If no release notes specified, generate one from the latest tag, if present.
|
|
if manifest.ReleaseNotesURL == "" && BuildTagLatest != "" {
|
|
manifest.ReleaseNotesURL = manifest.HomepageURL + "releases/tag/" + BuildTagLatest
|
|
}
|
|
|
|
return &manifest, nil
|
|
}
|
|
|
|
// dumpPluginId writes the plugin id from the given manifest to standard out
|
|
func dumpPluginID(manifest *model.Manifest) {
|
|
fmt.Printf("%s", manifest.Id)
|
|
}
|
|
|
|
// dumpPluginVersion writes the plugin version from the given manifest to standard out
|
|
func dumpPluginVersion(manifest *model.Manifest) {
|
|
fmt.Printf("%s", manifest.Version)
|
|
}
|
|
|
|
// applyManifest propagates the plugin_id into the server and webapp folders, as necessary
|
|
func applyManifest(manifest *model.Manifest) error {
|
|
if manifest.HasServer() {
|
|
// generate JSON representation of Manifest.
|
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
manifestStr := string(manifestBytes)
|
|
|
|
// write generated code to file by using Go file template.
|
|
if err := os.WriteFile(
|
|
"server/manifest.go",
|
|
[]byte(fmt.Sprintf(pluginIDGoFileTemplate, manifestStr)),
|
|
0600,
|
|
); err != nil {
|
|
return errors.Wrap(err, "failed to write server/manifest.go")
|
|
}
|
|
}
|
|
|
|
if manifest.HasWebapp() {
|
|
// generate JSON representation of Manifest.
|
|
// JSON is very similar and compatible with JS's object literals. so, what we do here
|
|
// is actually JS code generation.
|
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
manifestStr := string(manifestBytes)
|
|
|
|
// Escape newlines
|
|
manifestStr = strings.ReplaceAll(manifestStr, `\n`, `\\n`)
|
|
|
|
// write generated code to file by using JS file template.
|
|
if err := os.WriteFile(
|
|
"webapp/src/manifest.ts",
|
|
[]byte(fmt.Sprintf(pluginIDJSFileTemplate, manifestStr)),
|
|
0600,
|
|
); err != nil {
|
|
return errors.Wrap(err, "failed to open webapp/src/manifest.ts")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// distManifest writes the manifest file to the dist directory
|
|
func distManifest(manifest *model.Manifest) error {
|
|
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.WriteFile(fmt.Sprintf("dist/%s/plugin.json", manifest.Id), manifestBytes, 0600); err != nil {
|
|
return errors.Wrap(err, "failed to write plugin.json")
|
|
}
|
|
|
|
return nil
|
|
}
|