Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a0c6edc
Populate the $global:LASTEXITCODE with exit code of compiler
leojonathanoh Apr 27, 2020
86982b1
Fix integration tests to use $global:LASTEXITCODE
leojonathanoh Apr 27, 2020
4af9c66
Add integration tests: bad cases
leojonathanoh Apr 27, 2020
6ef6ed0
Fix integrated test bad plugin scenario titles and parameters
joeltimothyoh Aug 3, 2020
e1fe437
Fix contamination in stdout stream from creation of temporary directo…
joeltimothyoh Aug 3, 2020
3a06f36
Revise to return exit code 1 on plugin compilation failures when sour…
joeltimothyoh Aug 3, 2020
1c50592
Revise integration test scenarios for amxmodx to expect exit code 1 i…
joeltimothyoh Aug 3, 2020
c1831d2
Fix integrated test 'Compile plugin via wrapper, bad plugin' scenario
joeltimothyoh Aug 3, 2020
ff0ac21
Revise to return an exit code on plugin compilation errors whether am…
joeltimothyoh Aug 3, 2020
08f2914
Revise to return exit code 1 on plugin compilation failures when non-…
joeltimothyoh Aug 3, 2020
3c0227a
Fix displaying of compile and compiler wrapper stdout for when source…
joeltimothyoh Aug 3, 2020
c7f6bf5
Fix sourcemod plugin compilation error regex pattern
joeltimothyoh Aug 3, 2020
4c9e880
Tweak debug line for expected exit code and exit code
joeltimothyoh Aug 3, 2020
0b76d30
Rename expected exit code variable for improved clarity
joeltimothyoh Aug 3, 2020
b77e9cf
Refactor: Improve code flow in generation of command line arguments a…
leojonathanoh Aug 10, 2020
5f4dceb
Refactor: Match compiler-emitted stdout against error regex to detect…
leojonathanoh Aug 11, 2020
baf0dce
Refactor: Cleanup stdinFile immediately after compilation
leojonathanoh Aug 11, 2020
d9751aa
Refactor: Enhance regex to match compiler-emitted stdout against to d…
leojonathanoh Aug 11, 2020
eff914f
Refactor: Enhance integration test descriptions for good plugins
leojonathanoh Aug 11, 2020
fb8517a
Refactor: Print stderr of compilation after stdout of compilation
leojonathanoh Aug 31, 2020
d3f8694
Fix: Add try catch finally around compilation environment preparation…
leojonathanoh Aug 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 62 additions & 29 deletions src/Compile-SourceScript/Public/Compile-SourceScript.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ function Compile-SourceScript {

# Initialize variables
$MOD = @{
# The sourcemod compiler returns exits code correctly.
# The sourcemod compiler wrapper returns the exit code of the lastmost executed shell statement. This is particularly bad when the compiler exits with '0' from a successful finalmost shell statement, even when one or more prior shell statements exited with non-zero exit codes.
# Hence, knowing that exit codes are not a reliable way to determine whether one or more compilation statements failed, we are going to use a regex on the stdout as a more reliable way to detect compilation errors, regardless of whether compilation was performed via the compiler binary or via the compiler wrapper.
sourcemod = @{
script_ext = '.sp'
plugin_ext = '.smx'
Expand All @@ -70,13 +73,18 @@ function Compile-SourceScript {
windows = @{
wrapper = 'compile.exe'
bin = 'spcomp.exe'
error_regex = '^Compilation aborted|^\d+\s+Errors?|.*\.sp\(\d+\)\s*:\s*(?:fatal)? error (\d+)'
}
others = @{
wrapper = 'compile.sh'
bin = 'spcomp'
error_regex = '^Compilation aborted|^\d+\s+Errors?|.*\.sp\(\d+\)\s*:\s*(?:fatal)? error (\d+)'
}
}
}
# The amxmodx compiler binary always exits with exit code 0.
# The amxmodx compiler wrapper always exits with exit code 0.
# Hence, knowing that exit codes are not a reliable way to determine whether one or more compilation statements failed, we are going to use a regex on the stdout as a more reliable way to detect compilation errors, regardless of whether compilation was performed via the compiler binary or via the compiler wrapper.
amxmodx = @{
script_ext = '.sma'
plugin_ext = '.amxx'
Expand All @@ -86,21 +94,18 @@ function Compile-SourceScript {
windows = @{
wrapper = 'compile.exe'
bin = 'amxxpc.exe'
error_regex = '^\d+\s+Errors?|compile failed|^.*\.sma\(\d+\)\s*:\s*error (\d+)'
}
others = @{
wrapper = 'compile.sh'
bin = 'amxxpc'
error_regex = '^\d+\s+Errors?|compile failed|^.*\.sma\(\d+\)\s*:\s*error (\d+)'
}
}
}
}
$COMPILER_NAME = if ($env:OS -eq 'Windows_NT') {
if ($PSBoundParameters['SkipWrapper']) { $MOD[$MOD_NAME]['compiler']['windows']['bin'] }
else { $MOD[$MOD_NAME]['compiler']['windows']['wrapper'] }
}else {
if ($PSBoundParameters['SkipWrapper']) { $MOD[$MOD_NAME]['compiler']['others']['bin'] }
else { $MOD[$MOD_NAME]['compiler']['others']['wrapper'] }
}
$OS = if ($env:OS -eq 'Windows_NT') { 'windows' } else { 'others' }
$COMPILER_NAME = if ($PSBoundParameters['SkipWrapper']) { $MOD[$MOD_NAME]['compiler'][$OS]['bin'] } else { $MOD[$MOD_NAME]['compiler'][$OS]['wrapper'] }
$SCRIPTING_DIR = $sourceFile.DirectoryName
$COMPILED_DIR = Join-Path $SCRIPTING_DIR $MOD[$MOD_NAME]['compiled_dir_name']
$COMPILER_PATH = Join-Path $SCRIPTING_DIR $COMPILER_NAME
Expand All @@ -123,33 +128,65 @@ function Compile-SourceScript {
# Get all items in compiled directory before compilation by hash
$compiledDirItemsPre = Get-ChildItem -Path $COMPILED_DIR -File -Recurse -Force | ? { $_.Extension -eq $MOD[$MOD_NAME]['plugin_ext'] } | Select-Object *, @{name='md5'; expression={(Get-FileHash -Path $_.Fullname -Algorithm MD5).Hash}}

# Prepare for compilation
"Compiling..." | Write-Host -ForegroundColor Cyan
# Generate command line arguments
$epoch = [Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))
$stdInFile = New-Item -Path (Join-Path $SCRIPTING_DIR ".$epoch") -ItemType File -Force
'1' | Out-File -FilePath $stdInFile.FullName -Force -Encoding utf8
$stdInFile = Join-Path $SCRIPTING_DIR ".$epoch"
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) (New-Guid).Guid
$stdoutFile = Join-Path $tempDir 'stdout'
$stderrFile = Join-Path $tempDir 'stderr'
$processArgs = @{
FilePath = $compiler.FullName
ArgumentList = @(
if ($PSBoundParameters['SkipWrapper']) {
$sourceFile.Name
"-o$($MOD[$MOD_NAME]['compiled_dir_name'])/$($sourceFile.Basename)$($MOD[$MOD_NAME]['plugin_ext'])"
}else {
$sourceFile.Name
}
)
WorkingDirectory = $SCRIPTING_DIR
RedirectStandardInput = $stdInFile.FullName
RedirectStandardInput = $stdInFile
RedirectStandardOutput = $stdoutFile
RedirectStandardError = $stderrFile
Wait = $true
NoNewWindow = $true
PassThru = $true
}
if ($PSBoundParameters['SkipWrapper']) {
$processArgs['ArgumentList'] = @(
$sourceFile.Name
"-o$($MOD[$MOD_NAME]['compiled_dir_name'])/$($sourceFile.Basename)$($MOD[$MOD_NAME]['plugin_ext'])"
)
}else {
$processArgs['ArgumentList'] = @(
$sourceFile.Name
)

try {
# Prepare compilation environment
if ($item = New-Item -Path $stdInFile -ItemType File -Force) {
# This dummy input bypasses the 'Press any key to continue' prompt of the compiler
'1' | Out-File -FilePath $item.FullName -Force -Encoding utf8
}
New-Item $tempDir -ItemType Directory -Force > $null
New-Item -Path $COMPILED_DIR -ItemType Directory -Force | Out-Null

# Begin compilation
"Compiling..." | Write-Host -ForegroundColor Cyan
if ($PSBoundParameters['SkipWrapper']) { "Compiling $($sourceFile.Name)..." | Write-Host -ForegroundColor Yellow }

Comment thread
leojonathanoh marked this conversation as resolved.
# Compile
$global:LASTEXITCODE = 0
$p = Start-Process @processArgs
$stdout = Get-Content $stdoutFile
$stdout | Write-Host
$stderr = Get-Content $stderrFile
Comment thread
leojonathanoh marked this conversation as resolved.
$stderr | Write-Host
foreach ($line in $stdout) {
if ($line -match $MOD[$MOD_NAME]['compiler'][$OS]['error_regex']) {
$global:LASTEXITCODE = 1
break
}
}
}catch {
throw
}finally {
# Cleanup
Remove-Item $stdInFile -Force
Remove-Item $tempDir -Recurse -Force
}
New-Item -Path $COMPILED_DIR -ItemType Directory -Force | Out-Null

# Begin compilation
if ($PSBoundParameters['SkipWrapper']) { "Compiling $($sourceFile.Name)..." | Write-Host -ForegroundColor Yellow }
Start-Process @processArgs
if ($PSBoundParameters['SkipWrapper']) { "End of compilation." | Write-Host -ForegroundColor Yellow }

# Get all items in compiled directory after compilation by hash
Expand Down Expand Up @@ -231,10 +268,6 @@ function Compile-SourceScript {
}catch {
Write-Error -Exception $_.Exception -Message $_.Exception.Message -Category $_.CategoryInfo.Category -TargetObject $_.TargetObject
}finally {
# Cleanup
if ($stdInFile) {
Remove-Item -Path $stdInFile -Force
}
"End of Compile-SourceScript." | Write-Host -ForegroundColor Cyan
}
}
Expand Down
6 changes: 6 additions & 0 deletions test/mod/amxmodx/addons/amxmodx/scripting/plugin1_bad.sma
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <amxmodx>

public plugin_init() {
log_message("Hello from amxmodx.");
}
i am junk
6 changes: 6 additions & 0 deletions test/mod/amxmodx/addons/amxmodx/scripting/plugin2_bad.sma
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <amxmodx>

public plugin_init() {
log_message("Hello from amxmodx.");
}
i am junk
6 changes: 6 additions & 0 deletions test/mod/sourcemod/addons/sourcemod/scripting/plugin1_bad.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <sourcemod>

public void OnPluginStart() {
LogMessage("Hello from sourcemod.");
}
i am junk
6 changes: 6 additions & 0 deletions test/mod/sourcemod/addons/sourcemod/scripting/plugin2_bad.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <sourcemod>

public void OnPluginStart() {
LogMessage("Hello from sourcemod.");
}
i am junk
51 changes: 47 additions & 4 deletions test/scripts/integration/Run-IntegrationTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ $functionTestScriptBlock = {
for ($i=0; $i -le $iterations-1; $i++) {
"Iteration: $($i+1)" | Write-Host
& $script:cmd @cmdArgs
if ($global:LASTEXITCODE -ne $expectedExitCode) {
throw "Expected exit code $expectedExitCode but got exit code $global:LASTEXITCODE"
}
"Expected exit code: $expectedExitCode, Exit code: $global:LASTEXITCODE" | Write-Host -ForegroundColor Yellow
}
}catch {
$_ | Write-Error
Expand All @@ -28,30 +32,49 @@ $cmd = "Compile-SourceScript"
# SourceMod #
#############

"`n[sourcemod] Compile plugin via wrapper" | Write-Host
"`n[sourcemod] Compile plugin via wrapper, good plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\sourcemod\addons\sourcemod\scripting\plugin1.sp"
Force = $true
}
$iterations = 2
$expectedExitCode = 0
& $functionTestScriptBlock

"`n[sourcemod] Compile plugin via wrapper, bad plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\sourcemod\addons\sourcemod\scripting\plugin1_bad.sp"
Force = $true
}
$iterations = 2
$expectedExitCode = 1
& $functionTestScriptBlock
Comment thread
leojonathanoh marked this conversation as resolved.

"`n[sourcemod] Compile plugin via compiler" | Write-Host
"`n[sourcemod] Compile plugin via compiler, good plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\sourcemod\addons\sourcemod\scripting\plugin2.sp"
Force = $true
SkipWrapper = $true
}
$iterations = 2
$expectedExitCode = 0
& $functionTestScriptBlock

"`n[sourcemod] Compile plugin via compiler, bad plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\sourcemod\addons\sourcemod\scripting\plugin2_bad.sp"
Force = $true
SkipWrapper = $true
}
$iterations = 2
$expectedExitCode = 1
& $functionTestScriptBlock

#############
# AMX Mod X #
#############

"`n[amxmodx] Compile plugin via wrapper" | Write-Host
"`n[amxmodx] Compile plugin via wrapper, good plugin" | Write-Host
# The following test should be run only for Windows, reason being that the non-Windows version:
# - Does not take in arguments, instead compiles all plugins within the scripting directory
# - Displays all the output using 'less' at the end of the compilation, thus is limited to interactive use
Expand All @@ -60,19 +83,39 @@ if ($env:OS -eq 'Windows_NT') {
File = "$PSScriptRoot\..\..\mod\amxmodx\addons\amxmodx\scripting\plugin1.sma"
Force = $true
}
$expectedExitCode = 0
$iterations = 2
& $functionTestScriptBlock

"`n[amxmodx] Compile plugin via wrapper, bad plugin" | Write-Host
Comment thread
leojonathanoh marked this conversation as resolved.
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\amxmodx\addons\amxmodx\scripting\plugin1_bad.sma"
Force = $true
}
$expectedExitCode = 1
$iterations = 2
& $functionTestScriptBlock
}else { "Skipping: Test only applicable to Windows." | Write-Host }

"`n[amxmodx] Compile plugin via compiler" | Write-Host
"`n[amxmodx] Compile plugin via compiler, good plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\amxmodx\addons\amxmodx\scripting\plugin2.sma"
Force = $true
SkipWrapper = $true
}
$expectedExitCode = 0
$iterations = 2
& $functionTestScriptBlock

"`n[amxmodx] Compile plugin via compiler, bad plugin" | Write-Host
$cmdArgs = @{
File = "$PSScriptRoot\..\..\mod\amxmodx\addons\amxmodx\scripting\plugin2_bad.sma"
Force = $true
SkipWrapper = $true
}
$expectedExitCode = 1
$iterations = 2
& $functionTestScriptBlock

###########
# Results #
Expand Down