-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jordan Singer
committed
Feb 10, 2023
1 parent
c499ef0
commit 3113a41
Showing
13 changed files
with
524 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package golang | ||
|
||
import ( | ||
"fmt" | ||
|
||
sitter "github.com/smacker/go-tree-sitter" | ||
) | ||
|
||
type Argument struct { | ||
Content string | ||
Type string | ||
} | ||
|
||
// GetArguements is passed a tree-sitter node, which is of type argument_list, and returns a list of in order Arguments | ||
func GetArguements(args *sitter.Node) []Argument { | ||
|
||
arguments := []Argument{} | ||
nextMatch := doQuery(args, findArgs) | ||
for { | ||
match, found := nextMatch() | ||
if !found { | ||
break | ||
} | ||
|
||
arg := match["arg"] | ||
if arg == nil { | ||
continue | ||
} | ||
|
||
arguments = append(arguments, Argument{Content: arg.Content(), Type: arg.Type()}) | ||
} | ||
return arguments | ||
} | ||
|
||
func ArgumentListToString(args []Argument) string { | ||
result := "(" | ||
for index, arg := range args { | ||
if index < len(args)-1 { | ||
result += fmt.Sprintf("%s, ", arg.Content) | ||
} else { | ||
result += arg.Content + ")" | ||
} | ||
} | ||
return result | ||
} | ||
|
||
func (a *Argument) IsString() bool { | ||
return a.Type == "interpreted_string_literal" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package golang | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/klothoplatform/klotho/pkg/annotation" | ||
"github.com/klothoplatform/klotho/pkg/core" | ||
"github.com/klothoplatform/klotho/pkg/logging" | ||
"github.com/klothoplatform/klotho/pkg/multierr" | ||
"github.com/klothoplatform/klotho/pkg/query" | ||
sitter "github.com/smacker/go-tree-sitter" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type PersistFsPlugin struct { | ||
runtime Runtime | ||
} | ||
|
||
func (p PersistFsPlugin) Name() string { return "Persist" } | ||
|
||
func (p PersistFsPlugin) Transform(result *core.CompilationResult, deps *core.Dependencies) error { | ||
|
||
var errs multierr.Error | ||
for _, res := range result.Resources() { | ||
unit, ok := res.(*core.ExecutionUnit) | ||
if !ok { | ||
continue | ||
} | ||
for _, f := range unit.Files() { | ||
goSource, ok := Language.ID.CastFile(f) | ||
if !ok { | ||
continue | ||
} | ||
|
||
resources, err := p.handleFile(goSource, unit) | ||
if err != nil { | ||
errs.Append(core.WrapErrf(err, "failed to handle persist in unit %s", unit.Name)) | ||
continue | ||
} | ||
|
||
for _, r := range resources { | ||
result.Add(r) | ||
|
||
deps.Add(core.ResourceKey{ | ||
Name: unit.Name, | ||
Kind: core.ExecutionUnitKind, | ||
}, r.Key()) | ||
} | ||
} | ||
} | ||
|
||
return errs.ErrOrNil() | ||
} | ||
|
||
func (p *PersistFsPlugin) handleFile(f *core.SourceFile, unit *core.ExecutionUnit) ([]core.CloudResource, error) { | ||
resources := []core.CloudResource{} | ||
var errs multierr.Error | ||
annots := f.Annotations() | ||
for _, annot := range annots { | ||
cap := annot.Capability | ||
if cap.Name != annotation.PersistCapability { | ||
continue | ||
} | ||
fsResult := queryFS(f, annot) | ||
if fsResult != nil { | ||
persistResource, err := p.transformFS(f, annot, fsResult, unit) | ||
if err != nil { | ||
errs.Append(err) | ||
} | ||
resources = append(resources, persistResource) | ||
|
||
} | ||
} | ||
return resources, errs.ErrOrNil() | ||
} | ||
|
||
func (p *PersistFsPlugin) transformFS(f *core.SourceFile, cap *core.Annotation, result *persistResult, unit *core.ExecutionUnit) (core.CloudResource, error) { | ||
|
||
fsEnvVar := core.EnvironmentVariable{ | ||
Name: cap.Capability.ID + "_fs_bucket", | ||
Kind: string(core.PersistFileKind), | ||
ResourceID: cap.Capability.ID, | ||
Value: "bucket_url", | ||
} | ||
|
||
unit.EnvironmentVariables = append(unit.EnvironmentVariables, fsEnvVar) | ||
|
||
args := GetArguements(result.args) | ||
|
||
// We need to check to make sure the path supplied to the original node content is a static string. This is because it will get erased and we dont want to leave os level orphaned code | ||
if !args[0].IsString() { | ||
return nil, errors.New("must supply static string for secret path") | ||
} | ||
|
||
args[0].Content = "nil" | ||
args[1].Content = fmt.Sprintf(`os.Getenv("%s")`, fsEnvVar.Name) | ||
|
||
newNodeContent := strings.Replace(result.args.Content(), result.args.Content(), ArgumentListToString(args), 1) | ||
|
||
f.ReplaceNodeContent(result.args, newNodeContent) | ||
f.ReplaceNodeContent(result.operator, "blob") | ||
|
||
err := UpdateImportsInFile(f, p.runtime.GetFsImports(), []Import{{Package: "gocloud.dev/blob/fileblob"}}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
persist := &core.Persist{ | ||
Kind: core.PersistFileKind, | ||
Name: cap.Capability.ID, | ||
} | ||
return persist, nil | ||
} | ||
|
||
type persistResult struct { | ||
varName string | ||
operator *sitter.Node | ||
args *sitter.Node | ||
} | ||
|
||
func queryFS(file *core.SourceFile, annotation *core.Annotation) *persistResult { | ||
log := zap.L().With(logging.FileField(file), logging.AnnotationField(annotation)) | ||
|
||
fileBlobImport := GetNamedImportInFile(file, "gocloud.dev/blob/fileblob") | ||
|
||
nextMatch := doQuery(annotation.Node, fileBucket) | ||
|
||
match, found := nextMatch() | ||
if !found { | ||
return nil | ||
} | ||
|
||
varName, args, id := match["varName"], match["args"], match["id"] | ||
|
||
if id != nil { | ||
if fileBlobImport.Alias != "" { | ||
if !query.NodeContentEquals(id, fileBlobImport.Alias) { | ||
return nil | ||
} | ||
} else { | ||
if !query.NodeContentEquals(id, "fileblob") { | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
if _, found := nextMatch(); found { | ||
log.Warn("too many assignments for fs_storage") | ||
return nil | ||
} | ||
|
||
return &persistResult{ | ||
varName: varName.Content(), | ||
operator: id, | ||
args: args, | ||
} | ||
} |
Oops, something went wrong.