From 995f7496a96438c2e6bb3de5696f39f9abe4db54 Mon Sep 17 00:00:00 2001
From: Jessica Yuen <im.jessicayuen@gmail.com>
Date: Mon, 30 Oct 2017 10:34:18 -0700
Subject: [PATCH] Parse system prototypes using the jsonnet snippet parser

We are currently parsing system prototypes using the default TextMate
snippet which does not take into account the translation of params of
format `import 'param://foo`. The jsonnet snippet parser does take this
into account.
---
 cmd/prototype.go                          | 11 +++--
 prototype/snippet/jsonnet/snippet.go      |  2 +-
 prototype/snippet/jsonnet/snippet_test.go | 58 ++++++++++++++++++++++-
 3 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/cmd/prototype.go b/cmd/prototype.go
index 233e26de..43e2d3be 100644
--- a/cmd/prototype.go
+++ b/cmd/prototype.go
@@ -24,7 +24,7 @@ import (
 
 	"github.com/ksonnet/ksonnet/metadata"
 	"github.com/ksonnet/ksonnet/prototype"
-	"github.com/ksonnet/ksonnet/prototype/snippet"
+	"github.com/ksonnet/ksonnet/prototype/snippet/jsonnet"
 	"github.com/spf13/cobra"
 )
 
@@ -229,7 +229,7 @@ var prototypePreviewCmd = &cobra.Command{
 			return fmt.Errorf("Incorrect number of arguments supplied to 'prototype preview'\n\n%s", cmd.UsageString())
 		}
 
-		text, err := expandPrototype(proto, flags, templateType)
+		text, err := expandPrototype(proto, flags, templateType, "preview")
 		if err != nil {
 			return err
 		}
@@ -320,7 +320,7 @@ var prototypeUseCmd = &cobra.Command{
 			return fmt.Errorf("'prototype use' has too many arguments (takes a prototype name and a component name)\n\n%s", cmd.UsageString())
 		}
 
-		text, err := expandPrototype(proto, flags, templateType)
+		text, err := expandPrototype(proto, flags, templateType, componentName)
 		if err != nil {
 			return err
 		}
@@ -381,7 +381,7 @@ func bindPrototypeFlags(cmd *cobra.Command, proto *prototype.SpecificationSchema
 	}
 }
 
-func expandPrototype(proto *prototype.SpecificationSchema, flags *pflag.FlagSet, templateType prototype.TemplateType) (string, error) {
+func expandPrototype(proto *prototype.SpecificationSchema, flags *pflag.FlagSet, templateType prototype.TemplateType, componentName string) (string, error) {
 	missingReqd := prototype.ParamSchemas{}
 	values := map[string]string{}
 	for _, param := range proto.RequiredParams() {
@@ -424,8 +424,9 @@ func expandPrototype(proto *prototype.SpecificationSchema, flags *pflag.FlagSet,
 	if err != nil {
 		return "", err
 	}
+	template = append([]string{`local params = std.extVar("__ksonnet/params").components.` + componentName + ";"}, template...)
 
-	tm := snippet.Parse(strings.Join(template, "\n"))
+	tm, err := jsonnet.Parse(componentName, strings.Join(template, "\n"))
 	text, err := tm.Evaluate(values)
 	if err != nil {
 		return "", err
diff --git a/prototype/snippet/jsonnet/snippet.go b/prototype/snippet/jsonnet/snippet.go
index ad00f736..b44d4056 100644
--- a/prototype/snippet/jsonnet/snippet.go
+++ b/prototype/snippet/jsonnet/snippet.go
@@ -13,7 +13,7 @@
 //    See the License for the specific language governing permissions and
 //    limitations under the License.
 
-package prototype
+package jsonnet
 
 import (
 	"errors"
diff --git a/prototype/snippet/jsonnet/snippet_test.go b/prototype/snippet/jsonnet/snippet_test.go
index 4fd213d4..d2f60bbc 100644
--- a/prototype/snippet/jsonnet/snippet_test.go
+++ b/prototype/snippet/jsonnet/snippet_test.go
@@ -13,7 +13,7 @@
 //    See the License for the specific language governing permissions and
 //    limitations under the License.
 
-package prototype
+package jsonnet
 
 import (
 	"testing"
@@ -54,6 +54,62 @@ func TestParse(t *testing.T) {
 			local name = params.name;
 			k.core.v1.service.new('%s-service' % [name], {app: name}, port)`,
 		},
+		// Test another complex case.
+		{
+			`
+			local params = std.extVar("__ksonnet/params").components.guestbook;
+			local k = import "k.libsonnet";
+			local deployment = k.apps.v1beta1.deployment;
+			local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;
+			local containerPort = container.portsType;
+			local service = k.core.v1.service;
+			local servicePort = k.core.v1.service.mixin.spec.portsType;
+			
+			local targetPort = import 'param://containerPort';
+			local labels = {app: import 'param://name'};
+			
+			local appService = service.new(
+			  import 'param://name',
+			  labels,
+			  servicePort.new(import 'param://servicePort', targetPort)) +
+			service.mixin.spec.type(import 'param://type');
+			
+			local appDeployment = deployment.new(
+			  import 'param://name',
+			  import 'param://replicas',
+			  container.new(import 'param://name', import 'param://replicas') +
+				container.ports(containerPort.new(targetPort)),
+			  labels);
+			
+			k.core.v1.list.new([appService, appDeployment])`,
+
+			`
+			local params = std.extVar("__ksonnet/params").components.guestbook;
+			local k = import "k.libsonnet";
+			local deployment = k.apps.v1beta1.deployment;
+			local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;
+			local containerPort = container.portsType;
+			local service = k.core.v1.service;
+			local servicePort = k.core.v1.service.mixin.spec.portsType;
+			
+			local targetPort = params.containerPort;
+			local labels = {app: params.name};
+			
+			local appService = service.new(
+			  params.name,
+			  labels,
+			  servicePort.new(params.servicePort, targetPort)) +
+			service.mixin.spec.type(params.type);
+			
+			local appDeployment = deployment.new(
+			  params.name,
+			  params.replicas,
+			  container.new(params.name, params.replicas) +
+				container.ports(containerPort.new(targetPort)),
+			  labels);
+			
+			k.core.v1.list.new([appService, appDeployment])`,
+		},
 		// Test where an import param is split over multiple lines.
 		{
 			`
-- 
GitLab