Compare commits

..

8 commits

Author SHA1 Message Date
Vova Ivanov 4bc8ee0316 Updated filebase64sha256 function 2021-11-23 17:10:04 -08:00
Vova Ivanov 809cf11d79 Added rangecheck to avoid potential out of bounds error 2021-11-23 16:51:21 -08:00
Vova Ivanov aa8aff0572 Implemented fileArchive support for Go 2021-11-23 16:51:21 -08:00
Vova Ivanov 6d48d3355e Cleaned up import array 2021-11-23 16:51:21 -08:00
Vova Ivanov 1c1e7e9d7d Added filebase64sha256 support for DotNet 2021-11-23 16:51:19 -08:00
Vova Ivanov 584f109588 Added filebase64sha256 support for Python 2021-11-23 16:50:31 -08:00
Vova Ivanov fba8aa6575 Added filebase64sha256 support for NodeJS 2021-11-23 16:49:19 -08:00
Vova Ivanov cae67f1f83 Added filebase64sha256 support for Go 2021-11-23 16:47:18 -08:00
244 changed files with 291 additions and 10029 deletions

View file

@ -8,5 +8,3 @@
### Bug Fixes
- [codegen/go] - Respect default values in Pulumi object types.
[#8411](https://github.com/pulumi/pulumi/pull/8400)

View file

@ -22,7 +22,7 @@ To hack on Pulumi, you'll need to get a development environment set up. You'll w
You can easily get all required dependencies with brew and npm
```bash
brew install node pipenv python@3 typescript yarn go@1.17 golangci/tap/golangci-lint pulumi/tap/pulumictl coreutils
brew install node pipenv python@3 typescript yarn go@1.17 golangci/tap/golangci-lint pulumi/tap/pulumictl
curl https://raw.githubusercontent.com/Homebrew/homebrew-cask/0272f0d33f/Casks/dotnet-sdk.rb > dotnet-sdk.rb # v3.1.0
brew install --HEAD -s dotnet-sdk.rb
rm dotnet-sdk.rb
@ -53,10 +53,9 @@ ulimit -n 5000
Across our projects, we try to use a regular set of make targets. The ones you'll care most about are:
1. `make ensure`, which restores/installs any build dependencies
1. `make dist`, which just builds and installs the Pulumi CLI
0. `make ensure`, which restores/installs any build dependencies
1. `make`, which builds Pulumi and runs a quick set of tests
1. `make all` which builds Pulumi and runs the quick tests and a larger set of tests.
2. `make all` which builds Pulumi and runs the quick tests and a larger set of tests.
We make heavy use of integration level testing where we invoke `pulumi` to create and then delete cloud resources. This requires you to have a Pulumi account (so [sign up for free](https://pulumi.com) today if you haven't already) and login with `pulumi login`.

View file

@ -238,12 +238,13 @@ func (g *generator) genRange(w io.Writer, call *model.FunctionCallExpression, en
}
var functionNamespaces = map[string][]string{
"readDir": {"System.IO", "System.Linq"},
"readFile": {"System.IO"},
"filebase64": {"System", "System.IO"},
"toJSON": {"System.Text.Json", "System.Collections.Generic"},
"toBase64": {"System"},
"sha1": {"System.Security.Cryptography", "System.Text"},
"readDir": {"System.IO", "System.Linq"},
"readFile": {"System.IO"},
"filebase64": {"System", "System.IO"},
"filebase64sha256": {"System", "System.IO", "System.Security.Cryptography", "System.Text"},
"toJSON": {"System.Text.Json", "System.Collections.Generic"},
"toBase64": {"System"},
"sha1": {"System.Security.Cryptography", "System.Text"},
}
func (g *generator) genFunctionUsings(x *model.FunctionCallExpression) []string {
@ -313,6 +314,9 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
case "filebase64":
// Assuming the existence of the following helper method located earlier in the preamble
g.Fgenf(w, "ReadFileBase64(%v)", expr.Args[0])
case "filebase64sha256":
// Assuming the existence of the following helper method located earlier in the preamble
g.Fgenf(w, "ComputeFileBase64Sha256(%v)", expr.Args[0])
case pcl.Invoke:
_, name := g.functionName(expr.Args[0])

View file

@ -126,7 +126,13 @@ func getHelperMethodIfNeeded(functionName string) (string, bool) {
switch functionName {
case "filebase64":
return `private static string ReadFileBase64(string path) {
return Convert.ToBase64String(System.Text.UTF8.GetBytes(File.ReadAllText(path)))
return Convert.ToBase64String(Encoding.UTF8.GetBytes(File.ReadAllText(path)))
}`, true
case "filebase64sha256":
return `private static string ComputeFileBase64Sha256(string path) {
var fileData = Encoding.UTF8.GetBytes(File.ReadAllText(path));
var hashData = SHA256.Create().ComputeHash(fileData);
return Convert.ToBase64String(hashData);
}`, true
case "sha1":
return `private static string ComputeSHA1(string input) {

View file

@ -114,9 +114,6 @@ type pkgContext struct {
// Determines if we should emit type registration code
disableInputTypeRegistrations bool
// Determines if we should emit object defaults code
disableObjectDefaults bool
}
func (pkg *pkgContext) detailsForType(t schema.Type) *typeDetails {
@ -272,7 +269,6 @@ func rawResourceName(r *schema.Resource) string {
return tokenToName(r.Token)
}
// If `nil` is a valid value of type `t`.
func isNilType(t schema.Type) bool {
switch t := t.(type) {
case *schema.OptionalType, *schema.ArrayType, *schema.MapType, *schema.ResourceType, *schema.InputType:
@ -299,6 +295,23 @@ func isNilType(t schema.Type) bool {
return false
}
// The default value for a Pulumi primitive type.
func primitiveNilValue(t schema.Type) string {
contract.Assert(schema.IsPrimitiveType(t))
switch t {
case schema.BoolType:
return "false"
case schema.IntType:
return "0"
case schema.NumberType:
return "0.0"
case schema.StringType:
return "\"\""
default:
return "nil"
}
}
func (pkg *pkgContext) inputType(t schema.Type) (result string) {
switch t := codegen.SimplifyInputUnion(t).(type) {
case *schema.OptionalType:
@ -500,12 +513,7 @@ func (pkg *pkgContext) typeStringImpl(t schema.Type, argsType bool) string {
}
func (pkg *pkgContext) typeString(t schema.Type) string {
s := pkg.typeStringImpl(t, false)
if s == "pulumi." {
return "pulumi.Any"
}
return s
return pkg.typeStringImpl(t, false)
}
func (pkg *pkgContext) isExternalReference(t schema.Type) bool {
@ -625,9 +633,6 @@ func (pkg *pkgContext) outputType(t schema.Type) string {
}
// TODO(pdg): union types
return "pulumi.AnyOutput"
case *schema.InputType:
// We can't make output types for input types. We instead strip the input and try again.
return pkg.outputType(t.ElementType)
default:
switch t {
case schema.BoolType:
@ -1091,27 +1096,6 @@ func (pkg *pkgContext) genEnumInputFuncs(w io.Writer, typeName string, enum *sch
fmt.Fprintln(w)
}
func (pkg *pkgContext) assignProperty(w io.Writer, p *schema.Property, object, value string, indirectAssign bool) {
t := strings.TrimSuffix(pkg.typeString(p.Type), "Input")
switch codegen.UnwrapType(p.Type).(type) {
case *schema.EnumType:
t = ""
}
if codegen.IsNOptionalInput(p.Type) {
if t != "" {
value = fmt.Sprintf("%s(%s)", t, value)
}
fmt.Fprintf(w, "\targs.%s = %s\n", Title(p.Name), value)
} else if indirectAssign {
tmpName := camel(p.Name) + "_"
fmt.Fprintf(w, "%s := %s\n", tmpName, value)
fmt.Fprintf(w, "%s.%s = &%s\n", object, Title(p.Name), tmpName)
} else {
fmt.Fprintf(w, "%s.%s = %s\n", object, Title(p.Name), value)
}
}
func (pkg *pkgContext) genPlainType(w io.Writer, name, comment, deprecationMessage string,
properties []*schema.Property) {
@ -1124,66 +1108,6 @@ func (pkg *pkgContext) genPlainType(w io.Writer, name, comment, deprecationMessa
fmt.Fprintf(w, "}\n\n")
}
func (pkg *pkgContext) genPlainObjectDefaultFunc(w io.Writer, name string,
properties []*schema.Property) error {
defaults := []*schema.Property{}
for _, p := range properties {
if p.DefaultValue != nil || codegen.IsProvideDefaultsFuncRequired(p.Type) {
defaults = append(defaults, p)
}
}
// There are no defaults, so we don't need to generate a defaults function.
if len(defaults) == 0 {
return nil
}
printComment(w, fmt.Sprintf("%s sets the appropriate defaults for %s", ProvideDefaultsMethodName, name), false)
fmt.Fprintf(w, "func (val *%[1]s) %[2]s() *%[1]s {\n", name, ProvideDefaultsMethodName)
fmt.Fprint(w, "if val == nil {\n return nil\n}\n")
fmt.Fprint(w, "tmp := *val\n")
for _, p := range defaults {
if p.DefaultValue != nil {
dv, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
if err != nil {
return err
}
pkg.needsUtils = true
fmt.Fprintf(w, "if isZero(tmp.%s) {\n", Title(p.Name))
pkg.assignProperty(w, p, "tmp", dv, !p.IsRequired())
fmt.Fprintf(w, "}\n")
} else if funcName := pkg.provideDefaultsFuncName(p.Type); funcName != "" {
var member string
if codegen.IsNOptionalInput(p.Type) {
f := fmt.Sprintf("func(v %[1]s) %[1]s { return v.%[2]s*() }", name, funcName)
member = fmt.Sprintf("tmp.%[1]s.ApplyT(%[2]s)\n", Title(p.Name), f)
} else {
member = fmt.Sprintf("tmp.%[1]s.%[2]s()\n", Title(p.Name), funcName)
}
sigil := ""
if p.IsRequired() {
sigil = "*"
}
pkg.assignProperty(w, p, "tmp", sigil+member, false)
} else {
panic(fmt.Sprintf("Property %s[%s] should not be in the default list", p.Name, p.Type.String()))
}
}
fmt.Fprintf(w, "return &tmp\n}\n")
return nil
}
// The name of the method used to instantiate defaults.
const ProvideDefaultsMethodName = "Defaults"
func (pkg *pkgContext) provideDefaultsFuncName(typ schema.Type) string {
if !codegen.IsProvideDefaultsFuncRequired(typ) {
return ""
}
return ProvideDefaultsMethodName
}
func (pkg *pkgContext) genInputTypes(w io.Writer, t *schema.ObjectType, details *typeDetails) {
contract.Assert(t.IsInputShape())
@ -1374,11 +1298,6 @@ func (pkg *pkgContext) getDefaultValue(dv *schema.DefaultValue, t schema.Type) (
return "", err
}
val = v
switch t.(type) {
case *schema.EnumType:
typeName := strings.TrimSuffix(pkg.typeString(codegen.UnwrapType(t)), "Input")
val = fmt.Sprintf("%s(%s)", typeName, val)
}
}
if len(dv.Environment) > 0 {
@ -1462,8 +1381,6 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
fmt.Fprintf(w, "\t}\n\n")
// Produce the inputs.
// Check all required inputs are present
for _, p := range r.InputProperties {
if p.IsRequired() && isNilType(p.Type) && p.DefaultValue == nil {
fmt.Fprintf(w, "\tif args.%s == nil {\n", Title(p.Name))
@ -1472,8 +1389,26 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
}
}
assign := func(p *schema.Property, value string) {
pkg.assignProperty(w, p, "args", value, isNilType(p.Type))
assign := func(p *schema.Property, value string, indentation int) {
ind := strings.Repeat("\t", indentation)
t := strings.TrimSuffix(pkg.typeString(p.Type), "Input")
switch codegen.UnwrapType(p.Type).(type) {
case *schema.EnumType:
t = strings.TrimSuffix(t, "Ptr")
}
if t == "pulumi." {
t = "pulumi.Any"
}
if codegen.IsNOptionalInput(p.Type) {
fmt.Fprintf(w, "\targs.%s = %s(%s)\n", Title(p.Name), t, value)
} else if isNilType(p.Type) {
tmpName := camel(p.Name) + "_"
fmt.Fprintf(w, "%s%s := %s\n", ind, tmpName, value)
fmt.Fprintf(w, "%sargs.%s = &%s\n", ind, Title(p.Name), tmpName)
} else {
fmt.Fprintf(w, "%sargs.%s = %s\n", ind, Title(p.Name), value)
}
}
for _, p := range r.InputProperties {
@ -1482,51 +1417,19 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
if err != nil {
return err
}
assign(p, v)
assign(p, v, 1)
} else if p.DefaultValue != nil {
dv, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
v, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
if err != nil {
return err
}
pkg.needsUtils = true
fmt.Fprintf(w, "\tif isZero(args.%s) {\n", Title(p.Name))
assign(p, dv)
defaultComp := "nil"
if !codegen.IsNOptionalInput(p.Type) && !isNilType(p.Type) {
defaultComp = primitiveNilValue(p.Type)
}
fmt.Fprintf(w, "\tif args.%s == %s {\n", Title(p.Name), defaultComp)
assign(p, v, 2)
fmt.Fprintf(w, "\t}\n")
} else if name := pkg.provideDefaultsFuncName(p.Type); name != "" && !pkg.disableObjectDefaults {
var value string
var needsNilCheck bool
if codegen.IsNOptionalInput(p.Type) {
innerFuncType := strings.TrimSuffix(pkg.typeString(codegen.UnwrapType(p.Type)), "Args")
applyName := fmt.Sprintf("%sApplier", camel(p.Name))
fmt.Fprintf(w, "%[3]s := func(v %[1]s) *%[1]s { return v.%[2]s() }\n", innerFuncType, name, applyName)
outputValue := pkg.convertToOutput(fmt.Sprintf("args.%s", Title(p.Name)), p.Type)
outputType := pkg.typeString(p.Type)
if strings.HasSuffix(outputType, "Input") {
outputType = strings.TrimSuffix(outputType, "Input") + "Output"
}
// Because applies return pointers, we need to convert to PtrOutput and then call .Elem().
var tail string
if !strings.HasSuffix(outputType, "PtrOutput") {
outputType = strings.TrimSuffix(outputType, "Output") + "PtrOutput"
tail = ".Elem()"
}
needsNilCheck = !p.IsRequired()
value = fmt.Sprintf("%s.ApplyT(%s).(%s)%s", outputValue, applyName, outputType, tail)
} else {
value = fmt.Sprintf("args.%[1]s.%[2]s()", Title(p.Name), name)
}
v := func() {
fmt.Fprintf(w, "args.%[1]s = %s\n", Title(p.Name), value)
}
if needsNilCheck {
fmt.Fprintf(w, "if args.%s != nil {\n", Title(p.Name))
v()
fmt.Fprint(w, "}\n")
} else {
v()
}
}
}
@ -1820,30 +1723,6 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
return nil
}
// Takes an expression and type, and returns a string that converts that expression to an Output type.
//
// Examples:
// ("bar", Foo of ObjectType) => "bar.ToFooOutput()"
// ("id", FooOutput) => "id"
// ("ptr", FooInput of ObjectType) => "ptr.ToFooPtrOutput().Elem()"
func (pkg *pkgContext) convertToOutput(expr string, typ schema.Type) string {
elemConversion := ""
switch typ.(type) {
case *schema.OptionalType:
elemConversion = ".Elem()"
}
outputType := pkg.outputType(typ)
// Remove any element before the last .
outputType = outputType[strings.LastIndex(outputType, ".")+1:]
if strings.HasSuffix(outputType, "ArgsOutput") {
outputType = strings.TrimSuffix(outputType, "ArgsOutput") + "Output"
}
if elemConversion != "" {
outputType = strings.TrimSuffix(outputType, "Output") + "PtrOutput"
}
return fmt.Sprintf("%s.To%s()%s", expr, outputType, elemConversion)
}
func NeedsGoOutputVersion(f *schema.Function) bool {
fPkg := f.Package
@ -1861,7 +1740,7 @@ func NeedsGoOutputVersion(f *schema.Function) bool {
return f.NeedsOutputVersion()
}
func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) (string, error) {
func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) string {
importsAndAliases := map[string]string{}
pkg.getImports(f, importsAndAliases)
buffer := &bytes.Buffer{}
@ -1872,14 +1751,12 @@ func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) (string, error) {
}
pkg.genHeader(buffer, imports, importsAndAliases)
if err := pkg.genFunction(buffer, f); err != nil {
return "", err
}
pkg.genFunction(buffer, f)
pkg.genFunctionOutputVersion(buffer, f)
return buffer.String(), nil
return buffer.String()
}
func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error {
func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) {
name := pkg.functionName(f)
printCommentWithDeprecationMessage(w, f.Comment, f.DeprecationMessage, false)
@ -1900,8 +1777,6 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error {
var inputsVar string
if f.Inputs == nil {
inputsVar = "nil"
} else if codegen.IsProvideDefaultsFuncRequired(f.Inputs) && !pkg.disableObjectDefaults {
inputsVar = "args.Defaults()"
} else {
inputsVar = "args"
}
@ -1925,38 +1800,19 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error {
fmt.Fprintf(w, "\t}\n")
// Return the result.
var retValue string
if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults {
retValue = "rv.Defaults()"
} else {
retValue = "&rv"
}
fmt.Fprintf(w, "\treturn %s, nil\n", retValue)
fmt.Fprintf(w, "\treturn &rv, nil\n")
}
fmt.Fprintf(w, "}\n")
// If there are argument and/or return types, emit them.
if f.Inputs != nil {
fmt.Fprintf(w, "\n")
fnInputsName := pkg.functionArgsTypeName(f)
pkg.genPlainType(w, fnInputsName, f.Inputs.Comment, "", f.Inputs.Properties)
if codegen.IsProvideDefaultsFuncRequired(f.Inputs) && !pkg.disableObjectDefaults {
if err := pkg.genPlainObjectDefaultFunc(w, fnInputsName, f.Inputs.Properties); err != nil {
return err
}
}
pkg.genPlainType(w, pkg.functionArgsTypeName(f), f.Inputs.Comment, "", f.Inputs.Properties)
}
if f.Outputs != nil {
fmt.Fprintf(w, "\n")
fnOutputsName := pkg.functionResultTypeName(f)
pkg.genPlainType(w, fnOutputsName, f.Outputs.Comment, "", f.Outputs.Properties)
if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults {
if err := pkg.genPlainObjectDefaultFunc(w, fnOutputsName, f.Outputs.Properties); err != nil {
return err
}
}
pkg.genPlainType(w, pkg.functionResultTypeName(f), f.Outputs.Comment, "", f.Outputs.Properties)
}
return nil
}
func (pkg *pkgContext) functionName(f *schema.Function) string {
@ -2135,24 +1991,16 @@ func rewriteCyclicObjectFields(pkg *schema.Package) {
}
}
func (pkg *pkgContext) genType(w io.Writer, obj *schema.ObjectType) error {
func (pkg *pkgContext) genType(w io.Writer, obj *schema.ObjectType) {
contract.Assert(!obj.IsInputShape())
if obj.IsOverlay {
// This type is generated by the provider, so no further action is required.
return nil
}
plainName := pkg.tokenToType(obj.Token)
pkg.genPlainType(w, plainName, obj.Comment, "", obj.Properties)
if !pkg.disableObjectDefaults {
if err := pkg.genPlainObjectDefaultFunc(w, plainName, obj.Properties); err != nil {
return err
}
return
}
pkg.genPlainType(w, pkg.tokenToType(obj.Token), obj.Comment, "", obj.Properties)
pkg.genInputTypes(w, obj.InputShape, pkg.detailsForType(obj))
pkg.genOutputTypes(w, genOutputTypesArgs{t: obj})
return nil
}
func (pkg *pkgContext) addSuffixesToName(typ schema.Type, name string) []string {
@ -2786,7 +2634,6 @@ func generatePackageContextMap(tool string, pkg *schema.Package, goInfo GoPackag
packages: packages,
liftSingleValueMethodReturns: goInfo.LiftSingleValueMethodReturns,
disableInputTypeRegistrations: goInfo.DisableInputTypeRegistrations,
disableObjectDefaults: goInfo.DisableObjectDefaults,
}
packages[mod] = pack
}
@ -3110,10 +2957,8 @@ func generatePackageContextMap(tool string, pkg *schema.Package, goInfo GoPackag
pkg.functions = append(pkg.functions, f)
name := tokenToName(f.Token)
if pkg.names.Has(name) ||
pkg.names.Has(name+"Args") ||
pkg.names.Has(name+"Result") {
originalName := name
if pkg.names.Has(name) {
switch {
case strings.HasPrefix(name, "New"):
name = "Create" + name[3:]
@ -3126,9 +2971,15 @@ func generatePackageContextMap(tool string, pkg *schema.Package, goInfo GoPackag
if f.Inputs != nil {
pkg.names.Add(name + "Args")
if originalName != name {
pkg.renamed[originalName+"Args"] = name + "Args"
}
}
if f.Outputs != nil {
pkg.names.Add(name + "Result")
if originalName != name {
pkg.renamed[originalName+"Result"] = name + "Result"
}
}
}
@ -3317,10 +3168,7 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
}
fileName := path.Join(mod, camel(tokenToName(f.Token))+".go")
code, err := pkg.genFunctionCodeFile(f)
if err != nil {
return nil, err
}
code := pkg.genFunctionCodeFile(f)
setFile(fileName, code)
}
@ -3360,9 +3208,7 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
pkg.genHeader(buffer, []string{"context", "reflect"}, importsAndAliases)
for _, t := range pkg.types {
if err := pkg.genType(buffer, t); err != nil {
return nil, err
}
pkg.genType(buffer, t)
delete(knownTypes, t)
}
@ -3498,12 +3344,4 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %%s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}
`

View file

@ -43,9 +43,7 @@ func CRDTypes(tool string, pkg *schema.Package) (map[string]*bytes.Buffer, error
if len(pkg.types) > 0 {
for _, t := range pkg.types {
if err := pkg.genType(buffer, t); err != nil {
return nil, err
}
pkg.genType(buffer, t)
}
pkg.genTypeRegistrations(buffer, pkg.types)
}

View file

@ -182,13 +182,15 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
// }
// g.Fgenf(w, " => new { Key = k, Value = v })")
case "fileArchive":
g.genNYI(w, "call %v", expr.Name)
// g.Fgenf(w, "new FileArchive(%.v)", expr.Args[0])
g.Fgenf(w, "pulumi.NewFileArchive(%.v)", expr.Args[0])
case "fileAsset":
g.Fgenf(w, "pulumi.NewFileAsset(%.v)", expr.Args[0])
case "filebase64":
// Assuming the existence of the following helper method
g.Fgenf(w, "filebase64OrPanic(%v)", expr.Args[0])
case "filebase64sha256":
// Assuming the existence of the following helper method
g.Fgenf(w, "filebase64sha256OrPanic(%v)", expr.Args[0])
case pcl.Invoke:
pkg, module, fn, diags := g.functionName(expr.Args[0])
contract.Assert(len(diags) == 0)
@ -1004,14 +1006,15 @@ func (g *generator) functionName(tokenArg model.Expression) (string, string, str
}
var functionPackages = map[string][]string{
"join": {"strings"},
"mimeType": {"mime", "path"},
"readDir": {"io/ioutil"},
"readFile": {"io/ioutil"},
"filebase64": {"io/ioutil", "encoding/base64"},
"toBase64": {"encoding/base64"},
"toJSON": {"encoding/json"},
"sha1": {"fmt", "crypto/sha1"},
"join": {"strings"},
"mimeType": {"mime", "path"},
"readDir": {"io/ioutil"},
"readFile": {"io/ioutil"},
"filebase64": {"io/ioutil", "encoding/base64"},
"toBase64": {"encoding/base64"},
"toJSON": {"encoding/json"},
"sha1": {"fmt", "crypto/sha1"},
"filebase64sha256": {"fmt", "io/ioutil", "crypto/sha256"},
}
func (g *generator) genFunctionPackages(x *model.FunctionCallExpression) []string {

View file

@ -77,6 +77,15 @@ func getHelperMethodIfNeeded(functionName string) (string, bool) {
panic(err.Error())
}
}`, true
case "filebase64sha256":
return `func filebase64sha256OrPanic(path string) pulumi.StringPtrInput {
if fileData, err := ioutil.ReadFile(path); err == nil {
hashedData := sha256.Sum256([]byte(fileData))
return pulumi.String(base64.StdEncoding.EncodeToString(hashedData[:]))
} else {
panic(err.Error())
}
}`, true
case "sha1":
return `func sha1Hash(input string) string {
hash := sha1.Sum([]byte(input))

View file

@ -60,10 +60,6 @@ type GoPackageInfo struct {
// Feature flag to disable generating input type registration. This is a
// space saving measure.
DisableInputTypeRegistrations bool `json:"disableInputTypeRegistrations,omitempty"`
// Feature flag to disable generating Pulumi object default functions. This is a
// space saving measure.
DisableObjectDefaults bool `json:"disableObjectDefaults,omitempty"`
}
// Importer implements schema.Language for Go.

View file

@ -192,22 +192,11 @@ var sdkTests = []sdkTest{
SkipCompileCheck: codegen.NewStringSet(nodejs),
},
{
Directory: "plain-object-defaults",
Description: "Ensure that object defaults are generated (repro #8132)",
Directory: "env-helper",
Description: "Ensure that eviromental helpers are generated (repro #8132)",
Skip: codegen.NewStringSet("python/test", "nodejs/test"),
SkipCompileCheck: codegen.NewStringSet(dotnet),
},
{
Directory: "plain-object-disable-defaults",
Description: "Ensure that we can still compile safely when defaults are disabled",
Skip: codegen.NewStringSet("python/test", "nodejs/test"),
SkipCompileCheck: codegen.NewStringSet(dotnet),
},
{
Directory: "regress-8403",
Description: "Regress pulumi/pulumi#8403",
SkipCompileCheck: codegen.NewStringSet(dotnet, python, nodejs),
},
}
var genSDKOnly bool

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -9,7 +9,6 @@
"plant-provider/tree/v1/init.go",
"plant-provider/tree/v1/nursery.go",
"plant-provider/tree/v1/pulumiEnums.go",
"plant-provider/tree/v1/pulumiUtilities.go",
"plant-provider/tree/v1/rubberTree.go"
]
}

View file

@ -17,19 +17,6 @@ type Container struct {
Size ContainerSize `pulumi:"size"`
}
// Defaults sets the appropriate defaults for Container
func (val *Container) Defaults() *Container {
if val == nil {
return nil
}
tmp := *val
if isZero(tmp.Brightness) {
brightness_ := ContainerBrightness(1.0)
tmp.Brightness = &brightness_
}
return &tmp
}
// ContainerInput is an input type that accepts ContainerArgs and ContainerOutput values.
// You can construct a concrete instance of `ContainerInput` via:
//

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -1,85 +0,0 @@
// *** WARNING: this file was generated by test. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package v1
import (
"fmt"
"os"
"reflect"
"regexp"
"strconv"
"strings"
"github.com/blang/semver"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type envParser func(v string) interface{}
func parseEnvBool(v string) interface{} {
b, err := strconv.ParseBool(v)
if err != nil {
return nil
}
return b
}
func parseEnvInt(v string) interface{} {
i, err := strconv.ParseInt(v, 0, 0)
if err != nil {
return nil
}
return int(i)
}
func parseEnvFloat(v string) interface{} {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return nil
}
return f
}
func parseEnvStringArray(v string) interface{} {
var result pulumi.StringArray
for _, item := range strings.Split(v, ";") {
result = append(result, pulumi.String(item))
}
return result
}
func getEnvOrDefault(def interface{}, parser envParser, vars ...string) interface{} {
for _, v := range vars {
if value := os.Getenv(v); value != "" {
if parser != nil {
return parser(value)
}
return value
}
}
return def
}
// PkgVersion uses reflection to determine the version of the current package.
func PkgVersion() (semver.Version, error) {
type sentinal struct{}
pkgPath := reflect.TypeOf(sentinal{}).PkgPath()
re := regexp.MustCompile("^.*/pulumi-plant/sdk(/v\\d+)?")
if match := re.FindStringSubmatch(pkgPath); match != nil {
vStr := match[1]
if len(vStr) == 0 { // If the version capture group was empty, default to v1.
return semver.Version{Major: 1}, nil
}
return semver.MustParse(fmt.Sprintf("%s.0.0", vStr[2:])), nil
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -29,20 +29,16 @@ func NewRubberTree(ctx *pulumi.Context,
return nil, errors.New("missing one or more required arguments")
}
containerApplier := func(v plantprovider.Container) *plantprovider.Container { return v.Defaults() }
if args.Container != nil {
args.Container = args.Container.ToContainerPtrOutput().Elem().ApplyT(containerApplier).(plantprovider.ContainerPtrOutput)
}
if isZero(args.Diameter) {
if args.Diameter == nil {
args.Diameter = Diameter(6.0)
}
if isZero(args.Farm) {
if args.Farm == nil {
args.Farm = pulumi.StringPtr("(unknown)")
}
if isZero(args.Size) {
if args.Size == nil {
args.Size = TreeSize("medium")
}
if isZero(args.Type) {
if args.Type == nil {
args.Type = RubberTreeVariety("Burgundy")
}
var resource RubberTree

View file

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View file

@ -7,8 +7,8 @@ import (
"context"
"reflect"
"env-helper/example/mod1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"plain-object-disable-defaults/example/mod1"
)
// A test for namespaces (mod 2)

View file

@ -7,8 +7,8 @@ import (
"context"
"reflect"
"env-helper/example/mod1"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"plain-object-disable-defaults/example/mod1"
)
type ModuleTest struct {

View file

@ -7,9 +7,9 @@ import (
"context"
"reflect"
"env-helper/example/mod1"
"env-helper/example/mod2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"plain-object-disable-defaults/example/mod1"
"plain-object-disable-defaults/example/mod2"
)
// BETA FEATURE - Options to configure the Helm Release resource.

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -219,8 +219,7 @@
}
},
"go": {
"importBasePath": "plain-object-disable-defaults/example",
"disableObjectDefaults": true
"importBasePath": "env-helper/example"
},
"nodejs": {
"dependencies": {

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -35,8 +35,8 @@ func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.Propert
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
switch args.Token {
case "mypkg::listStorageAccountKeys":
if args.Token == "mypkg::listStorageAccountKeys" {
targs := mypkg.ListStorageAccountKeysArgs{}
for k, v := range args.Args {
switch k {
@ -72,11 +72,12 @@ func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
"keys": result.Keys,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
case "mypkg::funcWithDefaultValue",
"mypkg::funcWithAllOptionalInputs",
"mypkg::funcWithListParam",
"mypkg::funcWithDictParam":
if args.Token == "mypkg::funcWithDefaultValue" ||
args.Token == "mypkg::funcWithAllOptionalInputs" ||
args.Token == "mypkg::funcWithListParam" ||
args.Token == "mypkg::funcWithDictParam" {
result := mypkg.FuncWithDefaultValueResult{
R: fmt.Sprintf("%v", args.Args),
}
@ -84,8 +85,9 @@ func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
"r": result.R,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
case "mypkg::getIntegrationRuntimeObjectMetadatum":
if args.Token == "mypkg::getIntegrationRuntimeObjectMetadatum" {
targs := mypkg.GetIntegrationRuntimeObjectMetadatumArgs{}
for k, v := range args.Args {
switch k {
@ -149,13 +151,16 @@ func TestListStorageAccountKeysOutput(t *testing.T) {
})
}
// TODO[pulumi/pulumi#7811]: it seems that default values are not
// supported by Go codegen yet, hence we do not observe "B" populated
// to default at all here.
func TestFuncWithDefaultValueOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := mypkg.FuncWithDefaultValueOutput(ctx, mypkg.FuncWithDefaultValueOutputArgs{
A: pulumi.String("my-a"),
})
r := waitOut(t, output.R())
assert.Equal(t, "map[a:{my-a} b:{b-default}]", r)
assert.Equal(t, "map[a:{my-a}]", r)
return nil
})
}

View file

@ -13,7 +13,7 @@ import (
// Check codegen of functions with default values.
func FuncWithDefaultValue(ctx *pulumi.Context, args *FuncWithDefaultValueArgs, opts ...pulumi.InvokeOption) (*FuncWithDefaultValueResult, error) {
var rv FuncWithDefaultValueResult
err := ctx.Invoke("mypkg::funcWithDefaultValue", args.Defaults(), &rv, opts...)
err := ctx.Invoke("mypkg::funcWithDefaultValue", args, &rv, opts...)
if err != nil {
return nil, err
}
@ -25,19 +25,6 @@ type FuncWithDefaultValueArgs struct {
B *string `pulumi:"b"`
}
// Defaults sets the appropriate defaults for FuncWithDefaultValueArgs
func (val *FuncWithDefaultValueArgs) Defaults() *FuncWithDefaultValueArgs {
if val == nil {
return nil
}
tmp := *val
if isZero(tmp.B) {
b_ := "b-default"
tmp.B = &b_
}
return &tmp
}
type FuncWithDefaultValueResult struct {
R string `pulumi:"r"`
}

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -22,53 +22,53 @@ func NewModuleResource(ctx *pulumi.Context,
return nil, errors.New("missing one or more required arguments")
}
if isZero(args.Optional_bool) {
if args.Optional_bool == nil {
args.Optional_bool = pulumi.BoolPtr(true)
}
args.Optional_const = pulumi.StringPtr("val")
if isZero(args.Optional_enum) {
if args.Optional_enum == nil {
args.Optional_enum = EnumThing(8)
}
if isZero(args.Optional_number) {
if args.Optional_number == nil {
args.Optional_number = pulumi.Float64Ptr(42.0)
}
if isZero(args.Optional_string) {
if args.Optional_string == nil {
args.Optional_string = pulumi.StringPtr("buzzer")
}
if isZero(args.Plain_optional_bool) {
if args.Plain_optional_bool == nil {
plain_optional_bool_ := true
args.Plain_optional_bool = &plain_optional_bool_
}
plain_optional_const_ := "val"
args.Plain_optional_const = &plain_optional_const_
if isZero(args.Plain_optional_number) {
if args.Plain_optional_number == nil {
plain_optional_number_ := 42.0
args.Plain_optional_number = &plain_optional_number_
}
if isZero(args.Plain_optional_string) {
if args.Plain_optional_string == nil {
plain_optional_string_ := "buzzer"
args.Plain_optional_string = &plain_optional_string_
}
if isZero(args.Plain_required_bool) {
if args.Plain_required_bool == false {
args.Plain_required_bool = true
}
args.Plain_required_const = "val"
if isZero(args.Plain_required_number) {
if args.Plain_required_number == 0.0 {
args.Plain_required_number = 42.0
}
if isZero(args.Plain_required_string) {
if args.Plain_required_string == "" {
args.Plain_required_string = "buzzer"
}
if isZero(args.Required_bool) {
if args.Required_bool == nil {
args.Required_bool = pulumi.Bool(true)
}
if isZero(args.Required_enum) {
if args.Required_enum == nil {
args.Required_enum = EnumThing(4)
}
if isZero(args.Required_number) {
if args.Required_number == nil {
args.Required_number = pulumi.Float64(42.0)
}
if isZero(args.Required_string) {
if args.Required_string == nil {
args.Required_string = pulumi.String("buzzer")
}
var resource ModuleResource

View file

@ -75,11 +75,3 @@ func PkgVersion() (semver.Version, error) {
}
return semver.Version{}, fmt.Errorf("failed to determine the package version from %s", pkgPath)
}
// isZero is a null safe check for if a value is it's types zero value.
func isZero(v interface{}) bool {
if v == nil {
return true
}
return reflect.ValueOf(v).IsZero()
}

View file

@ -1,26 +0,0 @@
// *** WARNING: this file was generated by test. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Pulumi.Serialization;
namespace Pulumi.Example.Mod1.Inputs
{
/// <summary>
/// A test for namespaces (mod 1)
/// </summary>
public sealed class TypArgs : Pulumi.ResourceArgs
{
[Input("val")]
public Input<string>? Val { get; set; }
public TypArgs()
{
Val = Utilities.GetEnv("PULUMI_EXAMPLE_MOD1_DEFAULT") ?? "mod1";
}
}
}

View file

@ -1,118 +0,0 @@
// Copyright 2016-2021, Pulumi Corporation.
//
// 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 codegentest
import (
"fmt"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"plain-object-defaults/example"
)
type mocks int
// We assert that default values were passed to our constuctor
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
checkFloat64 := func(v resource.PropertyValue, k string, expected float64) {
m := v.V.(resource.PropertyMap)
if m[resource.PropertyKey(k)].V.(float64) != expected {
panic(fmt.Sprintf("Expected %s to have value %.2f", k, expected))
}
}
for k, v := range args.Inputs {
switch k {
case "kubeClientSettings":
checkFloat64(v, "burst", 42)
case "backupKubeClientSettings":
checkFloat64(v, "qps", 7)
}
}
return args.Name, args.Inputs.Copy(), nil
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
panic("Call not supported")
}
func TestObjectDefaults(t *testing.T) {
path := "thePath"
defaultDriver := "secret"
kcs := example.HelmReleaseSettings{
PluginsPath: &path,
RequiredArg: "This is required",
}
withDefaults := kcs.Defaults()
assert.Equal(t, kcs.RequiredArg, withDefaults.RequiredArg)
assert.Equal(t, kcs.PluginsPath, withDefaults.PluginsPath)
assert.Nil(t, kcs.Driver)
assert.Equal(t, withDefaults.Driver, &defaultDriver)
}
func TestTransitiveObjectDefaults(t *testing.T) {
layered := example.LayeredType{
Other: example.HelmReleaseSettings{},
}
withDefaults := layered.Defaults()
assert.Equal(t, "secret", *withDefaults.Other.Driver)
}
// We already have that defaults for resources. We test that they translate through objects.
func TestDefaultResource(t *testing.T) {
os.Setenv("PULUMI_K8S_CLIENT_BURST", "42")
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := example.NewFoo(ctx, "foo", &example.FooArgs{
KubeClientSettings: example.KubeClientSettingsPtr(&example.KubeClientSettingsArgs{}),
BackupKubeClientSettings: &example.KubeClientSettingsArgs{Qps: pulumi.Float64(7)},
})
assert.NoError(t, err)
return nil
}, pulumi.WithMocks("example", "stack", mocks(0)))
}
func waitOut(t *testing.T, output pulumi.Output) interface{} {
result, err := waitOutput(output, 1*time.Second)
if err != nil {
t.Error(err)
return nil
}
return result
}
func waitOutput(output pulumi.Output, timeout time.Duration) (interface{}, error) {
c := make(chan interface{}, 2)
output.ApplyT(func(v interface{}) interface{} {
c <- v
return v
})
var timeoutMarker *int = new(int)
go func() {
time.Sleep(timeout)
c <- timeoutMarker
}()
result := <-c
if result == timeoutMarker {
return nil, fmt.Errorf("Timed out waiting for pulumi.Output after %v", timeout)
} else {
return result, nil
}
}

View file

@ -1,16 +0,0 @@
{
"emittedFiles": [
"example/doc.go",
"example/foo.go",
"example/funcWithAllOptionalInputs.go",
"example/init.go",
"example/mod1/pulumiTypes.go",
"example/mod1/pulumiUtilities.go",
"example/mod2/pulumiTypes.go",
"example/mod2/pulumiUtilities.go",
"example/moduleTest.go",
"example/provider.go",
"example/pulumiTypes.go",
"example/pulumiUtilities.go"
]
}

Some files were not shown because too many files have changed in this diff Show more