dynamo/.github/workflows/common.ps1

532 lines
13 KiB
PowerShell

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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.
set-strictmode -version latest
$global:_init_path = "${env:PWD}"
$global:_git_branch = $null
$global:_local = $null
$global:_local_srcdir = $null
$global:_repository_root = $null
$global:_verbosity = $null
$global:colors = @{
error = 'Red'
high = 'Cyan'
low = 'DarkGray'
medium = 'DarkBlue'
test = @{
failed = 'Red'
passed = 'Green'
}
title = 'Blue'
warning = 'Yellow'
}
function cleanup_after {
write-debug "<cleanup_after>"
$(reset_environment)
}
function configure_debug([bool] $enabled) {
write-debug "<configure_debug> enabled = '${enabled}'."
if ($enabled) {
# Notify user if any environment variables which could affect the build outcome are set prior to the build script running.
$overrides = @()
foreach ($entry in $(& get-childitem env:)) {
# We're only looking for environment variables which are used directly by the build scripts (starts with 'NVBUILD_`);
# and we're looking at environment variables which would indirectly affect the build scripts (i.e. `PATH`).
if ($entry.key.startswith('NVBUILD_')) {
# No reason to display values which are displayed when the build start, often time provided by the user.
if ($entry.key.endswith('_COMMAND') -or $entry.key.endswith('_VERBOSITY')) {
continue
}
$overrides += $entry
}
}
if ($overrides.count -gt 0) {
write-low ' Overriding environment variables:'
foreach ($entry in $overrides) {
write-low " $($entry.key) = $($entry.Value)"
}
}
}
}
function create_directory([string] $path, [switch] $recreate) {
write-debug "<create_directory> path = '${path}'."
write-debug "<create_directory> recreate = ${recreate}"
$path_local = $(to_local_path $path)
write-debug "<ensure_directory> path_local = '${path_local}'."
if (test-path $path_local -pathType Container) {
if ($recreate) {
remove-item $path_local -Recurse | out-null
new-item $path_local -itemtype Directory | out-null
}
}
else {
new-item $path_local -itemtype Directory | out-null
}
}
function default_git_branch {
if (is_installed 'git') {
$value = "$(git branch --show-current)"
}
else {
$value = 'main'
}
write-debug "<default_git_branch> -> '${value}'."
return $value
}
function default_local_srcdir {
$value = $(& git rev-parse --show-toplevel)
write-debug "<default_local_srcdir> -> '${value}'."
return $value;
}
function default_verbosity {
$value = 'NORMAL'
write-debug "<default_verbosity> -> '${value}'."
return $value
}
function env_get_git_branch {
$value = $env:NVBUILD_GIT_BRANCH
write-debug "<env_get_git_branch> -> '${value}'."
return $value
}
function env_get_local_srcdir {
$value = $env:NVBUILD_LOCAL_SRCDIR
write-debug "<env_get_local_srcdir> -> '${value}'."
return $value
}
function env_get_verbosity {
$value = $env:NVBUILD_VERBOSITY
write-debug "<env_get_verbosity> -> '${value}'."
return $value
}
function env_set_git_branch([string] $value) {
if ($null -eq $env:NVBUILD_NOSET) {
write-debug "<env_set_git_branch> value: '${value}'."
$env:NVBUILD_GIT_BRANCH = $value
}
}
function env_set_local_srcdir([string] $value) {
if ($null -eq $env:NVBUILD_NOSET) {
write-debug "<env_set_local_srcdir> value: '${value}'."
$env:NVBUILD_LOCAL_SRCDIR = $value
}
}
function env_set_verbosity([string] $value) {
if ($null -eq $env:NVBUILD_NOSET) {
write-debug "<env_set_verbosity> value: '${value}'."
$env:NVBUILD_VERBOSITY = $value
}
}
function fatal_exit([string] $message) {
write-error "fatal: ${message}"
exit 1
}
function get_git_branch {
if ($null -eq $global:_git_branch) {
$value = $(env_set_git_branch)
if ($null -ne $value) {
set_git_branch $value
}
else {
set_git_branch $(default_git_branch)
}
}
write-debug "<get_git_branch> -> '${global:_git_branch}'."
return $global:_git_branch
}
function get_local_srcdir {
if ($null -eq $global:_local_srcdir) {
$value = $(env_get_local_srcdir)
if ($null -ne $value) {
set_local_srcdir $value
}
else {
set_local_srcdir $(default_local_srcdir)
}
}
write-debug "<get_local_srcdir> -> '${global:_local_srcdir}'."
return $global:_local_srcdir
}
function get_repository_root {
if ($null -eq $global:_repository_root) {
$path = $(& git rev-parse --show-toplevel)
$global:_repository_root = $(normalize_path $path)
}
write-debug "<get_repository_root> '${global:_repository_root}'."
return $global:_repository_root
}
function get_verbosity {
if ($null -eq $global:_verbosity) {
$value = $(env_get_verbosity)
if ($null -ne $value) {
set_verbosity $value
}
else {
set_verbosity $(default_verbosity)
}
}
write-debug "<get_verbosity> -> '${global:_verbosity}'."
return $global:_verbosity
}
function is_debug {
$value = $($null -ne $env:NVBUILD_DEBUG_TRACE)
write-debug "<is_debug> -> ${value}."
return $value
}
function is_empty([string] $value) {
return [System.String]::IsNullOrWhiteSpace($value)
}
function is_git_ignored([string] $path) {
$repo_root = $(get_repository_root)
if ($path.startswith($repo_root)) {
$path = $path.substring($repo_root.length)
}
if ($path.startswith('/')) {
$path = $path.substring(1)
}
$result = $(& git check-ignore $path)
return (0 -eq $result)
}
function is_installed([string] $command) {
write-debug "<is_installed> command = '${command}'."
$out = $null -ne $(get-command "${command}" -errorAction SilentlyContinue)
write-debug "<is_installed> -> ${out}."
return $out
}
function is_tty {
return -not(([System.Console]::IsOutputRedirected) -or ([System.Console]::IsErrorRedirected))
}
function is_verbosity_valid([string] $value) {
return (('NORMAL' -eq $value) -or ('MINIMAL' -eq $value) -or ('DETAILED' -eq $value))
}
function normalize_path([string] $path) {
write-debug "<normalize-path> path: '${path}'."
$out = "$(resolve-path "${path}" -erroraction 'Ignore')"
if (($null -eq $out) -or ($out.length -eq 0)) {
if ($path.startswith($(get_repository_root))) {
$out = $path
}
else {
$out = "$(get_repository_root)/${path}"
}
}
if ($IsWindows) {
if ($out -match "^[A-Z]:") {
$out = $out.substring(2)
}
$out = $out.replace('\', '/')
}
write-debug "<normalize-path> '${path}' -> '${out}'."
return $out
}
function read_content([string] $path, [switch] $lines, [switch] $bytes) {
if (is_empty $path -or ($lines -and $bytes)) {
write-error 'usage: read_content {path} [(-bytes|-lines)]' -category InvalidArgument
write-error ' {path} file system path of the file to read contents from.'
write-error ' -bytes when provided content is returned as an array of bytes. mutually exclusive with -lines.'
write-error ' -lines when provided content is returned as an array of strings. mutually exclusive with -bytes.'
write-error ' '
usage_exit 'read_content {path} [(-bytes|-lines)]'
}
write-debug "<read_content> path: '${path}'."
write-debug "<read_content> bytes: ${bytes}."
write-debug "<read_content> lines: ${lines}."
$path = normalize_path $path
if ($bytes) {
return get-content -path $path -asbytestream -raw
}
if ($lines) {
return get-content -path $path
}
return get-content -path $path -raw
}
function reset_environment {
write-debug "<reset_environment>"
$overrides = @()
foreach ($entry in $(& get-childitem env:)) {
# We're only looking for environment variables which are used directly by the build scripts (starts with 'NVBUILD_`);
# and we're looking at environment variables which would indirectly affect the build scripts (i.e. `PATH`).
if ($entry.key.startswith('NVBUILD_')) {
$overrides += $entry
}
}
if ($overrides.count -gt 0) {
foreach ($entry in $overrides) {
$expression = '$env:' + "$($entry.Key)" + ' = $null'
invoke-expression "${expression}"
if ("$($entry.Key)" -ne 'NVBUILD_NOSET') {
write-debug "<reset_environment> removed '$($entry.Key)'."
}
}
}
}
function run([string] $command) {
if ($null -eq $command) {
write-error 'usage: run {command}' -category InvalidArgument
write-error ' {command} is the command to execute.'
write-error ' '
usage_exit 'run {command}'
}
write-debug "<run> command = '${command}'."
if ('MINIMAL' -ne $(get_verbosity)) {
write-high "${command}"
}
invoke-expression "${command}" | out-default
$exit_code = $LASTEXITCODE
write-debug "<run> exit_code = ${exit_code}."
if ($exit_code -ne 0) {
write-error "fatal: Command ""${command}"" failed, returned ${exit_code}." -category fromStdErr
exit $exit_code
}
}
function set_git_branch([string] $value) {
write-debug "<set_git_branch> value = '${value}'."
$global:_git_branch = $value
env_set_git_branch $value
}
function set_local_srcdir([string] $value) {
write-debug "<set_local_srcdir> value: '${value}'."
$global:_local_srcdir = $value
env_set_local_srcdir $value
}
function set_verbosity([string] $value) {
write-debug "<set_verbosity> '${value}'."
if (-not(is_verbosity_valid $value)) {
throw "Invalid verbosity value '${value}'."
}
$global:_verbosity = $value
env_set_verbosity $value
}
function to_local_path([string] $path) {
write-debug "<to_local_path> path: '${path}'."
if ($null -eq $path) {
return $(get_local_srcdir)
}
$out = $path.trim()
$out = $out.trim('/','\')
$out = join-path $(get_local_srcdir) $out
$out = $(normalize_path $out)
return $out
}
function typeof($object) {
if ($null -eq $object) {
return 'null'
}
return $object.gettype().name
}
function usage_exit([string] $message) {
write-error "usage: $message"
exit 254
}
function value_or_default([string] $value, [string] $default) {
if (($null -eq $value) -or ($value.Length -eq 0)) {
return $default
}
return $value
}
function write_content([string] $content, [string] $path, [switch] $overwrite) {
if (($null -eq $path) -or ($path.length -eq 0)) {
write-error 'usage: write_content {content} {path}'
write-error ' {content} is the content to be written to a file.'
write-error ' {path} is the path to file into which to write content.'
usage_exit 'write_content {content} {path}'
}
write-debug "<write_content> content = $($content.length) bytes."
write-debug "<write_content> path = '${path}'."
$path_local = normalize_path $path
write-debug "<write-content> '${path_local}'."
if ($null -eq $content) {
$content = ''
}
if ($overwrite -and (test-path $path_local)) {
remove-item $path_local | out-null
}
$content | out-file $path_local
}
function __write([string] $value, [string] $color, [bool] $no_newline) {
if (is_tty) {
$opts = @{
NoNewline = $no_newline
}
if (($null -ne $color) -and ($color.length -gt 0)) {
$opts.ForegroundColor = $color
}
write-host $value @opts
}
else {
if (-not($no_newline)) {
$value = "${value}`n"
}
write-output $value
}
}
function write-detailed {
param([string] $value, [string] $color = $null, [switch] $no_newline)
if ('DETAILED' -eq $(get_verbosity)) {
__write $value $color $no_newline
}
}
function write-error([string] $value) {
$opts = @{
color = $global:colors.error
no_newline = $false
}
write-minimal $value @opts
}
function write-failed([string] $value) {
if (is_tty) {
write-normal ' [Failed]' $global:colors.test.failed -no_newline
write-normal " ${value}"
}
else {
write-output " Test: [Failed] ${value}"
}
}
function write-high {
param([string] $value, [switch] $no_newline)
$opts = @{
color = $global:colors.high
no_newline = $no_newline
}
write-minimal $value @opts
}
function write-low {
param([string] $value, [switch] $no_newline)
$opts = @{
color = $global:colors.low
no_newline = $no_newline
}
write-detailed $value @opts
}
function write-medium {
param([string] $value, [switch] $no_newline)
$opts = @{
color = $global:colors.medium
no_newline = $no_newline
}
write-normal $value @opts
}
function write-minimal {
param([string] $value, [string] $color = $null, [switch] $no_newline)
__write $value $color $no_newline
}
function write-normal {
param([string] $value, [string] $color = $null, [switch] $no_newline)
if ('MINIMAL' -ne $(get_verbosity)) {
$opts = @{
color = $color
no_newline = $no_newline
}
__write $value @opts
}
}
function write-passed([string] $value) {
if (is_tty) {
write-detailed ' [Passed]' $global:colors.test.passed -no_newline
write-detailed " ${value}"
}
else {
write-output " Test: [Passed] ${value}"
}
}
function write-title([string] $value) {
write-minimal $value $global:colors.title
}
function write-warning([string] $value) {
write-minimal $value $global:colors.warning
}