Skip to content

Conversation

@N6REJ
Copy link
Contributor

@N6REJ N6REJ commented Nov 12, 2025

PR Type

Enhancement, Documentation


Description

  • Migrate build system from Apache Ant to pure Gradle

  • Add comprehensive Gradle documentation in .gradle-docs/

  • Implement new Gradle tasks for build, verification, and information

  • Remove legacy Ant build files and configuration


Diagram Walkthrough

flowchart LR
  A["Apache Ant<br/>build.xml"] -->|"Migrate"| B["Pure Gradle<br/>build.gradle"]
  B --> C["Gradle Tasks"]
  C --> D["Build Tasks<br/>release, releaseAll"]
  C --> E["Verification Tasks<br/>verify, validateProperties"]
  C --> F["Information Tasks<br/>info, listVersions"]
  B --> G["Configuration"]
  G --> H["gradle.properties<br/>settings.gradle"]
  B --> I["Documentation"]
  I --> J[".gradle-docs/<br/>6 markdown files"]
  K["Test Script<br/>test-gradle-build.bat"] -->|"Validates"| C
Loading

File Walkthrough

Relevant files
Enhancement
1 files
build.gradle
Main Gradle build script implementation                                   
Configuration changes
2 files
settings.gradle
Gradle project settings configuration                                       
gradle.properties
Gradle daemon and JVM performance settings                             
+19/-0   
Documentation
7 files
README.md
Main Gradle build documentation and quick start                   
+621/-0 
TASKS.md
Complete reference for all Gradle tasks                                   
+537/-0 
CONFIGURATION.md
Configuration guide for build system                                         
+441/-0 
API.md
API reference for build scripts and helpers                           
+830/-0 
MIGRATION.md
Migration guide from Ant to Gradle                                             
+443/-0 
INDEX.md
Documentation index and navigation guide                                 
+390/-0 
README.md
Update with Gradle build system information                           
+57/-2   
Tests
1 files
test-gradle-build.bat
Automated test script for Gradle build tasks                         
+100/-0 
Miscellaneous
3 files
build.xml
Remove legacy Apache Ant build file                                           
+0/-42   
CHANGELOG.md
Remove outdated changelog file                                                     
+0/-13   
module-ghostscript.RELEASE.launch
Remove Eclipse Ant launch configuration                                   
+0/-19   
Formatting
2 files
update_cidfmap.bat
Fix line ending formatting in batch file                                 
+3/-3     
update_cidfmap.bat
Fix line ending formatting in batch file                                 
+3/-3     
Additional files
14 files
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
update_cidfmap.bat [link]   
bearsampp.conf [link]   
bearsampp.conf [link]   

@N6REJ N6REJ added the enhancement ✨ Improve program label Nov 12, 2025
@qodo-code-review
Copy link

qodo-code-review bot commented Nov 12, 2025

PR Compliance Guide 🔍

(Compliance updated until commit 52a0d39)

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: The added batch test script invokes build tasks and reports pass/fail to console without
producing structured audit logs that record user, timestamp, actions, and outcomes for
later analysis.

Referred Code
REM Test 1: Display build info
echo [TEST 1] Testing 'gradle info' task...
echo ------------------------------------------------------------------------
call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle tasks task failed
    exit /b 1
)
echo [PASSED] gradle tasks task
echo.


 ... (clipped 70 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Limited errors: The script checks ERRORLEVEL and exits on failure but provides only generic failure
messages without actionable diagnostics or captured outputs from Gradle for debugging.

Referred Code
echo ------------------------------------------------------------------------
call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle tasks task failed
    exit /b 1
)
echo [PASSED] gradle tasks task
echo.

REM Test 3: List available versions


 ... (clipped 54 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured logs: The script emits unstructured console output and calls Gradle tasks whose outputs may
include environment details without ensuring structured logging or redaction of sensitive
data.

Referred Code
echo ========================================================================
echo   Bearsampp Module Ghostscript - Gradle Build Test
echo ========================================================================
echo.

REM Test 1: Display build info
echo [TEST 1] Testing 'gradle info' task...
echo ------------------------------------------------------------------------
call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (


 ... (clipped 75 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit e961a3b
Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
Missing audit logs: The batch test script runs multiple Gradle tasks and exits on failure without emitting
structured, user/timestamped audit entries for critical actions.

Referred Code
echo [TEST 1] Testing 'gradle info' task...
echo ------------------------------------------------------------------------
call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle tasks task failed
    exit /b 1
)
echo [PASSED] gradle tasks task
echo.



 ... (clipped 54 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Minimal error context: On task failure the script echoes a generic failure message and exits without capturing
stderr, exit codes per step detail, or additional diagnostics to aid debugging.

Referred Code
call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle tasks task failed
    exit /b 1
)
echo [PASSED] gradle tasks task
echo.

REM Test 3: List available versions
echo [TEST 3] Testing 'gradle listVersions' task...


 ... (clipped 50 lines)

Learn more about managing compliance generic rules or creating your own custom rules

@qodo-code-review
Copy link

qodo-code-review bot commented Nov 12, 2025

PR Code Suggestions ✨

Latest suggestions up to 52a0d39

CategorySuggestion                                                                                                                                    Impact
General
Add explicit Gradle install prerequisite link

Add a link to the Gradle installation page in the important note about requiring
a system-installed Gradle.

.gradle-docs/TASKS.md [5]

-> **⚠️ Important**: All commands use **system-installed Gradle** (e.g., `gradle <task>`). Neither Apache Ant nor Gradle Wrapper (gradlew/gradlew.bat) are used in this project.
+> **⚠️ Important**: All commands use **system-installed Gradle** (e.g., `gradle <task>`). Neither Apache Ant nor Gradle Wrapper (gradlew/gradlew.bat) are used in this project. Install Gradle 8.0+: https://gradle.org/install/
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion improves user experience by adding a direct link to install Gradle, which is a hard requirement for this project. This makes the documentation more helpful and can prevent setup issues for new users.

Low
Fix potentially stale doc link

Update the support section to include a direct link to the newly added local
documentation in the .gradle-docs directory, making it the primary reference.

.gradle-docs/README.md [421-425]

 For issues and questions:
 
 - **GitHub Issues**: https://github.com/bearsampp/module-ghostscript/issues
 - **Bearsampp Issues**: https://github.com/bearsampp/bearsampp/issues
-- **Documentation**: https://bearsampp.com/module/ghostscript
+- **Local Documentation (recommended)**: https://github.com/bearsampp/module-ghostscript/tree/main/.gradle-docs
+- **Module Page**: https://bearsampp.com/module/ghostscript
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that the new local documentation should be referenced. Adding a direct link to the .gradle-docs directory improves usability and ensures users can find the most relevant information introduced in this PR.

Low
  • More

Previous suggestions

Suggestions up to commit 44086f2
CategorySuggestion                                                                                                                                    Impact
Possible issue
Resolve Gradle wrapper inconsistency

Resolve the contradiction about the Gradle wrapper by clarifying in the setup
guide that the wrapper should be preferred if present, otherwise a system-wide
Gradle installation is required.

.gradle-docs/GRADLE_SETUP.md [5]

-The Bearsampp Module Ghostscript has been converted to use Gradle build system **without** a Gradle wrapper. This means you need to have Gradle installed on your system.
+The Bearsampp Module Ghostscript uses the Gradle build system.
 
+Note:
+- If the Gradle wrapper (gradlew/gradlew.bat) is present in this repository, prefer using it:
+  - Windows: gradlew.bat <task>
+  - macOS/Linux: ./gradlew <task>
+- If the wrapper is not present, install Gradle 8.5+ on your system and use the system Gradle:
+  - gradle <task>
+
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a critical inconsistency in the documentation regarding the Gradle wrapper, which could lead to user confusion and build failures.

Medium
Prefer wrapper in tests

Make the test script more robust by detecting and preferring gradlew.bat when
available, falling back to the system gradle command otherwise.

test-gradle-build.bat [13]

-call gradle info
+set "GRADLE_CMD=gradle"
+if exist "%~dp0gradlew.bat" set "GRADLE_CMD=%~dp0gradlew.bat"
 
+call "%GRADLE_CMD%" info
+
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies that hardcoding gradle makes the test script brittle and proposes a robust improvement to conditionally use the Gradle wrapper if it exists.

Medium
General
Clarify optional wrapper presence

Correct the documentation to state that the Gradle wrapper is optional, and
provide usage instructions for both scenarios (with and without the wrapper) to
resolve contradictions with other documents.

.gradle-docs/GRADLE_CONVERSION_SUMMARY.md [27-32]

-3. **gradlew.bat** - Gradle wrapper for Windows
-   - Ensures consistent Gradle version across environments
-   - No need to install Gradle separately
+3. (Optional) Gradle Wrapper
+   - If the repository includes gradlew/gradlew.bat and gradle/wrapper/*, use the wrapper to ensure a consistent Gradle version.
+   - If not included, install Gradle 8.5+ system-wide and invoke tasks with the system Gradle binary.
 
-4. **gradlew** - Gradle wrapper for Unix/Linux/Mac
-   - Shell script version of the wrapper
+   Usage:
+   - Windows: gradlew.bat <task> (or gradle <task> if no wrapper)
+   - Unix/Linux/Mac: ./gradlew <task> (or gradle <task> if no wrapper)
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a critical inconsistency in the documentation regarding the Gradle wrapper, which could lead to user confusion and build failures.

Medium
Unify wrapper usage guidance

Replace the incorrect statement that "No Gradle wrapper used" with guidance to
prefer the wrapper if available, otherwise use a system-installed Gradle, to
resolve documentation conflicts.

.gradle-docs/GRADLE_README.md [275]

-- No Gradle wrapper used
+- Prefer the Gradle wrapper if present (./gradlew or gradlew.bat); otherwise use a system-installed Gradle 8.5+.
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a critical inconsistency in the documentation regarding the Gradle wrapper, which could lead to user confusion and build failures.

Medium
Clarify Gradle requirement modality

Clarify the Gradle prerequisite to state that the Gradle wrapper should be used
if present, otherwise a system-wide installation is required, resolving a
documentation conflict.

.gradle-docs/GRADLE_BUILD.md [10]

-- Gradle               | 8.5+         | Must be installed on your system
+- Gradle               | 8.5+         | Use the Gradle wrapper if present; otherwise install Gradle on your system
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a critical inconsistency in the documentation regarding the Gradle wrapper, which could lead to user confusion and build failures.

Medium
Suggestions up to commit b99c353
CategorySuggestion                                                                                                                                    Impact
Security
Harden download and extraction flow

Implement the downloadAndExtractFromUrl function with robust logic, including
download caching, file validation, safe extraction for different archive
formats, and explicit error handling.

.gradle-docs/REMOTE_PROPERTIES_FEATURE.md [40-45]

 def downloadAndExtractFromUrl(String downloadUrl, String version, String name) {
-    // Downloads the archive from the URL
-    // Extracts it to bearsampp-build/tmp/extract/
-    // Finds the module directory
-    // Returns the path to the extracted module
+    File downloadsDir = file("${buildPath}/tmp/downloads/${name}")
+    downloadsDir.mkdirs()
+    String fileName = downloadUrl.tokenize('/').last()
+    File downloadedFile = new File(downloadsDir, fileName)
+
+    // Download if not cached
+    if (!downloadedFile.exists() || downloadedFile.length() == 0L) {
+        ant.get(src: downloadUrl, dest: downloadedFile, verbose: true, usetimestamp: true)
+    }
+    if (!downloadedFile.exists() || downloadedFile.length() == 0L) {
+        throw new GradleException("Download failed or empty file: ${downloadedFile}")
+    }
+
+    // Prepare extraction dir
+    File extractDir = file("${buildPath}/tmp/extract/${name}/${version}")
+    extractDir.mkdirs()
+
+    // Determine format and extract
+    String lower = downloadedFile.name.toLowerCase()
+    if (lower.endsWith(".7z")) {
+        String sevenZip = find7ZipExecutable()
+        def process = new ProcessBuilder(sevenZip, "x", "-y", downloadedFile.absolutePath, "-o${extractDir.absolutePath}")
+                .redirectErrorStream(true)
+                .start()
+        int code = process.waitFor()
+        if (code != 0) {
+            throw new GradleException("7-Zip extraction failed with code ${code} for ${downloadedFile}")
+        }
+    } else if (lower.endsWith(".zip")) {
+        ant.unzip(src: downloadedFile, dest: extractDir)
+    } else {
+        throw new GradleException("Unsupported archive type for ${downloadedFile.name}")
+    }
+
+    // Locate module dir
+    File moduleDir = new File(extractDir, "${name}${version}")
+    if (!moduleDir.exists()) {
+        // Fallback: try to find first matching directory
+        File guessed = extractDir.listFiles()?.find { it.isDirectory() && it.name.toLowerCase().startsWith(name.toLowerCase()) }
+        if (guessed) {
+            moduleDir = guessed
+        }
+    }
+    if (!moduleDir.exists()) {
+        throw new GradleException("Extracted module directory not found under ${extractDir}")
+    }
+    return moduleDir
 }
Suggestion importance[1-10]: 8

__

Why: The suggestion provides a robust implementation for a function stub, adding crucial logic for caching, error handling, and format detection, which significantly improves the reliability of the download feature.

Medium
Validate fallback download URL format

Validate that the download URL retrieved from releases.properties is a
well-formed HTTP or HTTPS URL to improve security and error handling.

.gradle-docs/BUGFIX_SUMMARY.md [57-68]

 def releasesFile = file('releases.properties')
 if (!releasesFile.exists()) {
     throw new GradleException("releases.properties not found")
 }
 
 def releases = new Properties()
 releasesFile.withInputStream { releases.load(it) }
 
-def downloadUrl = releases.getProperty(version)
+def downloadUrl = releases.getProperty(version)?.trim()
 if (!downloadUrl) {
     throw new GradleException("Version ${version} not found in releases.properties or modules-untouched repository")
 }
+if (!(downloadUrl.toLowerCase().startsWith("http://") || downloadUrl.toLowerCase().startsWith("https://"))) {
+    throw new GradleException("Invalid download URL for version ${version}: ${downloadUrl}. Expected an http(s) URL.")
+}
Suggestion importance[1-10]: 7

__

Why: The suggestion hardens the build script against malformed or potentially malicious URLs in the releases.properties file, improving both security and robustness.

Medium
Possible issue
Support 32/64-bit executable detection

Modify the getModuleUntouched function to check for both gswin64c.exe and
gswin32c.exe to support 32-bit and 64-bit architectures.

.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md [50-62]

 def getModuleUntouched(String name, String version) {
     def modulesUntouchedPath = file("${rootDir}/modules-untouched")
     if (modulesUntouchedPath.exists()) {
         def untouchedModulePath = file("${modulesUntouchedPath}/${name}/${name}${version}")
         if (untouchedModulePath.exists()) {
-            def ghostscriptExe = file("${untouchedModulePath}/bin/gswin64c.exe")
-            if (ghostscriptExe.exists()) {
+            def exe64 = file("${untouchedModulePath}/bin/gswin64c.exe")
+            def exe32 = file("${untouchedModulePath}/bin/gswin32c.exe")
+            if (exe64.exists() || exe32.exists()) {
+                println "Found untouched module in: ${untouchedModulePath}"
                 return untouchedModulePath
             }
         }
     }
     return null
 }
Suggestion importance[1-10]: 7

__

Why: This suggestion correctly identifies a potential issue where 32-bit modules would be ignored and makes the build script more flexible by checking for both 32-bit and 64-bit executables.

Medium
Validate source executable before rename

Add an explicit check to ensure gswin64c.exe exists before the copy-and-rename
operation to prevent silent failures.

.gradle-docs/ANT_TO_GRADLE_MAPPING.md [180-184]

+def srcExe = file("${ghostscriptPrepPath}/bin/gswin64c.exe")
+if (!srcExe.exists()) {
+    throw new GradleException("Expected source executable not found: ${srcExe}. Ensure extraction succeeded and architecture matches.")
+}
 copy {
-    from file("${ghostscriptPrepPath}/bin/gswin64c.exe")
+    from srcExe
     into file("${ghostscriptPrepPath}/bin")
     rename { 'gs.exe' }
 }
Suggestion importance[1-10]: 6

__

Why: This is a good defensive programming suggestion that improves error handling by adding a fail-fast check, making potential build failures easier to diagnose.

Low
Suggestions up to commit 1f25990
CategorySuggestion                                                                                                                                    Impact
Possible issue
Preserve function contract and side effects

Modify downloadAndExtractGhostscript to copy contents from the untouchedModule
into destDir before returning, ensuring the function's side-effect is consistent
across all execution paths.

.gradle-docs/BUGFIX_SUMMARY.md [44-70]

 def downloadAndExtractGhostscript(String version, File destDir) {
     // First, try to get from modules-untouched repository (like Ant build)
     def untouchedModule = getModuleUntouched(bundleName, version)
     if (untouchedModule) {
         println "Found untouched module in: ${untouchedModule}"
         println "Using untouched module from modules-untouched repository"
-        return untouchedModule
+        // Ensure destDir contains the expected binaries/layout
+        copy {
+            from untouchedModule
+            into destDir
+        }
+        return destDir
     }
     
     // Second, try to download from releases.properties
     println "Module not found in modules-untouched, downloading from releases.properties..."
     println ""
     
     def releasesFile = file('releases.properties')
     if (!releasesFile.exists()) {
         throw new GradleException("releases.properties not found")
     }
 
     def releases = new Properties()
     releasesFile.withInputStream { releases.load(it) }
 
     def downloadUrl = releases.getProperty(version)
     if (!downloadUrl) {
         throw new GradleException("Version ${version} not found in releases.properties or modules-untouched repository")
     }
-    // ... continues with download
+    // ... continues with download and extraction into destDir
 }
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a logical flaw where the function downloadAndExtractGhostscript violates its contract by not populating the destDir in all code paths, leading to inconsistent behavior.

Medium
Stabilize error checking logic

Modify the test script to prefer the Gradle wrapper (gradlew.bat) for consistent
builds and use delayed expansion for more reliable error checking.

test-gradle-build.bat [13-17]

-call gradle info
-if %ERRORLEVEL% NEQ 0 (
-    echo [FAILED] gradle info task failed
-    exit /b 1
+setlocal EnableDelayedExpansion
+if exist gradlew.bat (
+    set "GRADLE_CMD=gradlew.bat"
+) else (
+    set "GRADLE_CMD=gradle"
 )
 
+call "%GRADLE_CMD%" info
+set "RC=!ERRORLEVEL!"
+if !RC! NEQ 0 (
+    echo [FAILED] gradle info task failed (rc=!RC!)
+    exit /b !RC!
+)
+
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly points out that the script should use the Gradle wrapper (gradlew.bat) for reproducible builds, which is a significant improvement. Using delayed expansion (!ERRORLEVEL!) is also a good practice for making the batch script more robust.

Medium
General
Add Gradle/Java preflight checks

Add pre-flight checks at the beginning of the script to verify that Java and
Gradle are available in the environment, and fail fast if they are not.

test-gradle-build.bat [1-8]

 @echo off
-REM Test script for Gradle build conversion
-REM This script tests all Gradle tasks to ensure they work correctly
+setlocal EnableExtensions EnableDelayedExpansion
+
+where gradlew.bat >nul 2>&1
+if %ERRORLEVEL% EQU 0 (
+    set "GRADLE_CMD=gradlew.bat"
+) else (
+    where gradle >nul 2>&1
+    if %ERRORLEVEL% NEQ 0 (
+        echo [FAILED] Gradle not found. Install Gradle or include gradlew.bat.
+        exit /b 1
+    )
+    set "GRADLE_CMD=gradle"
+)
+
+where java >nul 2>&1
+if %ERRORLEVEL% NEQ 0 (
+    echo [FAILED] Java not found. Ensure Java 8+ is installed and in PATH.
+    exit /b 1
+)
 
 echo ========================================================================
 echo   Bearsampp Module Ghostscript - Gradle Build Test
 echo ========================================================================
 echo.
Suggestion importance[1-10]: 8

__

Why: This is a valuable suggestion that significantly improves the test script's robustness by adding pre-flight checks for Java and Gradle, ensuring it fails fast with clear error messages if the environment is not set up correctly.

Medium
Fix Gradle version mismatch

Align the minimum Gradle version in GRADLE.md with the 7.0+ version stated in
gradle.properties to resolve the documentation conflict.

GRADLE.md [42]

-- Gradle 8.5 or higher
+- Gradle 7.0 or higher
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a clear inconsistency between the GRADLE.md documentation and the gradle.properties file regarding the minimum required Gradle version, which is crucial for correct environment setup.

Medium
✅ Suggestions up to commit d77d2e6
CategorySuggestion                                                                                                                                    Impact
Possible issue
Correct Java version requirement

Update the Java version prerequisite from "Java 8 or higher" to "Java 11 or
higher" to align with the requirements of Gradle 8.5.

GRADLE.md [41-43]

-- Java 8 or higher
+- Java 11 or higher (required by Gradle 8.x)
 - Gradle 8.5 or higher
 - 7-Zip (for .7z archives)
Suggestion importance[1-10]: 9

__

Why: This suggestion corrects a significant factual error in the documentation's prerequisites, as Gradle 8.5 requires Java 11+, preventing user confusion and build failures.

High
Fix unreliable errorlevel checks

Replace the if %ERRORLEVEL% NEQ 0 check with the more reliable if ERRORLEVEL 1
syntax for robust error handling in the batch script.

test-gradle-build.bat [13-17]

 call gradle info
-if %ERRORLEVEL% NEQ 0 (
+if ERRORLEVEL 1 (
     echo [FAILED] gradle info task failed
     exit /b 1
 )
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a potential reliability issue with %ERRORLEVEL% checks in batch scripts and proposes using the more robust IF ERRORLEVEL 1 syntax, which improves the test script's correctness.

Medium
General
Fix absolute doc links
Suggestion Impact:The commit updated at least one documentation link from an absolute path to a relative path (e.g., SOURCE_DOWNLOAD_BEHAVIOR.md), aligning with the suggestion.

code diff:

-See [SOURCE_DOWNLOAD_BEHAVIOR.md](.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) for details.

Change the absolute links to documentation files in /.gradle-docs to relative
links to improve portability.

GRADLE.md [28-37]

-- [GRADLE_README.md](/.gradle-docs/GRADLE_README.md) - Quick reference guide
-- [GRADLE_BUILD.md](/.gradle-docs/GRADLE_BUILD.md) - Complete build documentation
-- [GRADLE_SETUP.md](/.gradle-docs/GRADLE_SETUP.md) - Installation and setup guide
-- [SOURCE_DOWNLOAD_BEHAVIOR.md](/.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) - Source download flow
-- [REMOTE_PROPERTIES_FEATURE.md](/.gradle-docs/REMOTE_PROPERTIES_FEATURE.md) - Remote properties support
-- [BUGFIX_SUMMARY.md](/.gradle-docs/BUGFIX_SUMMARY.md) - Bug fixes and improvements
-- [TEST_MISSING_VERSION.md](/.gradle-docs/TEST_MISSING_VERSION.md) - Testing documentation
-- [MIGRATION_GUIDE.md](/.gradle-docs/MIGRATION_GUIDE.md) - Migration from Ant to Gradle
-- [ANT_TO_GRADLE_MAPPING.md](/.gradle-docs/ANT_TO_GRADLE_MAPPING.md) - Task mapping reference
-- [GRADLE_CONVERSION_SUMMARY.md](/.gradle-docs/GRADLE_CONVERSION_SUMMARY.md) - Conversion summary
+- [GRADLE_README.md](.gradle-docs/GRADLE_README.md) - Quick reference guide
+- [GRADLE_BUILD.md](.gradle-docs/GRADLE_BUILD.md) - Complete build documentation
+- [GRADLE_SETUP.md](.gradle-docs/GRADLE_SETUP.md) - Installation and setup guide
+- [SOURCE_DOWNLOAD_BEHAVIOR.md](.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) - Source download flow
+- [REMOTE_PROPERTIES_FEATURE.md](.gradle-docs/REMOTE_PROPERTIES_FEATURE.md) - Remote properties support
+- [BUGFIX_SUMMARY.md](.gradle-docs/BUGFIX_SUMMARY.md) - Bug fixes and improvements
+- [TEST_MISSING_VERSION.md](.gradle-docs/TEST_MISSING_VERSION.md) - Testing documentation
+- [MIGRATION_GUIDE.md](.gradle-docs/MIGRATION_GUIDE.md) - Migration from Ant to Gradle
+- [ANT_TO_GRADLE_MAPPING.md](.gradle-docs/ANT_TO_GRADLE_MAPPING.md) - Task mapping reference
+- [GRADLE_CONVERSION_SUMMARY.md](.gradle-docs/GRADLE_CONVERSION_SUMMARY.md) - Conversion summary
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly recommends using relative links for better portability, which is a good practice for markdown files in a repository, even if the current links work.

Low
Make links repository-relative

Change the absolute documentation links in README.md to relative links to
improve portability and avoid potential broken navigation.

README.md [10-11]

-- Project docs: /.gradle-docs
-- Build guide: /.gradle-docs/GRADLE_README.md
+- Project docs: .gradle-docs
+- Build guide: .gradle-docs/GRADLE_README.md
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly recommends using relative links for better portability, which is a good practice for markdown files in a repository, even if the current links work.

Low
✅ Suggestions up to commit d96544f
CategorySuggestion                                                                                                                                    Impact
General
Ensure CMD extensions enabled

Add setlocal enableextensions at the beginning of the script to ensure command
extensions are enabled for reliable execution.

test-gradle-build.bat [1-3]

 @echo off
+setlocal enableextensions
 REM Test script for Gradle build conversion
 REM This script tests all Gradle tasks to ensure they work correctly
Suggestion importance[1-10]: 5

__

Why: Adding setlocal enableextensions is a good practice for batch scripts to ensure consistent behavior across different environments, enhancing the script's portability and robustness.

Low
Clarify cross-platform 7-Zip requirement

Clarify the 7-Zip prerequisite to include instructions for both Windows
(7Z_HOME) and non-Windows (7z in PATH) environments to avoid cross-platform
confusion.

GRADLE.md [43]

-- 7-Zip (for .7z archives)
+- 7-Zip (for .7z archives; ensure `7z` is available in PATH on Linux/macOS, or set `7Z_HOME` on Windows)
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that the documentation for the 7-Zip prerequisite is Windows-centric and provides helpful clarification for non-Windows users.

Low
Make paths clickable links

Convert the plain text paths for project documentation and the build guide into
explicit Markdown links to ensure they are always clickable.

README.md [10-11]

-- Project docs: /.gradle-docs
-- Build guide: /.gradle-docs/GRADLE_README.md
+- Project docs: [/.gradle-docs](/.gradle-docs)
+- Build guide: [/.gradle-docs/GRADLE_README.md](/.gradle-docs/GRADLE_README.md)
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly proposes converting plain text paths into explicit Markdown links, improving link reliability and user experience across different Markdown viewers.

Low
Fix inconsistent relative link
Suggestion Impact:The link was changed from a relative path to an absolute-from-root path: ".gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md" became "/.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md".

code diff:

-See [SOURCE_DOWNLOAD_BEHAVIOR.md](.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) for details.

Standardize the relative link for SOURCE_DOWNLOAD_BEHAVIOR.md to use an
absolute-from-root path, matching other links in the file for consistency.

GRADLE.md [78]

-See [SOURCE_DOWNLOAD_BEHAVIOR.md](.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) for details.
+See [SOURCE_DOWNLOAD_BEHAVIOR.md](/.gradle-docs/SOURCE_DOWNLOAD_BEHAVIOR.md) for details.
Suggestion importance[1-10]: 3

__

Why: The suggestion correctly identifies an inconsistent link format and proposes a change for better consistency and robustness, which is a minor but valid improvement.

Low
Possible issue
Fix errorlevel checks robustness

Replace if %ERRORLEVEL% NEQ 0 with the more robust if ERRORLEVEL 1 for all error
checks in the batch script to improve reliability.

test-gradle-build.bat [13-17]

 call gradle info
-if %ERRORLEVEL% NEQ 0 (
+if ERRORLEVEL 1 (
     echo [FAILED] gradle info task failed
     exit /b 1
 )
Suggestion importance[1-10]: 4

__

Why: The suggestion correctly identifies that using if ERRORLEVEL 1 is more robust than if %ERRORLEVEL% NEQ 0 in batch scripts, improving script reliability.

Low

@qodo-code-review
Copy link

qodo-code-review bot commented Nov 14, 2025

PR Reviewer Guide 🔍

(Review updated until commit 52a0d39)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Portability

The script assumes 'gradle' is on PATH and uses Windows-only batch commands; consider using 'gradlew' or documenting PATH checks and using 'gradle.bat' explicitly for Windows environments.

call gradle info
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle info task failed
    exit /b 1
)
echo [PASSED] gradle info task
echo.

REM Test 2: List all tasks
echo [TEST 2] Testing 'gradle tasks' task...
echo ------------------------------------------------------------------------
call gradle tasks
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle tasks task failed
    exit /b 1
)
echo [PASSED] gradle tasks task
echo.

REM Test 3: List available versions
echo [TEST 3] Testing 'gradle listVersions' task...
echo ------------------------------------------------------------------------
call gradle listVersions
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle listVersions task failed
    exit /b 1
)
echo [PASSED] gradle listVersions task
echo.

REM Test 4: List releases from properties
echo [TEST 4] Testing 'gradle listReleases' task...
echo ------------------------------------------------------------------------
call gradle listReleases
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle listReleases task failed
    exit /b 1
)
echo [PASSED] gradle listReleases task
echo.

REM Test 5: Verify build environment
echo [TEST 5] Testing 'gradle verify' task...
echo ------------------------------------------------------------------------
call gradle verify
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle verify task failed
    exit /b 1
)
echo [PASSED] gradle verify task
echo.

REM Test 6: Validate properties
echo [TEST 6] Testing 'gradle validateProperties' task...
echo ------------------------------------------------------------------------
call gradle validateProperties
if %ERRORLEVEL% NEQ 0 (
    echo [FAILED] gradle validateProperties task failed
    exit /b 1
)
echo [PASSED] gradle validateProperties task
echo.

REM Test 7: Clean build
echo [TEST 7] Testing 'gradle clean' task...
echo ------------------------------------------------------------------------
call gradle clean
if %ERRORLEVEL% NEQ 0 (
Consistency

Documentation repeats sections and mixes two "Quick Start" blocks with slightly different prerequisites (Gradle 8.0+ vs 8.5+); unify versions and remove duplication to prevent confusion.

> **⚠️ Important Note**: This project uses **system-installed Gradle only**. Neither Apache Ant nor Gradle Wrapper (gradlew/gradlew.bat) are used or supported. You must install Gradle 8.0+ on your system before building.

### Project Information

| Property          | Value                                    |
|-------------------|------------------------------------------|
| **Project Name**  | module-ghostscript                       |
| **Group**         | com.bearsampp.modules                    |
| **Type**          | Ghostscript Module Builder               |
| **Build Tool**    | Gradle 8.x+                              |
| **Language**      | Groovy (Gradle DSL)                      |

---

## Quick Start

### Prerequisites

| Requirement       | Version       | Purpose                                  |
|-------------------|---------------|------------------------------------------|
| **Java**          | 8+            | Required for Gradle execution            |
| **Gradle**        | 8.0+          | Build automation tool                    |
| **7-Zip**         | Latest        | Archive extraction and creation          |

### Basic Commands

```bash
# Display build information
gradle info

# List all available tasks
gradle tasks

# Verify build environment
gradle verify

# Build a release (interactive)
gradle release

# Build a specific version (non-interactive)
gradle release -PbundleVersion=10.05.1

# Build all versions
gradle releaseAll

# Clean build artifacts
gradle clean

Installation

1. Clone the Repository

git clone https://github.com/bearsampp/module-ghostscript.git
cd module-ghostscript

2. Verify Environment

gradle verify

This will check:

  • Java version (8+)
  • Required files (build.properties, releases.properties)
  • Directory structure (bin/, bin/archived/)
  • Build dependencies
  • 7-Zip availability (if format=7z)

3. List Available Versions

gradle listVersions

4. Build Your First Release

# Interactive mode (prompts for version)
gradle release

# Or specify version directly
gradle release -PbundleVersion=10.05.1

Build Tasks

Core Build Tasks

Task Description Example
release Build and package release (interactive/non-interactive) gradle release -PbundleVersion=10.05.1
releaseAll Build all available versions gradle releaseAll
clean Clean build artifacts and temporary files gradle clean

Verification Tasks

Task Description Example
verify Verify build environment and dependencies gradle verify
validateProperties Validate build.properties configuration gradle validateProperties
checkModulesUntouched Check modules-untouched integration gradle checkModulesUntouched

Information Tasks

Task Description Example
info Display build configuration information gradle info
listVersions List available bundle versions in bin/ gradle listVersions
listReleases List all available releases from properties gradle listReleases

Task Groups

Group Purpose
build Build and package tasks
verification Verification and validation tasks
help Help and information tasks

Configuration

build.properties

The main configuration file for the build:

bundle.name    = ghostscript
bundle.release = 2025.7.31
bundle.type    = tools
bundle.format  = 7z
#build.path    = C:/Bearsampp-build
Property Description Example Value
bundle.name Name of the bundle ghostscript
bundle.release Release version 2025.7.31
bundle.type Type of bundle tools
bundle.format Archive format 7z
build.path Custom build output path (optional) C:/Bearsampp-build

gradle.properties

Gradle-specific configuration:

# Gradle daemon configuration
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.caching=true

# JVM settings
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m

Directory Structure

module-ghostscript/
├── .gradle-docs/          # Gradle documentation
│   ├── README.md          # Main documentation (this file)
│   ├── TASKS.md           # Task reference
│   ├── CONFIGURATION.md   # Configuration guide
│   ├── API.md             # API reference
│   ├── MIGRATION.md       # Migration guide
│   └── INDEX.md           # Documentation index
├── bin/                   # Ghostscript version bundles
│   ├── ghostscript10.05.1/
│   └── archived/
│       ├── ghostscript9.22/
│       ├── ghostscript9.56.1/
│       └── ...
├── bearsampp-build/       # External build directory (outside repo)
│   ├── tmp/               # Temporary build files
│   │   ├── bundles_prep/tools/ghostscript/
│   │   ├── bundles_build/tools/ghostscript/
│   │   ├── downloads/ghostscript/
│   │   └── extract/ghostscript/
│   └── tools/ghostscript/ # Final packaged archives
│       └── 2025.7.31/
│           ├── bearsampp-ghostscript-10.05.1-2025.7.31.7z
│           ├── bearsampp-ghostscript-10.05.1-2025.7.31.7z.md5
│           └── ...
├── build.gradle           # Main Gradle build script
├── settings.gradle        # Gradle settings
├── build.properties       # Build configuration
└── releases.properties    # Available Ghostscript releases

Architecture

Build Process Flow

1. User runs: gradle release -PbundleVersion=10.05.1
                    ↓
2. Validate environment and version
                    ↓
3. Check for local bundle in bin/ or bin/archived/
                    ↓
4. If not found, download from:
   - modules-untouched repository (remote)
   - releases.properties (fallback)
                    ↓
5. Create preparation directory (tmp/prep/)
                    ↓
6. Copy Ghostscript files (excluding docs/examples)
                    ↓
7. Create gs.exe from gswin64c.exe or gswin32c.exe
                    ↓
8. Copy configuration files (bearsampp.conf, update_cidfmap.bat)
                    ↓
9. Output prepared bundle to tmp/prep/
                    ↓
10. Package prepared folder into archive in bearsampp-build/tools/ghostscript/{bundle.release}/
    - The archive includes the top-level folder: ghostscript{version}/

Packaging Details

  • Archive name format: bearsampp-ghostscript-{version}-{bundle.release}.{7z|zip}
  • Location: bearsampp-build/tools/ghostscript/{bundle.release}/
    • Example: bearsampp-build/tools/ghostscript/2025.7.31/bearsampp-ghostscript-10.05.1-2025.7.31.7z
  • Content root: The top-level folder inside the archive is ghostscript{version}/ (e.g., ghostscript10.05.1/)
  • Structure: The archive contains the Ghostscript version folder at the root with all files inside

Archive Structure Example:

bearsampp-ghostscript-10.05.1-2025.7.31.7z
└── ghostscript10.05.1/    ← Version folder at root
    ├── bin/
    │   ├── gswin64c.exe
    │   ├── gs.exe
    │   └── ...
    ├── bearsampp.conf
    ├── update_cidfmap.bat
    └── ...

Hash Files: Each archive is accompanied by hash sidecar files:

  • .md5 - MD5 checksum
  • .sha1 - SHA-1 checksum
  • .sha256 - SHA-256 checksum
  • .sha512 - SHA-512 checksum

Download Priority

When building a version, the system follows this priority:

  1. Local bin/ directory: Check bin/ghostscript{version}/
  2. Local bin/archived/ directory: Check bin/archived/ghostscript{version}/
  3. modules-untouched repository: Download from remote properties file
  4. releases.properties: Download from local configuration

Downloaded files are cached in bearsampp-build/tmp/downloads/ and bearsampp-build/tmp/extract/.


Troubleshooting

Common Issues

Issue: "Dev path not found"

Symptom:

Dev path not found: E:/Bearsampp-development/dev

Solution:
This is a warning only. The dev path is optional for most tasks. If you need it, ensure the dev project exists in the parent directory.


Issue: "Bundle version not found"

Symptom:

Bundle version not found: E:/Bearsampp-development/module-ghostscript/bin/ghostscript10.05.99

Solution:

  1. List available versions: gradle listVersions
  2. Use an existing version: gradle release -PbundleVersion=10.05.1
  3. Or add the version to releases.properties for download

Issue: "7-Zip not found"

Symptom:

7-Zip not found. Please install 7-Zip or set 7Z_HOME environment variable.

Solution:

  1. Install 7-Zip from https://www.7-zip.org/
  2. Set 7Z_HOME environment variable: set 7Z_HOME=C:\Program Files\7-Zip

Issue: "Java version too old"

Symptom:

Java 8+ required

Solution:

  1. Check Java version: java -version
  2. Install Java 8 or higher
  3. Update JAVA_HOME environment variable

Debug Mode

Run Gradle with debug output:

gradle release -PbundleVersion=10.05.1 --info
gradle release -PbundleVersion=10.05.1 --debug

Clean Build

If you encounter issues, try a clean build:

gradle clean
gradle release -PbundleVersion=10.05.1

Migration Guide

From Ant to Gradle

The project has been fully migrated from Ant to Gradle. Here's what changed:

Removed Files

File Status Replacement
build.xml ❌ Removed build.gradle

Command Mapping

Ant Command Gradle Command
ant release.build -Dbundle.path=bin/ghostscript10.05.1 gradle release -PbundleVersion=10.05.1
N/A gradle release (interactive)
N/A gradle releaseAll
ant clean gradle clean

Key Differences

Aspect Ant Gradle
Build File XML (build.xml) Groovy DSL (build.gradle)
Task Definition <target name="..."> tasks.register('...')
Properties <property name="..." /> ext { ... }
Caching None Built-in incremental builds
IDE Support Limited Excellent (IntelliJ, Eclipse)

For complete migration guide, see MIGRATION.md


Additional Resources


Support

For issues and questions:


Last Updated: 2025-01-31
Version: 2025.7.31
Build System: Pure Gradle (no wrapper, no Ant)

Notes:

  • This project deliberately does not ship the Gradle Wrapper. Install Gradle 8+ locally and run with gradle ....
  • Legacy Ant files have been removed and replaced with pure Gradle implementation.

🚀 Quick Start

Prerequisites

Requirement Version Description
Java 8 or higher Required for Gradle execution
Gradle 8.5+ Must be installed on your system
7-Zip Latest Required for .7z archive creation

Basic Commands

# Verify environment
gradle verify

# List available versions
gradle listVersions

# Build a specific version
gradle release -PbundleVersion=10.05.1

# Build interactively (select from menu)
gradle release

# Build all versions
gradle releaseAll

# Display build info
gradle info

# List all tasks
gradle tasks

</details>

<details><summary><a href='https://github.com/Bearsampp/module-ghostscript/pull/16/files#diff-2882908f3aeed61d657698338c698f94281febf60dc07c94656ccf5370f92497R210-R420'><strong>Accuracy</strong></a>

API docs reference helper methods and Gradle tasks; ensure these helpers and tasks actually exist in 'build.gradle' and match names/signatures to avoid doc-code drift.
</summary>

```markdown
## Helper Functions

### `fetchModulesUntouchedProperties()`

**Description:** Fetch ghostscript.properties from modules-untouched repository

**Parameters:** None

**Returns:** `Properties` - Properties object or null if fetch fails

**Example:**

```groovy
def props = fetchModulesUntouchedProperties()
if (props) {
    def url = props.getProperty('10.05.1')
}

Process:

  1. Construct URL to modules-untouched properties file
  2. Download properties file
  3. Parse and return Properties object
  4. Return null on failure

getModuleUntouched(String name, String version)

Description: Get Ghostscript module from modules-untouched repository (local or remote)

Parameters:

Parameter Type Description
name String Module name (ghostscript)
version String Version to retrieve

Returns: File - Directory containing Ghostscript files or null

Example:

def ghostscriptDir = getModuleUntouched('ghostscript', '10.05.1')
if (ghostscriptDir) {
    println "Found at: ${ghostscriptDir}"
}

Process:

  1. Check local modules-untouched repository
  2. If not found, check remote properties file
  3. Download and extract if found remotely
  4. Return directory or null

getModuleUntouchedRemoteUrl(String name, String version)

Description: Get download URL from modules-untouched remote properties file

Parameters:

Parameter Type Description
name String Module name (ghostscript)
version String Version to retrieve

Returns: String - Download URL or null

Example:

def url = getModuleUntouchedRemoteUrl('ghostscript', '10.05.1')
if (url) {
    println "Download URL: ${url}"
}

downloadAndExtractFromUrl(String downloadUrl, String version, String name)

Description: Download and extract Ghostscript from URL

Parameters:

Parameter Type Description
downloadUrl String URL to download from
version String Version being downloaded
name String Module name

Returns: File - Directory containing extracted files

Example:

def ghostscriptDir = downloadAndExtractFromUrl(
    'https://example.com/gs10.05.1.7z',
    '10.05.1',
    'ghostscript'
)

Process:

  1. Download archive from URL
  2. Extract to temporary directory
  3. Find Ghostscript directory in extracted files
  4. Return directory

downloadAndExtractGhostscript(String version, File destDir)

Description: Download and extract Ghostscript binaries (with fallback logic)

Parameters:

Parameter Type Description
version String Ghostscript version
destDir File Destination directory

Returns: File - Directory containing Ghostscript files

Example:

def ghostscriptDir = downloadAndExtractGhostscript('10.05.1', file(bundleTmpExtractPath))

Process:

  1. Try modules-untouched repository (local)
  2. Try modules-untouched repository (remote)
  3. Try releases.properties
  4. Download and extract
  5. Return directory

findGhostscriptDirectory(File extractPath)

Description: Find Ghostscript directory in extracted files

Parameters:

Parameter Type Description
extractPath File Directory to search

Returns: File - Ghostscript directory or null

Example:

def ghostscriptDir = findGhostscriptDirectory(file("${bundleTmpExtractPath}/10.05.1"))

Process:

  1. Check if extractPath itself contains gswin64c.exe or gswin32c.exe
  2. Search top-level directories
  3. Search one level deep
  4. Return directory or null

find7ZipExecutable()

Description: Find 7-Zip executable on system

Parameters: None

Returns: String - Path to 7z.exe or null

Example:

def sevenZipPath = find7ZipExecutable()
if (sevenZipPath) {
    println "7-Zip found at: ${sevenZipPath}"
}

Process:

  1. Check 7Z_HOME environment variable
  2. Check common installation paths
  3. Check PATH environment variable
  4. Return path or null

generateHashFiles(File file)

Description: Generate hash files (MD5, SHA1, SHA256, SHA512) for archive

Parameters:

Parameter Type Description
file File File to generate hashes for

Returns: void

Example:

generateHashFiles(file('bearsampp-ghostscript-10.05.1-2025.7.31.7z'))

Process:


</details>

</td></tr>
</table>

@jwaisner jwaisner merged commit 55b3e7c into main Nov 19, 2025
@jwaisner jwaisner deleted the gradle-convert branch November 19, 2025 02:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement ✨ Improve program

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants