diff --git a/gitpyup/Deploy-gitpyup.ps1 b/gitpyup/Deploy-gitpyup.ps1 index 11a6dfd..425c745 100644 --- a/gitpyup/Deploy-gitpyup.ps1 +++ b/gitpyup/Deploy-gitpyup.ps1 @@ -16,7 +16,6 @@ param( # variables $scriptVersion = "v1" $gpun = "gitpyup" -$Env:GITPYUPUTILSNAME = "Utility-Functions.ps1" $installConfigFile = "installConfig.yaml" $defaultGitpyup = @{ # default gitpyup config @@ -54,9 +53,9 @@ $shortcutScript = { [array]$toAdd ) - . "./$Env:GITPYUPUTILSNAME" + . "./Utility-Functions.ps1" Start-Logging - + # TODO: check if have permissions to remove, if needed get permissions, ideally from existing elevated process # remove old shortcuts foreach ($shortcut in $toRemove) { @@ -170,7 +169,7 @@ function Reset-Path { # save the Start-Logging function to a file # define the path to the file -$utilityFunctionsPath = Join-Path -Path (Get-Location).Path -ChildPath $Env:GITPYUPUTILSNAME +$utilityFunctionsPath = Join-Path -Path (Get-Location).Path -ChildPath "Utility-Functions.ps1" # Write the function to the file Set-Content -Force -Path $utilityFunctionsPath -Value $utilityString @@ -268,9 +267,9 @@ $installSupportSoftware = { } } - . "./$Env:GITPYUPUTILSNAME" - Start-Logging -PrintVersion - + . "./Utility-Functions.ps1" + Start-Logging + function Install-ViaWinget { param( [string]$AppTestCommand, @@ -738,7 +737,7 @@ $installConfig = @{ $response = ConvertTo-Yaml $installConfig -OutFile $installConfigPath Write-Log "The config yml has been written to $installConfigPath" -if (-not (Test-Path $Env:GITPYUPUTILSNAME)){ +if (-not (Test-Path "Utility-Functions.ps1")){ Copy-Item $utilityFunctionsPath . Write-Log "The application yml has been copied to $gitpyupScriptDir" } @@ -795,24 +794,44 @@ while(($confirm -ne "y") -and ($confirm -ne "n")) } } +$pinfo = New-Object System.Diagnostics.ProcessStartInfo +$pinfo.FileName = "powershell" +$pinfo.RedirectStandardError = $true +$pinfo.RedirectStandardOutput = $false +$pinfo.UseShellExecute = $false +$pinfo.CreateNoWindow = $false # doesn't seem to open a window but when false does output to console +$pinfo.WorkingDirectory = (Get-Location).Path + # create or update the python environment for each application foreach ($application in $appConfigs) { $name = $application.name # gitpyup is not a python application - if ($application.name -eq $gpun) { + if ($name -eq $gpun) { continue } $confirm = "" - while(($confirm -ne "y") -and ($confirm -ne "n")) - { + while(($confirm -ne "y") -and ($confirm -ne "n")) { $confirm = Read-Host -Prompt "Do you want to install or update $name ? (y/n)" if ($confirm -ceq "y") { - $proc = Start-Process -FilePath "powershell" -PassThru ` - -ArgumentList "-Command & '.\Setup-Application.ps1' -AppConfig $application -InstallType $($install.type)" - $handle = $proc.Handle - $proc.WaitForExit(); - if ($proc.ExitCode -ne 0) { - Write-Log "Python environment setup failed for $name, re-run $gpun-update shortcut to try again." -Level 'ERROR' + $pinfo.Arguments = "-Command & './Setup-Application.ps1' " + + "-Name $name " + + "-Path $($application.path) " + # if $application contains environment_file key use it else use null + if ($application.ContainsKey("environment_file")) { + $pinfo.Arguments += "-EnvironmentFile $($application.environment_file) " + } + $pinfo.Arguments += "-InstallType $($install.type)" + $p = New-Object System.Diagnostics.Process + $p.StartInfo = $pinfo + $p.Start() | Out-Null + $p.WaitForExit() + if ($p.ExitCode -ne 0) { + Write-Log "Python environment setup failed for $name, Run $gpun-update shortcut to try again!" -Level 'ERROR' + Write-Log "exit code: $($p.ExitCode)" -Level 'ERROR' + $stderr = $p.StandardError.ReadToEnd() + if ($stderr) { + Write-Log "stderr: $stderr" -Level 'ERROR' + } } else { Write-Log "Python environment setup complete for $name." } diff --git a/gitpyup/Setup-Application.ps1 b/gitpyup/Setup-Application.ps1 index 51cfae6..790b31d 100644 --- a/gitpyup/Setup-Application.ps1 +++ b/gitpyup/Setup-Application.ps1 @@ -4,25 +4,27 @@ This script creates or updates the python applications configured in gitpyup. #> param( - [hashtable]$AppConfig = @{}, + [string]$Name = "", + [string]$Path = "", + [string]$EnvironmentFile = "", [string]$InstallType = "SingleUser", [string]$LocalConfigYaml = "gitpyup.yml" ) # logging -. "./$ENV:GITPYUPUTILSNAME" +. "./Utility-Functions.ps1" Start-Logging Write-Log "Setup-Application v1" -if ($AppConfig.ContainsKey("name")) { - $appName = $AppConfig["name"] +if ($Name) { + $appName = $Name } else { $appName = Split-Path (Get-Location).Path -Parent } -if ($AppConfig.ContainsKey("path")) { - $appPath = $AppConfig["path"] +if ($Path) { + $appPath = $Path } else { $appPath = (Get-Location).Path } @@ -30,10 +32,12 @@ if ($AppConfig.ContainsKey("path")) { # load repo config $configYmlPath = Join-Path $appPath $LocalConfigYaml if (Test-Path $configYmlPath) { + Write-Log "Using config file $configYmlPath" # config file found $repoConfigRaw = Get-Content -Path $configYmlPath -Raw $repoConfig = ConvertFrom-Yaml $repoConfigRaw } else { + Write-Log "No config file found in $appPath" $repoConfig = @{} } @@ -49,7 +53,9 @@ $envFiles = @( ) # auto-detect environment file foreach ($autoEnvFile in $envFiles) { + #LINUX #MACOS make case insensitive if (Test-Path (Join-Path $appPath $autoEnvFile)) { + Write-Log "Automatically found environment file $autoEnvFile" break } } @@ -60,8 +66,8 @@ if ($repoConfig.ContainsKey("environment_file")) { } # app config has priority over repo config -if ($AppConfig.ContainsKey("environment_file")) { - $envFile = $AppConfig["environment_file"] +if ($EnvironmentFile) { + $envFile = $EnvironmentFile } # if environment file exists continue if not return error @@ -71,61 +77,64 @@ if (Test-Path $envFilePath -PathType Leaf) { Write-Log "Using environment file $envFilePath" } elseif (Test-Path $autoEnvFilePath -PathType Leaf) { $envFilePath = $autoEnvFilePath - Write-Log "Automatically found environment file $envFilePath" + Write-Log "Using automatically found environment file $autoEnvFilePath" } else { - Write-Log "No environment file found in $appPath" -Level "ERROR" - Return 1 + $message = "No environment file found in $appPath" + Write-Log "$message" -Level "ERROR" + Exit 1 } -# check for existing conda environment, create if not found +# set environment file type and condaEnvName +$envFile = Split-Path $envFilePath -Leaf $condaEnvName = $appName -$condaEnvList = conda env list -if ($condaEnvList | Select-String -Pattern $condaEnvName) { - Write-Log "Conda environment $condaEnvName already exists" -} else { - Write-Log "Creating conda environment $condaEnvName" - $response = conda create -n $condaEnvName - Write-Log ($response | Out-String) -} # configure install/update command -if ($envFile -ieq "environment.yml" -or $envFile -ieq "environment.yaml") { +if ($envFile.Contains(".yml") -or $envFile.Contains(".yaml")) { $installCommand = "conda env update -n $condaEnvName --file $envFilePath --prune" - $successString = "Successfully installed " } elseif ($envFile -ieq "setup.py" -or $envFile -ieq "pyproject.toml") { $installCommand = "conda run -n $condaEnvName python -m pip install -e $appPath" } elseif ($envFile -ieq "requirements.txt") { $installCommand = "conda run -n $condaEnvName python -m pip install -r $envFilePath" } else { Write-Log "Unsupported environment file $envFile" -Level "ERROR" - Return 1 + Exit 1 +} + +# check for existing conda environment, create if not found +$condaEnvList = conda env list +if ($condaEnvList | Select-String -Pattern $condaEnvName) { + Write-Log "Conda environment $condaEnvName exists" +} else { + Write-Log "Creating conda environment $condaEnvName" + $response = conda create -n $condaEnvName + Write-Log ($response | Out-String) } # install or update python into environment -if ($envFile -ieq "setup.py" -or $envFile -ieq "requirements.txt") { +if ($envFile -ieq "setup.py" -or $envFile -ieq "requirements.txt" -or $envFile -ieq "pyproject.toml") { # get version of python in base environment $response = conda run -n base python --version - if ($response -match "Python (\d+\.\d+\.\d+)") { + if (($response | Out-String) -match "Python (\d+\.\d+\.\d+)") { $basePythonVersion = $matches[1] Write-Log "base environment Python version: $basePythonVersion" } else { Write-Log "No Python found in base environment." -Level "ERROR" - return 1 + Exit 1 } # get current version of python in environment, install if not found $response = conda run -n $condaEnvName python --version - if ($response -match "Python (\d+\.\d+\.\d+)") { + if (($response | Out-String) -match "Python (\d+\.\d+\.\d+)") { $pythonVersion = $matches[1] Write-Log "$condaEnvName environment Python version: $pythonVersion" } else { Write-Log "It is normal to see 'Python was not found' above this message." - Write-Log "Installing Python=$basePythonVersion into $condaEnvName environment..." + Write-Log "Installing Python=$basePythonVersion into $condaEnvName conda environment..." $response = conda install -n $condaEnvName python=$basePythonVersion -y Write-Log ($response | Out-String) } # if versions don't match update python if ($pythonVersion -ne $basePythonVersion) { - Write-Log "Updating to Python=$basePythonVersion in $condaEnvName environment..." + Write-Log "Updating to Python=$basePythonVersion in $condaEnvName conda environment..." $response = conda install -n $condaEnvName python=$basePythonVersion -y Write-Log ($response | Out-String) } @@ -147,14 +156,9 @@ While (!($Success) -and ($NumAttempts -lt 5)) { $Success = $False } - # success string based test overrides exit code - if ($successString) { - $Success = $response | Select-String -Pattern $successString - } - if ($Success) { Write-Log ($response | Out-String) - Write-Log "Successfully installed or updated" + Write-Log "Successfully installed or updated $appName in $condaEnvName conda environment" # environment files have no permissions for 'Users' group if ($InstallType -eq "AllUsers") { Write-Log "Granting permissions to env folder. This can take over 30 minutes..." @@ -162,6 +166,7 @@ While (!($Success) -and ($NumAttempts -lt 5)) { icacls $EnvPath /grant:r "Users:(OI)(CI)F" /T /Q # full permissions } } else { + Write-Log "Attempt $NumAttempts failed to install or update" -Level "ERROR" Write-Log ($response | Out-String) -Level "ERROR" } $NumAttempts++ @@ -172,4 +177,4 @@ if ($Env:GITPYUP_DEPLOY_DEBUG) { Read-Host -Prompt "Press enter key to exit" | Out-Null } -Return $LASTEXITCODE \ No newline at end of file +Exit $installExitCode \ No newline at end of file diff --git a/gitpyup/Setup-NationalInstruments.ps1 b/gitpyup/Setup-NationalInstruments.ps1 index f8adf83..96c01b7 100644 --- a/gitpyup/Setup-NationalInstruments.ps1 +++ b/gitpyup/Setup-NationalInstruments.ps1 @@ -6,8 +6,8 @@ This script sets up National Instruments software using NI Package Manager. # logging # check if Utility-Functions.ps1 is present -if (Test-Path "./$ENV:GITPYUPUTILSNAME") { - . "./$ENV:GITPYUPUTILSNAME" +if (Test-Path "./Utility-Functions.ps1") { + . "./Utility-Functions.ps1" Start-Logging } function Write-LogOrHost { diff --git a/gitpyup/Setup-Python.ps1 b/gitpyup/Setup-Python.ps1 index fda66f9..887ab91 100644 --- a/gitpyup/Setup-Python.ps1 +++ b/gitpyup/Setup-Python.ps1 @@ -4,8 +4,8 @@ This script installs Miniforge3 for the 3M corporate environment. It can be run as part of gitpyup for now. #> -# check if Utility-Functions.ps1 is present -. "./$ENV:GITPYUPUTILSNAME" +# run Utility-Functions.ps1 to get the utility functions +. "./Utility-Functions.ps1" Start-Logging Write-Log "Setup-Python v1" @@ -68,7 +68,7 @@ $MiniforgeInstall = { [hashtable]$Conda ) - . "./$ENV:GITPYUPUTILSNAME" + . "./Utility-Functions.ps1" Start-Logging # remove Miniforge3 folder if it exists @@ -118,9 +118,12 @@ $EnvSetupScript = { ) # logging - . "./$ENV:GITPYUPUTILSNAME" + . "./Utility-Functions.ps1" Start-Logging + # this prevents a halts due to an interactive conda message about reporting errors + conda config --set report_errors false + # this sections is needed if the device is subject to SSL inspection # currently Minforge/conda does not have a way to use the system certs # The bundle URL is set by an environment variable diff --git a/gitpyup/run-elevated-first.bat b/gitpyup/run-elevated-first.bat index f3890e5..a594359 100644 --- a/gitpyup/run-elevated-first.bat +++ b/gitpyup/run-elevated-first.bat @@ -2,10 +2,12 @@ echo run-elevated-v1 +pushd %~dp0 + if exist Deploy-gitpyup.ps1 goto check_Permissions :result_False - echo Ensure run-elevated-once.bat, Deploy-gitpyup.ps1 and your yaml file are extracted (may have downloaded .zip) and in the same directory. + echo Please try again!: Ensure run-elevated-first.bat and Deploy-gitpyup.ps1 are extracted (not in a zip file) and in the same directory. goto Done :check_Permissions @@ -16,7 +18,7 @@ if exist Deploy-gitpyup.ps1 goto check_Permissions echo Success: Administrative permissions confirmed. goto set_Policies_Unblock ) else ( - echo Failure: Current permissions inadequate, right click and select 'Run with Elevated Privileges' + echo Please try again!: Current permissions inadequate, right click and select 'Run with Elevated Privileges' or 'Run as Administrator'. goto Done ) @@ -28,4 +30,5 @@ if exist Deploy-gitpyup.ps1 goto check_Permissions echo Next step: right click Deploy-gitpyup.ps1 and select 'Run with PowerShell' :Done - pause \ No newline at end of file + pause + popd \ No newline at end of file diff --git a/tests/Test-Setup-Application.ps1 b/tests/Test-Setup-Application.ps1 new file mode 100644 index 0000000..48353c2 --- /dev/null +++ b/tests/Test-Setup-Application.ps1 @@ -0,0 +1,53 @@ +<# +Copyright (c) 2025 3M Company +This script tests the Setup-Application.ps1 script. +!!! need to manually run Deploy-gitpyup once to generate Utility-Functions.ps1 +#> + +# change path to gitpyup +Set-Location "$PSScriptRoot\..\gitpyup" + +. "./Utility-Functions.ps1" +Start-Logging + +$install = @{ + 'type' = "SingleUser" +} + +# set the application path to the tests directory +$appPath = $PSScriptRoot + +$application = @{ + 'name' = "gitpyup-test" + 'path' = $appPath + 'environment_file' = "gitpyup-test-env.yml" +} + +$name = $application.name + +$pinfo = New-Object System.Diagnostics.ProcessStartInfo +$pinfo.FileName = "powershell" +$pinfo.RedirectStandardError = $true +$pinfo.RedirectStandardOutput = $false +$pinfo.UseShellExecute = $false +$pinfo.CreateNoWindow = $false # doesn't seem to open a window but when false does output to console +$pinfo.WorkingDirectory = (Get-Location).Path +$pinfo.Arguments = "-Command & './Setup-Application.ps1' " + + "-Name $($application.name) " + + "-Path $($application.path) " + + "-EnvironmentFile $($application.environment_file) " + + "-InstallType $($install.type)" +$p = New-Object System.Diagnostics.Process +$p.StartInfo = $pinfo +$p.Start() | Out-Null +$p.WaitForExit() +if ($p.ExitCode -ne 0) { + Write-Log "Python environment setup failed for $name, Run $gpun-update shortcut to try again!" -Level 'ERROR' + Write-Log "exit code: $($p.ExitCode)" -Level 'ERROR' + $stderr = $p.StandardError.ReadToEnd() + if ($stderr) { + Write-Log "stderr: $stderr" -Level 'ERROR' + } +} else { + Write-Log "Python environment setup complete for $name." +} diff --git a/tests/gitpyup-test-env.yml b/tests/gitpyup-test-env.yml new file mode 100644 index 0000000..e8499d3 --- /dev/null +++ b/tests/gitpyup-test-env.yml @@ -0,0 +1,9 @@ +name: gitpyup-test +channels: + - conda-forge +dependencies: + - pip + - python=3.13 + - pip-system-certs + - pip: + - psutil \ No newline at end of file