Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Marker support to process markers and generate code #2

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions cmd/accessor/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"github.com/procyon-projects/marker"
"log"
)

// printErrors prints error(s) if any error exists after processing markers.
func printErrors(errorList marker.ErrorList) {
if errorList == nil || len(errorList) == 0 {
return
}

for _, err := range errorList {
switch typedErr := err.(type) {
case marker.ParserError:
pos := typedErr.Position
log.Errorf("%s (%d:%d) : %s\n", typedErr.FileName, pos.Line, pos.Column, typedErr.Error())
case marker.ErrorList:
printErrors(typedErr)
}
}
}

// validateMarkers visits all files and returns errors
func validateMarkers(collector *marker.Collector, pkgs []*marker.Package) error {
marker.EachFile(collector, pkgs, func(file *marker.File, fileErrors error) {
if fileErrors != nil {
validationErrors = append(validationErrors, fileErrors)
}
})

return marker.NewErrorList(validationErrors)
}
22 changes: 22 additions & 0 deletions cmd/accessor/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

const (
AppName = "accessor"
AppVersion = "1.0.0"
PkgId = "github.com/procyon-projects/accessor"
)
88 changes: 88 additions & 0 deletions cmd/accessor/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"github.com/procyon-projects/marker"
"github.com/spf13/cobra"
"log"
)

var paths []string
var outputPath string
var options []string

var generateCmd = &cobra.Command{
Use: "generate",
Short: "Generate Go files by processing markers",
Long: `The generate command helps your code generation process by processing markers`,
Run: func(cmd *cobra.Command, args []string) {
packages, err := marker.LoadPackages(paths...)

if err != nil {
log.Errorln(err)
return
}

registry := marker.NewRegistry()
err = RegisterDefinitions(registry)

if err != nil {
log.Errorln(err)
return
}

collector := marker.NewCollector(registry)
err = validateMarkers(collector, packages)

if err != nil {

switch typedErr := err.(type) {
case marker.ErrorList:
printErrors(typedErr)
return
}

log.Errorln(err)
return
}

err = ProcessMarkers(collector, packages)
if err != nil {
log.Errorln(err)
}
},
}

func init() {
rootCmd.AddCommand(generateCmd)

generateCmd.Flags().StringSliceVarP(&paths, "path", "p", paths, "path(s) separated by comma")
err := generateCmd.MarkFlagRequired("path")

if err != nil {
panic(err)
}

generateCmd.Flags().StringVarP(&outputPath, "output", "o", "", "output path")
err = generateCmd.MarkFlagRequired("output")

if err != nil {
panic(err)
}

generateCmd.Flags().StringSliceVarP(&options, "args", "a", options, "extra arguments for marker processors (key-value separated by comma)")
}
23 changes: 23 additions & 0 deletions cmd/accessor/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import "log"

func main() {
log.SetFlags(0)
Execute()
}
59 changes: 59 additions & 0 deletions cmd/accessor/markers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package main

import (
"errors"
"fmt"
"strings"
)

const (
MarkerAccessor = "accessor"
MarkerAccessorMapping = "accessor:mapping"
)

type AccessorMarker struct {
Value string `marker:"Value,useValueSyntax"`
Url string `marker:"Url"`
}

func (a AccessorMarker) Validate() error {
if strings.TrimSpace(a.Value) == "" {
return errors.New("'Value' cannot be empty or nil")
}

if strings.TrimSpace(a.Url) == "" {
return errors.New("'Url' cannot be empty or nil")
}

return nil
}

type AccessorMappingMarker struct {
Value string `marker:"Value,useValueSyntax"`
Method string `marker:"Method"`
}

func (a AccessorMappingMarker) Validate() error {
if strings.TrimSpace(a.Value) == "" {
return errors.New("'Value' cannot be empty or nil")
}

if strings.TrimSpace(a.Method) == "" {
return errors.New("'Url' cannot be empty or nil")
}

matched := false
methods := []string{"GET", "POST", "HEAD", "OPTIONS", "PUT", "PATCH", "DELETE", "TRACE"}

for _, method := range methods {
if strings.TrimSpace(a.Method) == method {
matched = true
}
}

if !matched {
return fmt.Errorf("invalid 'Method' argument value. Here is the list of valid values %s", strings.Join(methods, ", "))
}

return nil
}
77 changes: 77 additions & 0 deletions cmd/accessor/processor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"github.com/procyon-projects/marker"
)

var (
accessorInterfaces []marker.InterfaceType
)

// Register your marker definitions.
func RegisterDefinitions(registry *marker.Registry) error {
markers := []struct {
Name string
Level marker.TargetLevel
Output interface{}
}{
{Name: MarkerAccessor, Level: marker.InterfaceTypeLevel, Output: &AccessorMarker{}},
{Name: MarkerAccessorMapping, Level: marker.InterfaceMethodLevel, Output: &AccessorMappingMarker{}},
}

for _, m := range markers {
err := registry.Register(m.Name, PkgId, m.Level, m.Output)
if err != nil {
return err
}
}

return nil
}

// Process your markers.
func ProcessMarkers(collector *marker.Collector, pkgs []*marker.Package) error {
marker.EachFile(collector, pkgs, func(file *marker.File, err error) {
findAccessorInterfaces(file.InterfaceTypes)
})
return nil
}

func findAccessorInterfaces(interfaceTypes []marker.InterfaceType) {
for _, interfaceType := range interfaceTypes {
markerValues := interfaceType.Markers

if markerValues == nil {
return
}

markers, ok := markerValues[MarkerAccessor]

if !ok {
return
}

for _, candidateMarker := range markers {
switch candidateMarker.(type) {
case AccessorMarker:
accessorInterfaces = append(accessorInterfaces, interfaceType)
}
}

}
}
31 changes: 31 additions & 0 deletions cmd/accessor/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
Copyright © 2021 Accessor Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
"fmt"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: fmt.Sprintf(AppName),
Short: "Marker Processor",
Long: `Marker Processor`,
}

func Execute() {
cobra.CheckErr(rootCmd.Execute())
}
Loading