Skip to content

Commit

Permalink
go rewrite - copy script and adjustments for compute (#10929)
Browse files Browse the repository at this point in the history
  • Loading branch information
c2thorn authored Jun 11, 2024
1 parent d2afb5f commit 4982932
Show file tree
Hide file tree
Showing 22 changed files with 498 additions and 292 deletions.
2 changes: 1 addition & 1 deletion mmv1/api/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ func Compile(yamlPath string, obj interface{}) {
}

yamlValidator := google.YamlValidator{}
yamlValidator.Parse(objYaml, obj)
yamlValidator.Parse(objYaml, obj, yamlPath)
}
6 changes: 6 additions & 0 deletions mmv1/api/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ def all_nested_properties(props)
nested
end

def convert_go_file(file)
dir, base = File.split(file)
base.slice! '.erb'
"#{dir}/go/#{base}.tmpl"
end

# All settable properties in the resource.
# Fingerprints aren't *really" settable properties, but they behave like one.
# At Create, they have no value but they can just be read in anyways, and after a Read
Expand Down
4 changes: 3 additions & 1 deletion mmv1/api/type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,9 @@ def nested_properties

def item_type_class
return @item_type \
if @item_type.instance_of?(Class)
if @item_type.instance_of?(Class) \
|| @item_type.is_a?(Api::Type::ResourceRef) \
|| @item_type.is_a?(Api::Type::Enum)

Object.const_get(@item_type)
end
Expand Down
7 changes: 6 additions & 1 deletion mmv1/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
products_to_generate = nil
all_products = false
yaml_dump = false
go_yaml = false
generate_code = true
generate_docs = true
output_path = nil
Expand Down Expand Up @@ -94,6 +95,9 @@
opt.on('--openapi-generate', 'Generate MMv1 YAML from openapi directory (Experimental)') do
openapi_generate = true
end
opt.on('--go-yaml', 'Generate MMv1 Go YAML from Ruby YAML') do
go_yaml = true
end
end.parse!
# rubocop:enable Metrics/BlockLength

Expand Down Expand Up @@ -270,7 +274,8 @@
product_name,
yaml_dump,
generate_code,
generate_docs
generate_docs,
go_yaml
)

# we need to preserve a single provider instance to use outside of this loop.
Expand Down
147 changes: 147 additions & 0 deletions mmv1/description-copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package main

import (
"bufio"
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"strings"
)

// Used to copy/paste text from Ruby -> Go YAML files
func CopyText(identifier string) {
var allProductFiles []string = make([]string, 0)
files, err := filepath.Glob("products/**/go_product.yaml")
if err != nil {
return
}
for _, filePath := range files {
dir := filepath.Dir(filePath)
allProductFiles = append(allProductFiles, fmt.Sprintf("products/%s", filepath.Base(dir)))
}

for _, productPath := range allProductFiles {
// Gather go and ruby file pairs
yamlMap := make(map[string][]string)
yamlPaths, err := filepath.Glob(fmt.Sprintf("%s/*", productPath))
if err != nil {
log.Fatalf("Cannot get yaml files: %v", err)
}
for _, yamlPath := range yamlPaths {
if strings.HasSuffix(yamlPath, "_new") {
continue
}
fileName := filepath.Base(yamlPath)
baseName, found := strings.CutPrefix(fileName, "go_")
if yamlMap[baseName] == nil {
yamlMap[baseName] = make([]string, 2)
}
if found {
yamlMap[baseName][1] = yamlPath
} else {
yamlMap[baseName][0] = yamlPath
}
}

for _, files := range yamlMap {
rubyPath := files[0]
goPath := files[1]
var text []string
currText := ""
recording := false

if strings.Contains(rubyPath, "product.yaml") {
// log.Printf("skipping %s", rubyPath)
continue
}

// Ready Ruby yaml
file, _ := os.Open(rubyPath)
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, identifier) && !strings.HasPrefix(strings.TrimSpace(line), "#") {
currText = strings.SplitAfter(line, identifier)[1]
recording = true
} else if recording {
if terminateText(line) {
text = append(text, currText)
currText = ""
recording = false
} else {
currText = fmt.Sprintf("%s\n%s", currText, line)
}
}
}
if recording {
text = append(text, currText)
}

// Read Go yaml while writing to a temp file
index := 0
firstLine := true
newFilePath := fmt.Sprintf("%s_new", goPath)
fo, _ := os.Create(newFilePath)
w := bufio.NewWriter(fo)
file, _ = os.Open(goPath)
defer file.Close()
scanner = bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if firstLine {
if line != "NOT CONVERTED - RUN YAML MODE" {
// log.Printf("skipping %s", goPath)
break
} else {
firstLine = false
continue
}
}
if strings.Contains(line, identifier) {
if index >= len(text) {
log.Printf("did not replace %s correctly! Is the file named correctly?", goPath)
w.Flush()
break
}
line = fmt.Sprintf("%s%s", line, text[index])
index += 1
}
w.WriteString(fmt.Sprintf("%s\n", line))
}

if !firstLine {
if index != len(text) {
log.Printf("potential issue with %s, only completed %d index out of %d replacements", goPath, index, len(text))
}
if err = w.Flush(); err != nil {
panic(err)
}

// Overwrite original file with temp
os.Rename(newFilePath, goPath)
} else {
os.Remove(newFilePath)
}
}

}

}

// quick and dirty logic to determine if a description/note is terminated
func terminateText(line string) bool {
terminalStrings := []string{
"!ruby/",
}

for _, t := range terminalStrings {
if strings.Contains(line, t) {
return true
}
}

return regexp.MustCompile(`^\s*[a-z_]+:[\s$]*`).MatchString(line)
}
4 changes: 2 additions & 2 deletions mmv1/google/yaml_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import (
// A helper class to validate contents coming from YAML files.
type YamlValidator struct{}

func (v *YamlValidator) Parse(content []byte, obj interface{}) {
func (v *YamlValidator) Parse(content []byte, obj interface{}, yamlPath string) {
// TODO(nelsonjr): Allow specifying which symbols to restrict it further.
// But it requires inspecting all configuration files for symbol sources,
// such as Enum values. Leaving it as a nice-to-have for the future.
if err := yaml.Unmarshal(content, obj); err != nil {
log.Fatalf("Cannot unmarshal data: %v", err)
log.Fatalf("Cannot unmarshal data from file %s: %v", yamlPath, err)
}
}

Expand Down
10 changes: 10 additions & 0 deletions mmv1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,18 @@ var version = flag.String("version", "", "optional version name. If specified, t

var product = flag.String("product", "", "optional product name. If specified, the resources under the specific product will be generated. Otherwise, resources under all products will be generated.")

// Example usage: --yaml
var yamlMode = flag.Bool("yaml", false, "strictly copy text over from ruby yaml to go yaml")

func main() {
flag.Parse()

if *yamlMode {
CopyText("description:")
CopyText("note:")
return
}

var generateCode = true
var generateDocs = true

Expand Down
12 changes: 6 additions & 6 deletions mmv1/products/compute/ForwardingRule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ custom_code: !ruby/object:Provider::Terraform::CustomCode
custom_diff: [
'forwardingRuleCustomizeDiff',
]
virtual_fields:
- !ruby/object:Api::Type::Boolean
name: recreate_closed_psc
description:
This is used in PSC consumer ForwardingRule to make terraform recreate the ForwardingRule when the status is closed
default_value: false
parameters:
- !ruby/object:Api::Type::ResourceRef
name: 'region'
Expand Down Expand Up @@ -656,9 +662,3 @@ properties:
- :IPV6
immutable: true
default_from_api: true
virtual_fields:
- !ruby/object:Api::Type::Boolean
name: recreate_closed_psc
description:
This is used in PSC consumer ForwardingRule to make terraform recreate the ForwardingRule when the status is closed
default_value: false
Loading

0 comments on commit 4982932

Please sign in to comment.