@@ -2,10 +2,12 @@ package serve
22
33import (
44 "archive/zip"
5+ "bufio"
56 "bytes"
67 "context"
78 "crypto/sha256"
89 "encoding/json"
10+ "errors"
911 "fmt"
1012 "io"
1113 "os"
@@ -111,7 +113,7 @@ func (s *PluginServe) build(pluginDirectory, goos, goarch, distPath, pluginVersi
111113 if err != nil {
112114 return nil , err
113115 }
114- ldFlags := fmt .Sprintf ("-s -w -X %s/plugin.Version=%s" , importPath , pluginVersion )
116+ ldFlags := fmt .Sprintf ("-s -w -X %[1] s/plugin.Version=%[2]s -X %[1]s/resources/plugin.Version=%[2] s" , importPath , pluginVersion )
115117 if s .plugin .IsStaticLinkingEnabled () && strings .EqualFold (goos , plugin .GoOSLinux ) {
116118 ldFlags += " -linkmode external -extldflags=-static"
117119 }
@@ -262,6 +264,70 @@ func (*PluginServe) copyDocs(distPath, docsPath string) error {
262264 return nil
263265}
264266
267+ func (* PluginServe ) versionRegex () * regexp.Regexp {
268+ return regexp .MustCompile (`^(var)?\s?Version\s*=` )
269+ }
270+
271+ func (s * PluginServe ) validatePluginExports (pluginPath string ) error {
272+ st , err := os .Stat (pluginPath )
273+ if err != nil {
274+ return err
275+ }
276+ if ! st .IsDir () {
277+ return errors .New ("plugin path must be a directory" )
278+ }
279+
280+ checkRelativeDirs := []string {"resources" + string (filepath .Separator ) + "plugin" , "plugin" }
281+ foundDirs := []string {}
282+ for _ , dir := range checkRelativeDirs {
283+ p := filepath .Join (pluginPath , dir )
284+ s , err := os .Stat (p )
285+ if err == nil && s .IsDir () {
286+ foundDirs = append (foundDirs , dir )
287+ }
288+ }
289+ if len (foundDirs ) == 0 {
290+ return fmt .Errorf ("plugin directory must contain at least one of the following directories: %s" , strings .Join (checkRelativeDirs , ", " ))
291+ }
292+
293+ findVersion := s .versionRegex ()
294+
295+ foundVersion := false
296+ for _ , dir := range foundDirs {
297+ p := filepath .Join (pluginPath , dir )
298+ if err := filepath .WalkDir (p , func (path string , d os.DirEntry , err error ) error {
299+ if err != nil {
300+ return err
301+ }
302+ if d .IsDir () || foundVersion {
303+ return nil
304+ }
305+ if ! strings .HasSuffix (strings .ToLower (d .Name ()), ".go" ) {
306+ return nil
307+ }
308+
309+ f , err := os .Open (path )
310+ if err != nil {
311+ return err
312+ }
313+ defer f .Close ()
314+ if ok , err := containsRegex (f , findVersion ); err != nil {
315+ return err
316+ } else if ok {
317+ foundVersion = true
318+ }
319+ return nil
320+ }); err != nil {
321+ return err
322+ }
323+ }
324+ if ! foundVersion {
325+ return fmt .Errorf ("could not find `Version` global variable in package" )
326+ }
327+
328+ return nil
329+ }
330+
265331func copyFile (src , dst string ) error {
266332 srcFile , err := os .Open (src )
267333 if err != nil {
@@ -280,6 +346,16 @@ func copyFile(src, dst string) error {
280346 return nil
281347}
282348
349+ func containsRegex (r io.Reader , needle * regexp.Regexp ) (bool , error ) {
350+ scanner := bufio .NewScanner (r )
351+ for scanner .Scan () {
352+ if needle .MatchString (scanner .Text ()) {
353+ return true , nil
354+ }
355+ }
356+ return false , scanner .Err ()
357+ }
358+
283359func (s * PluginServe ) newCmdPluginPackage () * cobra.Command {
284360 cmd := & cobra.Command {
285361 Use : "package -m <message> <version> <plugin_directory>" ,
@@ -320,11 +396,16 @@ func (s *PluginServe) newCmdPluginPackage() *cobra.Command {
320396 return fmt .Errorf ("plugin name is required for packaging" )
321397 }
322398 if s .plugin .Team () == "" {
323- return fmt .Errorf ("plugin team is required (hint: use the plugin.WithTeam() option" )
399+ return fmt .Errorf ("plugin team is required (hint: use the plugin.WithTeam() option) " )
324400 }
325401 if s .plugin .Kind () == "" {
326- return fmt .Errorf ("plugin kind is required (hint: use the plugin.WithKind() option" )
402+ return fmt .Errorf ("plugin kind is required (hint: use the plugin.WithKind() option) " )
327403 }
404+
405+ if err := s .validatePluginExports (pluginDirectory ); err != nil {
406+ return err
407+ }
408+
328409 if s .plugin .Kind () == plugin .KindSource {
329410 if err := s .plugin .Init (cmd .Context (), nil , plugin.NewClientOptions {
330411 NoConnection : true ,
0 commit comments