-
Notifications
You must be signed in to change notification settings - Fork 9
/
node.go
148 lines (121 loc) · 4.16 KB
/
node.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2022 Namespace Labs Inc; All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
package parsing
import (
"context"
"path/filepath"
"namespacelabs.dev/foundation/internal/codegen/protos"
"namespacelabs.dev/foundation/internal/fnerrors"
"namespacelabs.dev/foundation/schema"
"namespacelabs.dev/foundation/std/pkggraph"
)
func TransformNode(ctx context.Context, pl pkggraph.PackageLoader, loc pkggraph.Location, node *schema.Node, kind schema.Node_Kind) error {
if kind == schema.Node_EXTENSION {
if node.Ingress != schema.Endpoint_INGRESS_UNSPECIFIED {
return fnerrors.New("ingress can only be specified for services")
}
if len(node.ExportService) > 0 {
return fnerrors.New("extensions can't export services")
}
}
var additionalInstances []*schema.Instantiate
var deps schema.PackageList
instances := node.Instantiate
for _, p := range node.Provides {
instances = append(instances, p.Instantiate...)
}
for _, dep := range instances {
// Checking language compatibility
// No package happen for internal nodes, e.g. "std/grpc"
if len(dep.PackageName) > 0 {
pkg, err := pl.LoadByName(ctx, schema.PackageName(dep.PackageName))
if err != nil {
return err
}
ext := pkg.Extension
if ext == nil {
return fnerrors.NewWithLocation(loc, "Trying to instantiate a node that is not an extension: %s", dep.PackageName)
}
providesFmwks := ext.ProvidedInFrameworks()
for _, fmwk := range node.CodegeneratedFrameworks() {
if _, ok := providesFmwks[fmwk]; !ok {
return fnerrors.NewWithLocation(
loc,
"Node has generated code for framework %s but tries to instantiate an "+
"extension provider '%s:%s' that doesn't support this framework",
fmwk.String(),
dep.PackageName,
dep.Name,
)
}
}
}
// Adding a proto dependency.
if ref := protos.Ref(dep.Constructor); ref != nil && !ref.Builtin {
deps.Add(ref.Package)
}
// XXX this special casing should be found a new home.
// Note(@nicolasalt): this only affects Go. In Node.js the "Conn" type is not provided,
// so this statement has no effect.
if dep.PackageName == "namespacelabs.dev/foundation/std/grpc" && dep.Type == "Backend" {
additionalInstances = append(additionalInstances, &schema.Instantiate{
PackageName: dep.PackageName,
Type: "Conn",
Name: dep.Name + "Conn",
Constructor: dep.Constructor,
})
}
}
node.Instantiate = append(node.Instantiate, additionalInstances...)
if kind == schema.Node_SERVICE {
node.IngressServiceName = filepath.Base(loc.PackageName.String())
}
for _, imp := range node.Import {
deps.Add(schema.PackageName(imp))
}
for _, hook := range ExtendNodeHook {
r, err := hook(ctx, pl, loc, node)
if err != nil {
return fnerrors.InternalError("%s: hook failed: %w", loc.PackageName, err)
}
if r != nil {
// These are dependencies that depend on the properties of the node, and as such as still considered user-provided imports.
deps.AddMultiple(r.Import...)
for _, pkg := range r.LoadPackages {
if err := pl.Ensure(ctx, pkg); err != nil {
return err
}
}
}
}
node.UserImports = deps.PackageNamesAsString()
err := validateDependencies(ctx, pl, loc, deps.PackageNames(), &deps)
if err != nil {
return err
}
node.Import = deps.PackageNamesAsString()
return nil
}
func validateDependencies(ctx context.Context, pl pkggraph.PackageLoader, loc pkggraph.Location, includes []schema.PackageName, dl *schema.PackageList) error {
for _, include := range includes {
if _, err := loadDep(ctx, pl, include); err != nil {
return fnerrors.NewWithLocation(loc, "loading dependency failed: %s: %w", include, err)
}
dl.Add(include)
}
return nil
}
func loadDep(ctx context.Context, pl pkggraph.PackageLoader, pkg schema.PackageName) (*pkggraph.Package, error) {
p, err := pl.LoadByName(ctx, pkg)
if err != nil {
return nil, err
}
if p.Server != nil {
return nil, fnerrors.New("dependencies can't include servers")
}
if len(p.Binaries) > 0 {
return nil, fnerrors.New("dependencies can't be binaries")
}
return p, nil
}