diff --git a/.github/workflows/make.pas b/.github/workflows/make.pas new file mode 100644 index 00000000..843b63e9 --- /dev/null +++ b/.github/workflows/make.pas @@ -0,0 +1,237 @@ +program Make; +{$mode objfpc}{$H+} + +uses + Classes, + SysUtils, + StrUtils, + FileUtil, + Zipper, + fphttpclient, + RegExpr, + openssl, + opensslsockets, + Process; + +const + Target: string = 'lazpaint'; + Dependencies: array of string = (); + +type + TLog = (audit, info, error); + Output = record + Success: boolean; + Output: string; + end; + + procedure OutLog(Knd: TLog; Msg: string); + begin + case Knd of + error: Writeln(stderr, #27'[31m', Msg, #27'[0m'); + info: Writeln(stderr, #27'[32m', Msg, #27'[0m'); + audit: Writeln(stderr, #27'[33m', Msg, #27'[0m'); + end; + end; + + function CheckModules: Output; + begin + if FileExists('.gitmodules') then + if RunCommand('git', ['submodule', 'update', '--init', '--recursive', + '--force', '--remote'], Result.Output) then + OutLog(info, Result.Output); + end; + + function AddPackage(Path: string): Output; + begin + with TRegExpr.Create do + begin + Expression := + {$IFDEF MSWINDOWS} + '(cocoa|x11|_template)' + {$ELSE} + '(cocoa|gdi|_template)' + {$ENDIF} + ; + if not Exec(Path) and RunCommand('lazbuild', ['--add-package-link', Path], + Result.Output) then + OutLog(audit, 'added ' + Path); + Free; + end; + end; + + function BuildProject(Path: string): Output; + var + Line: string; + begin + OutLog(audit, 'build from ' + Path); + try + Result.Success := RunCommand('lazbuild', ['--build-all', '--recursive', + '--no-write-project', Path], Result.Output); + if Result.Success then + for Line in SplitString(Result.Output, LineEnding) do + begin + if ContainsStr(Line, 'Linking') then + begin + Result.Output := SplitString(Line, ' ')[2]; + OutLog(info, ' to ' + Result.Output); + break; + end; + end + else + begin + ExitCode += 1; + for Line in SplitString(Result.Output, LineEnding) do + with TRegExpr.Create do + begin + Expression := '(Fatal|Error):'; + if Exec(Line) then + OutLog(error, #10 + Line); + Free; + end; + end; + except + on E: Exception do + OutLog(error, E.ClassName + #13#10 + E.Message); + end; + end; + + function RunTest(Path: string): Output; + var + Temp: string; + begin + Result := BuildProject(Path); + Temp:= Result.Output; + if Result.Success then + try + if not RunCommand(Temp, ['--all', '--format=plain', '--progress'], Result.Output) then + begin + ExitCode += 1; + OutLog(error, Result.Output); + end; + except + on E: Exception do + OutLog(error, E.ClassName + #13#10 + E.Message); + end; + end; + + function InstallOPM(Each: string): string; + var + OutFile, Uri: string; + Zip: TStream; + begin + Result := + {$IFDEF MSWINDOWS} + GetEnvironmentVariable('APPDATA') + '\.lazarus\onlinepackagemanager\packages\' + {$ELSE} + GetEnvironmentVariable('HOME') + '/.lazarus/onlinepackagemanager/packages/' + {$ENDIF} + + Each; + OutFile := GetTempFileName; + Uri := 'https://packages.lazarus-ide.org/' + Each + '.zip'; + if not DirectoryExists(Result) then + begin + Zip := TFileStream.Create(OutFile, fmCreate or fmOpenWrite); + with TFPHttpClient.Create(nil) do + begin + try + AddHeader('User-Agent', 'Mozilla/5.0 (compatible; fpweb)'); + AllowRedirect := True; + Get(Uri, Zip); + OutLog(audit, 'Download from ' + Uri + ' to ' + OutFile); + finally + Free; + end; + end; + Zip.Free; + CreateDir(Result); + with TUnZipper.Create do + begin + try + FileName := OutFile; + OutputPath := Result; + Examine; + UnZipAllFiles; + OutLog(audit, 'Unzip from ' + OutFile + ' to ' + Result); + finally + Free; + end; + end; + DeleteFile(OutFile); + end; + end; + + function LintPython(Path: string): Output; + begin + OutLog(audit, 'Linting Python file: ' + Path); + if not RunCommand('python3', ['-m', 'pylint', Path], Result.Output) then + begin + OutLog(error, Result.Output); + //ExitCode += 1; + end + end; + + function LintC(Path: string): Output; + begin + OutLog(audit, 'Linting C file: ' + Path); + if not RunCommand('cppcheck', ['--language=c', '--enable=warning,style', '--template=gcc', Path], Result.Output) then + begin + OutLog(error, Result.Output); + //ExitCode += 1; + end + end; + + function LintShell(Path: string): Output; + begin + OutLog(audit, 'Linting Shell file: ' + Path); + if not RunCommand('shellcheck', ['--external-sources', Path], Result.Output) then + begin + OutLog(error, Result.Output); + //ExitCode += 1; + end + end; + + procedure BuildAll; + var + Each, Item: string; + List: TStringList; + begin + CheckModules; + InitSSLInterface; + for Item in Dependencies do + begin + List := FindAllFiles(InstallOPM(Item), '*.lpk', True); + try + for Each in List do + AddPackage(Each); + finally + List.Free; + end; + end; + List := FindAllFiles(GetCurrentDir, '*.lpk', True); + try + for Each in List do + AddPackage(Each); + finally + List.Free; + end; + List := FindAllFiles(Target, '*.lpi', True); + try + for Each in List do + if not ContainsStr(Each, 'zengl') then + if ContainsStr(ReadFileToString(ReplaceStr(Each, '.lpi', '.lpr')), + 'consoletestrunner') then + RunTest(Each) + else + BuildProject(Each); + finally + List.Free; + end; + if ExitCode <> 0 then + OutLog(error, #10 + 'Errors: ' + IntToStr(ExitCode)) + else + OutLog(info, #10 + 'Errors: ' + IntToStr(ExitCode)); + end; + +begin + BuildAll; +end. diff --git a/.github/workflows/make.ps1 b/.github/workflows/make.ps1 deleted file mode 100644 index 0f8c2d91..00000000 --- a/.github/workflows/make.ps1 +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env pwsh -############################################################################################################## - -Function Show-Usage { - " -Usage: pwsh -File $($PSCommandPath) [OPTIONS] -Options: - build Build program -" | Out-Host -} - -Function Build-Project { - New-Variable -Name VAR -Option Constant -Value @{ - Src = 'lazpaint' - Use = '.' - Pkg = 'use\components.txt' - } - If (! (Test-Path -Path $Var.Src)) { - 'Source do not find!' | Out-Host - Exit 1 - } - If (Test-Path -Path '.gitmodules') { - & git submodule update --init --recursive --force --remote | Out-Host - ".... [[$($LastExitCode)]] git submodule update" | Out-Host - } - @( - @{ - Cmd = 'lazbuild' - Url = 'https://fossies.org/windows/misc/lazarus-3.6-fpc-3.2.2-win64.exe' - Path = "C:\Lazarus" - } - ) | Where-Object { ! (Test-Path -Path $_.Path) } | - ForEach-Object { - $_.Url | Request-File | Install-Program - $Env:PATH+=";$($_.Path)" - (Get-Command $_.Cmd).Source | Out-Host - } - If (Test-Path -Path $VAR.Use) { - If (Test-Path -Path $VAR.Pkg) { - Get-Content -Path $VAR.Pkg | - Where-Object { - ! (Test-Path -Path "$($VAR.Use)\$($_)") && - ! (& lazbuild --verbose-pkgsearch $_ ) && - ! (& lazbuild --add-package $_) - } | ForEach-Object { - Return @{ - Uri = "https://packages.lazarus-ide.org/$($_).zip" - Path = "$($VAR.Use)\$($_)" - OutFile = (New-TemporaryFile).FullName - } - } | ForEach-Object -Parallel { - Invoke-WebRequest -OutFile $_.OutFile -Uri $_.Uri - Expand-Archive -Path $_.OutFile -DestinationPath $_.Path - Remove-Item $_.OutFile - Return ".... download $($_.Uri)" - } | Out-Host - } - (Get-ChildItem -Filter '*.lpk' -Recurse -File –Path $VAR.Use).FullName | - ForEach-Object { - & lazbuild --add-package-link $_ | Out-Null - Return ".... [$($LastExitCode)] add package link $($_)" - } | Out-Host - } - Exit ( - (Get-ChildItem -Filter '*.lpi' -Recurse -File –Path $Var.Src).FullName | - Sort-Object | - ForEach-Object { - $Output = (& lazbuild --build-all --recursive --no-write-project --build-mode='release' $_) - $Result = @(".... [$($LastExitCode)] build project $($_)") - $exitCode = Switch ($LastExitCode) { - 0 { - $Result += $Output | Select-String -Pattern 'Linking' - 0 - } - Default { - $Result += $Output | Select-String -Pattern 'Error:', 'Fatal:' - 1 - } - } - $Result | Out-Host - Return $exitCode - } | Measure-Object -Sum - ).Sum -} - -Function Request-File { - While ($Input.MoveNext()) { - New-Variable -Name VAR -Option Constant -Value @{ - Uri = $Input.Current - OutFile = (Split-Path -Path $Input.Current -Leaf).Split('?')[0] - } - Invoke-WebRequest @VAR - Return $VAR.OutFile - } -} - -Function Install-Program { - While ($Input.MoveNext()) { - Switch ((Split-Path -Path $Input.Current -Leaf).Split('.')[-1]) { - 'msi' { - & msiexec /passive /package $Input.Current | Out-Null - } - Default { - & ".\$($Input.Current)" /SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART | Out-Null - } - } - Remove-Item $Input.Current - } -} - -Function Switch-Action { - $ErrorActionPreference = 'stop' - Set-PSDebug -Strict #-Trace 1 - Invoke-ScriptAnalyzer -EnableExit -Path $PSCommandPath - If ($args.count -gt 0) { - Switch ($args[0]) { - 'build' { - Build-Project - } - Default { - Show-Usage - } - } - } Else { - Show-Usage - } -} - -############################################################################################################## -Switch-Action @args diff --git a/.github/workflows/make.sh b/.github/workflows/make.sh deleted file mode 100644 index f696624e..00000000 --- a/.github/workflows/make.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env bash - -function priv_clippit -( - cat <&2 - fi - declare -i errors=0 - while read -r; do - declare -A TMP=( - [out]=$(mktemp) - ) - if (lazbuild --build-all --recursive --no-write-project --build-mode='release' --widgetset='qt5' "${REPLY}" > "${TMP[out]}"); then - printf '\x1b[32m\t[%s]\t%s\x1b[0m\n' "${?}" "${REPLY}" - grep --color='always' 'Linking' "${TMP[out]}" - else - printf '\x1b[31m\t[%s]\t%s\x1b[0m\n' "${?}" "${REPLY}" - grep --color='always' --extended-regexp '(Error|Fatal):' "${TMP[out]}" - ((errors+=1)) - fi 1>&2 - rm "${TMP[out]}" - done < <(find "${VAR[src]}" -type 'f' -name '*.lpi' | sort) - - # Python linting - find 'resources' -type 'f' -name '*.py' | while read -r file; do - printf '\033[32m\tLinting Python file: %s\033[0m\n' "$file" - if ! python3 -m pylint "$file" 1>&2; then - printf '\033[31m\tError in Python linting: %s\033[0m\n' "$file" - ((errors+=1)) - fi - done - - # C linting - find "${VAR[src]}" -type 'f' -name '*.c' | while read -r file; do - printf '\033[32m\tLinting C file: %s\033[0m\n' "$file" - if ! cppcheck --language=c --enable=warning,style --template=gcc "$file" 1>&2; then - printf '\033[31m\tError in C linting: %s\033[0m\n' "$file" - ((errors+=1)) - fi - done - - # Shell script linting - find "${PWD}" -type 'f' -name '*.sh' | while read -r file; do - printf '\033[32m\tLinting Shell script: %s\033[0m\n' "$file" - if ! shellcheck --external-sources "$file" 1>&2; then - printf '\033[31m\tError in Shell linting: %s\033[0m\n' "$file" - ((errors+=1)) - fi - done - - exit "${errors}" -) - -function priv_main -( - set -uo pipefail - if ((${#})); then - case ${1} in - build) priv_lazbuild ;; - *) priv_clippit ;; - esac - else - priv_clippit - fi -) - -priv_main "${@}" >/dev/null diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml index 006d55cd..04f9bdba 100644 --- a/.github/workflows/make.yml +++ b/.github/workflows/make.yml @@ -34,16 +34,23 @@ jobs: - name: Build on Linux if: runner.os == 'Linux' shell: bash - run: bash .github/workflows/make.sh build + run: | + set -xeuo pipefail + sudo bash -c 'apt-get update; apt-get install -y lazarus cppcheck pylint shellcheck' >/dev/null + instantfpc -Fu/usr/lib/lazarus/*/components/lazutils .github/workflows/make.pas - name: Build on Windows if: runner.os == 'Windows' shell: powershell - run: pwsh -File .github/workflows/make.ps1 build - - - name: Archive - if: runner.os == 'Windows' - uses: actions/upload-artifact@v4 - with: - retention-days: 1 - path: src\bin\*.exe + run: | + New-Variable -Option Constant -Name VAR -Value @{ + Uri = 'https://fossies.org/windows/misc/lazarus-3.6-fpc-3.2.2-win64.exe' + OutFile = (New-TemporaryFile).FullName + '.exe' + } + Invoke-WebRequest @VAR + & $VAR.OutFile.Replace('Temp', 'Temp\.') /SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART | Out-Null + $Env:PATH+=';C:\Lazarus' + $Env:PATH+=';C:\Lazarus\fpc\3.2.2\bin\x86_64-win64' + (Get-Command 'lazbuild').Source | Out-Host + (Get-Command 'instantfpc').Source | Out-Host + instantfpc '-FuC:\Lazarus\components\lazutils' .github/workflows/make.pas diff --git a/.gitmodules b/.gitmodules index fe8b2cba..b0432302 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "use/bgracontrols"] - path = use/bgracontrols - url = git@github.com:bgrabitmap/bgracontrols.git [submodule "use/bgrabitmap"] path = use/bgrabitmap url = git@github.com:bgrabitmap/bgrabitmap.git +[submodule "use/bgracontrols"] + path = use/bgracontrols + url = git@github.com:bgrabitmap/bgracontrols.git