Skip to content

Commit

Permalink
Merge pull request #1015 from brandonbodnar-wk/STREAMS-1981-use-vendo…
Browse files Browse the repository at this point in the history
…r-support-for-java

STREAMS-1981: Java: Support use_vendor
  • Loading branch information
kevinfrommelt-wf authored Jul 17, 2018
2 parents f198cff + d6b53ce commit de285a6
Show file tree
Hide file tree
Showing 49 changed files with 7,906 additions and 43 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,14 +241,15 @@ intention to use the vendored code as advertised by the `vendor` annotation.
If no location is specified by the `vendor` annotation, the behavior is defined
by the language generator.

The `vendor` annotation is currently only supported by Go and Dart.
The `vendor` annotation is currently only supported by Go, Dart and Java.

The example below illustrates how this works.

bar.frugal ("providing" IDL):
```thrift
namespace go bar (vendor="github.com/Workiva/my-repo/gen-go/bar")
namespace dart bar (vendor="my-repo/gen-go")
namespace java bar (vendor="com.workiva.bar.custom.pkg")
struct Struct {}
```
Expand Down
7 changes: 6 additions & 1 deletion compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,12 @@ func generateFrugalRec(f *parser.Frugal, g generator.ProgramGenerator, generate

// Iterate through includes in order to ensure determinism in
// generated code.
for _, inclFrugal := range f.OrderedIncludes() {
for _, include := range f.OrderedIncludes() {
// Skip recursive generation if include is marked vendor and use_vendor option is enabled
if _, vendored := include.Annotations.Vendor(); vendored && g.UseVendor() {
continue
}
inclFrugal := f.ParsedIncludes[include.Name]
if err := generateFrugalRec(inclFrugal, g, globals.Recurse, lang); err != nil {
return err
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/generator/dartlang/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func (g *Generator) addToPubspec(dir string) error {
name = namespace.Value
}

if g.useVendor() && includesSet[include] {
if g.UseVendor() && includesSet[include] {
vendorPath, _ := namespace.Annotations.Vendor()
deps[toLibraryName(vendorPath)] = dep{
Hosted: hostedDep{Name: toLibraryName(vendorPath), URL: "https://pub.workiva.org"},
Expand Down Expand Up @@ -1867,7 +1867,7 @@ func (g *Generator) generateIncludeImport(include *parser.Include) (string, erro
name := include.Name

_, vendored := include.Annotations.Vendor()
vendored = vendored && g.useVendor()
vendored = vendored && g.UseVendor()
vendorPath := ""

if namespace := g.Frugal.NamespaceForInclude(name, lang); namespace != nil {
Expand Down Expand Up @@ -1911,7 +1911,7 @@ func (g *Generator) useEnums() bool {
return useEnums
}

func (g *Generator) useVendor() bool {
func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
Expand Down
11 changes: 11 additions & 0 deletions compiler/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ var Languages = LanguageOptions{
"suppress: suppress @Generated annotations entirely",
"async": "Generate async client code using futures",
"boxed_primitives": "Generate primitives as the boxed equivalents",
"use_vendor": "Use specified import references for vendored includes and do not generate code for them",
},
"dart": Options{
"library_prefix": "Generate code that can be used within an existing library. " +
Expand Down Expand Up @@ -100,6 +101,9 @@ type ProgramGenerator interface {

// DefaultOutputDir returns the default directory for generated code.
DefaultOutputDir() string

// UseVendor returns whether this generator supports using vendored includes
UseVendor() bool
}

// LanguageGenerator generates source code as implemented for specific
Expand Down Expand Up @@ -136,6 +140,9 @@ type LanguageGenerator interface {
GenerateScopeImports(*os.File, *parser.Scope) error
GeneratePublisher(*os.File, *parser.Scope) error
GenerateSubscriber(*os.File, *parser.Scope) error

// UseVendor returns whether this generator instance supports using vendored includes
UseVendor() bool
}

// GetPackageComponents returns the package string split on dots.
Expand Down Expand Up @@ -337,3 +344,7 @@ func (o *programGenerator) GetOutputDir(dir string, f *parser.Frugal) string {
func (o *programGenerator) DefaultOutputDir() string {
return o.LanguageGenerator.DefaultOutputDir()
}

func (o *programGenerator) UseVendor() bool {
return o.LanguageGenerator.UseVendor()
}
4 changes: 2 additions & 2 deletions compiler/generator/golang/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1176,7 +1176,7 @@ func (g *Generator) generateIncludeImport(include *parser.Include, pkgPrefix str
namespace := g.Frugal.NamespaceForInclude(includeName, lang)

_, vendored := include.Annotations.Vendor()
vendored = vendored && g.useVendor()
vendored = vendored && g.UseVendor()
vendorPath := ""

if namespace != nil {
Expand Down Expand Up @@ -2258,7 +2258,7 @@ func (g *Generator) generateAsync() bool {
return ok
}

func (g *Generator) useVendor() bool {
func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/generator/html/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ func (g *Generator) DefaultOutputDir() string {
return defaultOutputDir
}

func (g *Generator) UseVendor() bool {
return false
}

func (g *Generator) generateStylesheet(file *os.File) error {
_, err := file.WriteString(css)
return err
Expand Down
55 changes: 40 additions & 15 deletions compiler/generator/java/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
defaultOutputDir = "gen-java"
tab = "\t"
generatedAnnotations = "generated_annotations"
useVendorOption = "use_vendor"
tabtab = tab + tab
tabtabtab = tab + tab + tab
tabtabtabtab = tab + tab + tab + tab
Expand Down Expand Up @@ -292,6 +293,23 @@ func (g *Generator) quote(s string) string {
return strconv.Quote(s)
}

func (g *Generator) namespaceForInclude(includeName string) string {
if includeName == "" {
return ""
}

namespace := g.Frugal.NamespaceForInclude(includeName, lang)
if namespace == nil {
return ""
}

if vendorPath, _ := namespace.Annotations.Vendor(); vendorPath != "" && g.UseVendor() && g.isVendoredInclude(includeName) {
return vendorPath
}

return namespace.Value
}

func (g *Generator) generateConstantValueRec(t *parser.Type, value interface{}, indent string) (string, string) {
underlyingType := g.Frugal.UnderlyingType(t)

Expand All @@ -307,14 +325,14 @@ func (g *Generator) generateConstantValueRec(t *parser.Type, value interface{},
return "", fmt.Sprintf("%s.%s", idCtx.Enum.Name, idCtx.EnumValue.Name)
case parser.IncludeConstant:
include := idCtx.Include.Name
if namespace := g.Frugal.NamespaceForInclude(include, lang); namespace != nil {
include = namespace.Value
if namespace := g.namespaceForInclude(include); namespace != "" {
include = namespace
}
return "", fmt.Sprintf("%s.%sConstants.%s", include, idCtx.Include.Name, idCtx.Constant.Name)
case parser.IncludeEnum:
include := idCtx.Include.Name
if namespace := g.Frugal.NamespaceForInclude(include, lang); namespace != nil {
include = namespace.Value
if namespace := g.namespaceForInclude(include); namespace != "" {
include = namespace
}
return "", fmt.Sprintf("%s.%s.%s", include, idCtx.Enum.Name, idCtx.EnumValue.Name)
default:
Expand Down Expand Up @@ -2731,13 +2749,8 @@ func (g *Generator) generateServiceInterface(service *parser.Service, indent str
func (g *Generator) getServiceExtendsName(service *parser.Service) string {
serviceName := "F" + service.ExtendsService()
include := service.ExtendsInclude()
if include != "" {
if namespace := g.Frugal.NamespaceForInclude(include, lang); namespace != nil {
include = namespace.Value
} else {
return serviceName
}
serviceName = include + "." + serviceName
if namespace := g.namespaceForInclude(include); namespace != "" {
serviceName = namespace + "." + serviceName
}
return serviceName
}
Expand Down Expand Up @@ -3272,13 +3285,20 @@ func containerType(typeName string) string {
}
}

func (g *Generator) isVendoredInclude(includeName string) bool {
include := g.Frugal.Include(includeName)
if include == nil {
return false
}
_, vendored := include.Annotations.Vendor()
return vendored
}

func (g *Generator) qualifiedTypeName(t *parser.Type) string {
param := t.ParamName()
include := t.IncludeName()
if include != "" {
if namespace := g.Frugal.NamespaceForInclude(include, lang); namespace != nil {
return fmt.Sprintf("%s.%s", namespace.Value, param)
}
if namespace := g.namespaceForInclude(include); namespace != "" {
return fmt.Sprintf("%s.%s", namespace, param)
}
return param
}
Expand Down Expand Up @@ -3328,3 +3348,8 @@ func (g *Generator) generateAsync() bool {
_, ok := g.Options["async"]
return ok
}

func (g *Generator) UseVendor() bool {
_, ok := g.Options[useVendorOption]
return ok
}
4 changes: 4 additions & 0 deletions compiler/generator/python/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -1564,3 +1564,7 @@ func getAsyncOpt(options map[string]string) concurrencyModel {
}
return synchronous
}

func (g *Generator) UseVendor() bool {
return false
}
31 changes: 20 additions & 11 deletions compiler/parser/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ type Include struct {
Annotations Annotations
}

type byIncludeName []Include

func (s byIncludeName) Len() int {
return len(s)
}

func (s byIncludeName) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}

func (s byIncludeName) Less(i, j int) bool {
return s[i].Name < s[j].Name
}

// Namespace represents an IDL namespace.
type Namespace struct {
Scope string
Expand Down Expand Up @@ -689,19 +703,14 @@ func (f *Frugal) ContainsFrugalDefinitions() bool {
return len(f.Scopes)+len(f.Services) > 0
}

// OrderedIncludes returns the ParsedIncludes in order, sorted by the include
// OrderedIncludes returns the Includes in order, sorted by the include
// name.
func (f *Frugal) OrderedIncludes() []*Frugal {
keys := make([]string, 0, len(f.ParsedIncludes))
for key := range f.ParsedIncludes {
keys = append(keys, key)
}
sort.Strings(keys)

includes := make([]*Frugal, 0, len(f.ParsedIncludes))
for _, key := range keys {
includes = append(includes, f.ParsedIncludes[key])
func (f *Frugal) OrderedIncludes() []Include {
includes := make([]Include, 0, len(f.Includes))
for _, include := range f.Includes {
includes = append(includes, *include)
}
sort.Sort(byIncludeName(includes))
return includes
}

Expand Down
12 changes: 12 additions & 0 deletions test/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,15 @@ func copyFilePair(pair FileComparisonPair) error {
_, err = io.Copy(expectedFile, generatedFile)
return err
}

func assertFilesNotExist(t *testing.T, filePaths []string) {
for _, fileThatShouldNotExist := range filePaths {
if _, err := os.Stat(fileThatShouldNotExist); !os.IsNotExist(err) {
if err != nil {
t.Errorf("Unexpected error checking for existence on %q: %s", fileThatShouldNotExist, err)
} else {
t.Errorf("Expected %q not to exist, but it did", fileThatShouldNotExist)
}
}
}
}
7 changes: 7 additions & 0 deletions test/dart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func TestValidDartVendor(t *testing.T) {
"expected/dart/include_vendor/f_my_service_service.dart",
filepath.Join(outputDir, "include_vendor", "lib", "src", "f_my_service_service.dart"),
},
{
"expected/dart/include_vendor/f_vendored_references.dart",
filepath.Join(outputDir, "include_vendor", "lib", "src", "f_vendored_references.dart"),
},
{
"expected/dart/include_vendor/include_vendor.dart",
filepath.Join(outputDir, "include_vendor", "lib", "include_vendor.dart"),
Expand Down Expand Up @@ -147,6 +151,9 @@ func TestValidDartVendorNamespaceTargetGenerate(t *testing.T) {
files := []FileComparisonPair{
{"expected/dart/vendor_namespace/vendor_namespace.dart", filepath.Join(outputDir, "vendor_namespace", "lib", "vendor_namespace.dart")},
{"expected/dart/vendor_namespace/f_item.dart", filepath.Join(outputDir, "vendor_namespace", "lib", "src", "f_item.dart")},
{"expected/dart/vendor_namespace/f_vendored_base_service.dart", filepath.Join(outputDir, "vendor_namespace", "lib", "src", "f_vendored_base_service.dart")},
{"expected/dart/vendor_namespace/f_vendor_namespace_constants.dart", filepath.Join(outputDir, "vendor_namespace", "lib", "src", "f_vendor_namespace_constants.dart")},
{"expected/dart/vendor_namespace/f_my_enum.dart", filepath.Join(outputDir, "vendor_namespace", "lib", "src", "f_my_enum.dart")},
}
copyAllFiles(t, files)
compareAllFiles(t, files)
Expand Down
7 changes: 4 additions & 3 deletions test/expected/dart/include_vendor/f_my_service_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ import 'package:excepts/excepts.dart' as t_excepts;
import 'package:include_vendor/include_vendor.dart' as t_include_vendor;


abstract class FMyService {
abstract class FMyService extends t_vendor_namespace.FVendoredBase {

Future<t_vendor_namespace.Item> getItem(frugal.FContext ctx);
}

class FMyServiceClient implements FMyService {
class FMyServiceClient extends t_vendor_namespace.FVendoredBaseClient implements FMyService {
static final logging.Logger _frugalLog = new logging.Logger('MyService');
Map<String, frugal.FMethod> _methods;

FMyServiceClient(frugal.FServiceProvider provider, [List<frugal.Middleware> middleware]) {
FMyServiceClient(frugal.FServiceProvider provider, [List<frugal.Middleware> middleware])
: super(provider, middleware) {
_transport = provider.transport;
_protocolFactory = provider.protocolFactory;
var combined = middleware ?? [];
Expand Down
Loading

0 comments on commit de285a6

Please sign in to comment.