smalltalk.ps1
branchjv
changeset 1514 4bdcdc52e55a
child 1515 919fad4de40f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smalltalk.ps1	Wed Jul 12 10:25:43 2017 +0200
@@ -0,0 +1,324 @@
+# This file inherits the licencing from the batch file. (MIT)
+# $executable        ... stx.com or .exe
+# $log_file          ... log file name with path
+# $log_file_encoding ... user defined encoding
+# $append_to_log     ... should the log file be appended? (TRUE/FALSE)
+# $cmd_close         ... sends either cmd /u /c (close cmd) or /u /k (cmd remains open)
+# $PowerShellVersion ... detected powershell version
+# $cmd_in_powershell ... should cmd.exe be used for stdout redirection? (TRUE/FALSE)
+param($executable, $log_file, $log_file_encoding, $append_to_log, $cmd_close, $PowerShellVersion, $cmd_in_powershell, $stx_manual_switch_detected);
+
+
+# ===========================================================================
+# Reading directly from environment - due to the issues with passing quotes =
+# ===========================================================================
+# StX switches which are build during batch file execution $env:stx_switch;
+$stx_switch = [environment]::GetEnvironmentVariable("stx_switch");
+# PowerShell version detected during batch file execution  $env:powershell_version_all_functionality;
+$stx_powershell_version = [environment]::GetEnvironmentVariable("powershell_version_all_functionality");
+# getting line width for the log file
+$log_file_width = [environment]::GetEnvironmentVariable("stx.__numeric.log_file_width");
+
+
+# =======================================================
+# Adjust all variables to PowerShell style $true/$false =
+# =======================================================
+
+If ([environment]::GetEnvironmentVariable("stx.__binary.colored_stdout") -eq 'TRUE') {
+    $use_color = $true;
+} Else {
+    $use_color = $false;
+}
+
+If ($cmd_in_powershell -eq 'TRUE') {
+    $cmd_in_powershell = $true;
+} Else {
+    $cmd_in_powershell = $false;
+}
+
+If ($append_to_log -eq 'TRUE') {
+    $append_to_log = $true;
+} Else {
+    $append_to_log = $false;
+}
+
+If ($stx_manual_switch_detected -eq 'TRUE') {
+    $stx_manual_switch_detected = $true;
+} Else {
+    $stx_manual_switch_detected = $false;
+}
+
+If ($use_color) {
+    # fastest way to init empty Hastable
+    $saved_color = [System.Collections.Hashtable]@{};
+    # save colors for later restore
+    $window_private_data = (Get-Host).PrivateData;
+    $saved_color.Add('VerboseBackgroundColor', "$window_private_data.VerboseBackgroundColor") | Out-null; # Out-null for supressing the natural output
+    $saved_color.Add('VerboseForegroundColor', "$window_private_data.VerboseForegroundColor") | Out-null;
+    $saved_color.Add('WarningBackgroundColor', "$window_private_data.WarningBackgroundColor") | Out-null;
+    $saved_color.Add('WarningForegroundColor', "$window_private_data.WarningForegroundColor") | Out-null;
+    $saved_color.Add('ErrorBackgroundColor', "$window_private_data.ErrorBackgroundColor") | Out-null;
+    $saved_color.Add('ErrorForegroundColor', "$window_private_data.ErrorForegroundColor") | Out-null;
+    #setting the user specified colors
+    $window_private_data.VerboseBackgroundColor = [environment]::GetEnvironmentVariable("stx.stdout_VerboseBackgroundColor");
+    $window_private_data.VerboseForegroundColor = [environment]::GetEnvironmentVariable("stx.stdout_VerboseForegroundColor");
+    $window_private_data.WarningBackgroundColor = [environment]::GetEnvironmentVariable("stx.stdout_WarningBackgroundColor");
+    $window_private_data.WarningForegroundColor = [environment]::GetEnvironmentVariable("stx.stdout_WarningForegroundColor");
+    $window_private_data.ErrorBackgroundColor = [environment]::GetEnvironmentVariable("stx.stdout_ErrorBackgroundColor");
+    $window_private_data.ErrorForegroundColor = [environment]::GetEnvironmentVariable("stx.stdout_ErrorForegroundColor");
+} ElseIf ($cmd_in_powershell) {
+    $window_private_data = (Get-Host).PrivateData;
+    $window_private_data.VerboseBackgroundColor = 'Black';
+    $window_private_data.VerboseForegroundColor = 'Gray';
+}
+
+
+# ===========
+# Functions =
+# ===========
+
+# Function for correct $LASTEXITCODE to ERRORLEVEL passing
+function ExitWithCode {
+    param (
+        $exitcode
+    )
+    $host.SetShouldExit($exitcode);
+    EXIT;
+} # end ExitWithCode
+
+# Print User message using String Array $message
+function PrintMessage {
+    param(
+        [Parameter( `
+            Mandatory=$True, `
+            Valuefrompipeline = $true)]
+        [String]$message
+    )
+    begin {}
+    process {
+        foreach ($Message in $Message) {
+            # Write-Host Considered Harmful - see http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/
+            # first way how to correctly write it
+            #Write-host $message;
+            # highlights warning and error messages from StX VM!
+            If ($message -match '\[ERROR\]') {
+                $host.ui.WriteErrorLine("$message");
+            } ElseIf ($message -match '\[WARN\]') {
+                Write-Warning $message;
+            } Else {
+                Write-Verbose -Message $message -Verbose;
+            } 
+        }
+    }
+    end {}
+} # end PrintMessage
+
+
+# To correctly simultinously write to stdout and log file when using out-file!
+# Colors the output based on string match
+function Tee-Host {
+    Param (
+        [Parameter(Mandatory=$true,
+        ValueFromPipeline=$true,
+        Position=0)]
+        $message
+    )
+    begin {}
+    Process {
+        # first way how to correctly write it
+        # -EV is short (an alias) for -ErrorVariable
+        If ($message -match '\[error\]') {
+            # this is printing error compatible with all PS versions
+            $host.ui.WriteErrorLine("$message");
+        } ElseIf ($message -match '\[warning\]') {
+            Write-Warning "$message";
+        } Else {
+            Write-Verbose -Message "$message" -Verbose;
+        }
+        # second correct way how to write it
+        #$VerbosePreference = "Continue"
+        #Write-Verbose $input_object; 
+        return $message
+    }
+    end {}
+} # end Tee-Host
+
+function ExecuteCommand {
+    param(
+       $execute_command
+    )
+    try {
+       Invoke-Expression -Command:$execute_command
+       If ($lastexitcode -ne 0) {
+           $result = $result -join "`n";
+           throw "$result `n";
+       }
+    }
+    catch {
+        $window_private_data = (Get-Host).PrivateData;
+        # saving the original colors
+        $saved_background_color = $window_private_data.ErrorBackgroundColor
+        $saved_foreground_color = $window_private_data.ErrorForegroundColor
+        # setting the new colors
+        $window_private_data.ErrorBackgroundColor = 'White';
+        $window_private_data.ErrorForegroundColor = 'Red';
+
+        $host.ui.WriteErrorLine("[ERROR] happned in PowerShell (can be also stx.com) - See log file: $log_file.");
+        Write-Error "`n`n[ERROR] Error from PowerShell:`n`n $_" 2>> $log_file;
+
+        $window_private_data.ErrorBackgroundColor = $saved_background_color;
+        $window_private_data.ErrorForegroundColor = $saved_foreground_color;
+    }
+} # end ExecuteCommand
+
+
+# =============================
+# check if log file is locked =
+# =============================
+function Test-FileLock {
+    param (
+      [parameter(Mandatory=$true)][string]$path
+    )
+    $log_file = New-Object System.IO.FileInfo $path
+    If ((Test-Path -Path $path) -eq $false) {
+        return $false
+    }
+
+    try {
+      $log_file_stream = $log_file.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
+      If ($log_file_stream) {
+          $log_file_stream.Close()
+      }
+      $false
+    } catch {
+      # file is locked by a process.
+      return $true
+    }
+}
+
+
+# ========================================================================
+# Check if user did not start the PowerShell file directly - exit if yes =
+# ========================================================================
+If ([string]::IsNullOrEmpty($executable)) {
+    "`n", '[ERROR] You can not run this powershell script directly!', 'Execute batch file (.bat) instead.' | PrintMessage;
+    EXIT 1;
+}
+
+
+# ====================================
+# Checking the state of the log file =
+# ====================================
+# Must be done only once in the file in case 
+# the file is unlocked before the second instance is closed
+$is_logfile_locked = Test-FileLock($log_file)
+
+# ================
+# Stdout logging =
+# ================
+If ($is_logfile_locked){
+    "`n", "[WARN] Log file $log_file in use.`n`n  !!NO LOGGING will be available for this Smalltalk/X instance!!" | PrintMessage;
+    '[INFO] Press any key to continue ...' | PrintMessage;
+    # waits for pressing any key
+    $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-null;
+    $logging_function = "Tee-Host | Out-null";
+} Else {
+    If ($append_to_log) {
+        $logging_function = "Tee-Host | Out-File -Append -Encoding $log_file_encoding -FilePath $log_file -Width $log_file_width";
+    } Else {
+        $logging_function = "Tee-Host | Out-File -Encoding $log_file_encoding -FilePath $log_file -Width $log_file_width";
+    }
+}
+
+
+# ===========
+# Execution =
+# ===========
+# Decide which stdout use - either powershell.exe or cmd.exe
+If ($PowerShellVersion -ge $stx_powershell_version) {
+    # stdout output via powershell.exe
+    If (!$cmd_in_powershell) {
+        # --% was introduced in PowerShell 3.0, forces PowerShell to ignore all code afterwards
+        # redirection from 9 - combined (all output combined into a single - easy to redirect stream) from Powershell
+        # if manual switch detected force powershell to ignore all code afterwards
+        If ($stx_manual_switch_detected) {
+            $stx_switch = "--% $stx_switch";
+        }
+        $command = @"
+$executable $stx_switch 2>&1 | $logging_function;
+"@
+        # Due to the PowerShell bug produces FullyQualifiedErrorId : NativeCommandError in the log file -> you can ignore it.
+        # actual execution
+        ExecuteCommand -execute_command $command;
+    # stdout output via cmd.exe
+    } Else {
+        # check if manual switch detected
+        If ($stx_manual_switch_detected) {
+            # if manual switch detected force powershell to ignore all code afterwards
+            $stx_switch = "--% $stx_switch";
+            $command = @"
+cmd.exe $cmd_close $executable $stx_switch '2^>^&1' ^| $logging_function
+"@
+        } Else {
+            # must replace double quotes in order for the cmd.exe to work correctly - cmd.exe requirement
+            $stx_switch = $stx_switch -replace '"','^"';
+            $command = @"
+cmd.exe $cmd_close $executable $stx_switch '2>&1' | $logging_function
+"@
+        }
+        
+        # Due to the PowerShell bug may produce an error: "FullyQualifiedErrorId : NativeCommandError" in the log file -> you can ignore it.
+        # actual execution
+        Write-verbose -message $command -verbose;
+        ExecuteCommand -execute_command $command;
+    } # end Else
+} Else { # legacy powershell - no manual switches available!
+    # stdout output via powershell.exe
+    If (!$cmd_in_powershell) {
+        $command = @"
+$executable $stx_switch 2>&1 | $logging_function
+"@
+        # Due to the PowerShell bug produces FullyQualifiedErrorId : NativeCommandError in the log file -> you can ignore it.
+        # actual execution
+        ExecuteCommand -execute_command $command;
+    # stdout output via cmd.exe
+    } Else {
+        # must replace double quotes in order for the cmd.exe to work correctly??
+        $stx_switch = $stx_switch -replace '"','^"';
+        $command = @"
+cmd.exe $cmd_close $executable $stx_switch '2>&1' | $logging_function
+"@
+        # Due to the PowerShell bug produces FullyQualifiedErrorId : NativeCommandError in the log file -> you can ignore it.
+        # actual execution
+        ExecuteCommand -execute_command $command;
+    }
+} # end if
+
+
+# =========================================
+# Add Separator when adding into the file =
+# =========================================
+If (!$is_logfile_locked){
+    If ($append_to_log) {
+        Write-Output "`r`n=================================================================================================`r`n" >> $log_file;
+    }
+}
+
+# ===============================
+# Restore original Shell colors =
+# ===============================
+#TODO:
+If ($use_color) {
+    $window_private_data = (Get-Host).PrivateData;
+    ForEach($item in $saved_color.GetEnumerator()) {
+        Set-Variable -name "$window_private_data.$($item.Key)" -Value "$($item.Value)";
+    }
+}
+
+
+# ======
+# Exit =
+# ======
+# Sending exit code to calling batch file
+"`n", "[INFO] Exiting from PowerShell with code $LASTEXITCODE" | PrintMessage;
+ExitWithCode -exitcode $LASTEXITCODE;
\ No newline at end of file