tools/versions.py (46 lines of code) (raw):
#!/usr/bin/env python3
# Copyright 2025 Google LLC
#
# 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
#
# https://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.
import re
from pathlib import Path
import click
HEADER = "".join(open(__file__).readlines()[2:15])
VERSIONS_TEMPLATE = """
# Fabric release: {fabric_release}
terraform {{
required_version = ">= {engine_version}"
required_providers {{
google = {{
source = "hashicorp/google"
version = ">= {provider_min_version}, < {provider_max_version}" # tftest
}}
google-beta = {{
source = "hashicorp/google-beta"
version = ">= {provider_min_version}, < {provider_max_version}" # tftest
}}
}}
provider_meta "google" {{
module_name = "google-pso-tool/cloud-foundation-fabric/{path}:{fabric_release}-{engine}"
}}
provider_meta "google-beta" {{
module_name = "google-pso-tool/cloud-foundation-fabric/{path}:{fabric_release}-{engine}"
}}
}}
"""
def extract_variables(template, interpolated_string):
# Find all variable names in the escaped template
variable_names = re.findall(r'\{(.*?)\}', template)
# Create a regular expression pattern to match the interpolated string within the template
pattern = re.sub(r'\{(.*?)\}', r'(.*?)', template)
pattern = pattern.replace("{{", "{").replace("}}", "}")
pattern = r'.*?' + pattern + r'.*?'
# Extract the values using the pattern
match = re.search(pattern, interpolated_string)
if match:
return dict(zip(variable_names, match.groups()))
def process_file(file_path, context):
with file_path.open("w", encoding="utf-8") as f:
f.write(HEADER)
f.write(VERSIONS_TEMPLATE.format(**context))
@click.command()
@click.option("--fabric-release", help="Override Fabric release version")
@click.option("--provider-min-version",
help="Override GCP provider min version")
@click.option("--provider-max-version",
help="Override GCP provider max version")
@click.option("--tf-version", help="Override Terraform version")
@click.option("--tofu-version", help="Override OpenTofu version")
@click.option("--write-defaults/--no-write-defaults", default=False,
help="Also rewrite default-versions.t*f*")
def main(write_defaults, **kwargs):
root_path = Path(__file__).parents[1]
overrides = {k: v for k, v in kwargs.items() if v is not None}
for engine in ["tf", "tofu"]:
defaults_fname = root_path / f"default-versions.{engine}"
defaults = extract_variables(VERSIONS_TEMPLATE, defaults_fname.read_text())
context = defaults | overrides
if kwargs[f'{engine}_version'] is not None:
context['engine_version'] = kwargs[f'{engine}_version']
for file_path in root_path.rglob(f"versions.{engine}"):
click.echo(f"Processing {file_path}")
process_file(file_path, context | {
"path": file_path.parent.relative_to(root_path),
})
if write_defaults:
click.echo(f"Processing {defaults_fname}")
process_file(defaults_fname, context)
if __name__ == "__main__":
main()