From 082b84fe271a2ba59e433a3438eae0769abe6410 Mon Sep 17 00:00:00 2001 From: jwaisner Date: Sat, 8 Nov 2025 09:37:51 -0600 Subject: [PATCH 1/4] Added Gradle to build process. --- .gitignore | 4 + build.gradle | 381 ++++++++++++++++++++++++++++++++++++++++++++++ gradle.properties | 19 +++ settings.gradle | 25 +++ 4 files changed, 429 insertions(+) create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index 207bc8a7..0837e3f7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,7 @@ # Qodo /.qodo + +# Gradle +/.gradle +/build diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..9e9f2473 --- /dev/null +++ b/build.gradle @@ -0,0 +1,381 @@ +/* + * Bearsampp Module Node.js - Gradle Build + * + * This is a hybrid build configuration that: + * 1. Imports existing Ant build files for backward compatibility + * 2. Provides modern Gradle features (caching, incremental builds, parallel execution) + * 3. Allows gradual migration from Ant to Gradle + * + * Usage: + * gradle tasks - List all available tasks + * gradle release - Interactive release (prompts for version) + * gradle release "-PbundleVersion=22.13.0" - Non-interactive release + * gradle clean - Clean build artifacts + * gradle info - Display build information + */ + +plugins { + id 'base' +} + +// Load build properties +def buildProps = new Properties() +file('build.properties').withInputStream { buildProps.load(it) } + +// Project information +group = 'com.bearsampp.modules' +version = buildProps.getProperty('bundle.release', '1.0.0') +description = "Bearsampp Module - ${buildProps.getProperty('bundle.name', 'nodejs')}" + +// Define project paths +ext { + projectBasedir = projectDir.absolutePath + rootDir = projectDir.parent + devPath = file("${rootDir}/dev").absolutePath + buildPropertiesFile = file('build.properties').absolutePath + + // Bundle properties from build.properties + bundleName = buildProps.getProperty('bundle.name', 'nodejs') + bundleRelease = buildProps.getProperty('bundle.release', '1.0.0') + bundleType = buildProps.getProperty('bundle.type', 'bins') + bundleFormat = buildProps.getProperty('bundle.format', '7z') +} + +// Verify dev path exists +if (!file(ext.devPath).exists()) { + throw new GradleException("Dev path not found: ${ext.devPath}. Please ensure the 'dev' project exists in ${ext.rootDir}") +} + +// Configure repositories for dependencies +repositories { + mavenCentral() +} + +// ============================================================================ +// ANT INTEGRATION - Import existing Ant build files +// ============================================================================ + +// Set Ant properties before importing +ant.properties['project.basedir'] = ext.projectBasedir +ant.properties['root.dir'] = ext.rootDir +ant.properties['dev.path'] = ext.devPath +ant.properties['build.properties'] = ext.buildPropertiesFile + +// Load build.properties into Ant +ant.property(file: ext.buildPropertiesFile) + +// Import the main Ant build file +// This preserves all existing Ant functionality +ant.importBuild('build.xml') { antTargetName -> + // Map Ant target names to Gradle task names + // Prefix all with 'ant-' to avoid conflicts + return "ant-${antTargetName}".toString() +} + +// ============================================================================ +// GRADLE NATIVE TASKS - Modern alternatives and enhancements +// ============================================================================ + +// Task: Display build information +tasks.register('info') { + group = 'help' + description = 'Display build configuration information' + + def projectName = project.name + def projectVersion = project.version + def projectDescription = project.description + def gradleVersion = gradle.gradleVersion + def gradleHomeDir = gradle.gradleHomeDir + + doLast { + println """ + ================================================================ + Bearsampp Module Node.js - Build Info + ================================================================ + + Project: ${projectName} + Version: ${projectVersion} + Description: ${projectDescription} + + Bundle Properties: + Name: ${bundleName} + Release: ${bundleRelease} + Type: ${bundleType} + Format: ${bundleFormat} + + Paths: + Project Dir: ${projectBasedir} + Root Dir: ${rootDir} + Dev Path: ${devPath} + + Java: + Version: ${JavaVersion.current()} + Home: ${System.getProperty('java.home')} + + Gradle: + Version: ${gradleVersion} + Home: ${gradleHomeDir} + + Available Task Groups: + * build - Build and package tasks + * ant tasks - Legacy Ant tasks (prefixed with 'ant-') + * help - Help and information tasks + + Quick Start: + gradle tasks - List all available tasks + gradle info - Show this information + gradle release - Interactive release build + gradle release "-PbundleVersion=22.13.0" - Non-interactive release + gradle clean - Clean build artifacts + gradle verify - Verify build environment + """.stripIndent() + } +} + +// Task: Main release task - supports both interactive and non-interactive modes +tasks.register('release') { + group = 'build' + description = 'Build release package (interactive or use -PbundleVersion=X.X.X for non-interactive)' + + // Ensure libraries are loaded first + dependsOn 'ant-load.lib' + + doLast { + def versionToBuild = project.findProperty('bundleVersion') + + if (versionToBuild) { + // Non-interactive mode with specified version + println "=".multiply(70) + println "Building release for ${bundleName} version ${versionToBuild}..." + println "=".multiply(70) + + def bundlePath = file("${projectDir}/bin/${bundleName}${versionToBuild}") + + if (!bundlePath.exists()) { + def availableVersions = file("${projectDir}/bin").listFiles() + .findAll { it.isDirectory() && it.name.startsWith(bundleName) } + .collect { " - " + it.name.replace(bundleName, '') } + .join('\n') + + throw new GradleException("Bundle version not found: ${bundlePath}\n\nAvailable versions in bin/:\n${availableVersions}") + } + + println "Bundle path: ${bundlePath}" + println "" + + // Execute Ant command directly to avoid Gradle Ant integration issues + def antCommand = ["cmd", "/c", "ant", "release", "-Dinput.bundle=${versionToBuild}"] + println "Executing: ant release -Dinput.bundle=${versionToBuild}" + println "" + + def process = antCommand.execute(null, projectDir) + process.consumeProcessOutput(System.out, System.err) + def exitCode = process.waitFor() + + if (exitCode != 0) { + throw new GradleException("Ant release failed with exit code: ${exitCode}") + } + + println "" + println "=".multiply(70) + println "[SUCCESS] Release build completed successfully for version ${versionToBuild}" + println "=".multiply(70) + } else { + // Interactive mode - call Ant release target which will prompt for input + println "=".multiply(70) + println "Starting interactive release build..." + println "You will be prompted to enter the bundle version." + println "=".multiply(70) + println "" + + // Call the imported ant-release target for interactive mode + tasks.getByName('ant-release').actions.each { action -> + action.execute(tasks.getByName('ant-release')) + } + + println "" + println "=".multiply(70) + println "[SUCCESS] Release build completed" + println "=".multiply(70) + } + } +} + +// Task: Enhanced clean task +tasks.named('clean') { + group = 'build' + description = 'Clean build artifacts and temporary files' + + doLast { + // Clean Gradle build directory + def buildDir = file("${projectDir}/build") + if (buildDir.exists()) { + delete buildDir + } + + // Clean any temporary directories that might be created + // Use manual directory traversal to avoid fileTree default excludes issue + def tmpDirs = [] + projectDir.eachFileRecurse { file -> + if (file.isDirectory() && (file.name == 'tmp' || file.name == '.tmp')) { + tmpDirs.add(file) + } + } + tmpDirs.each { dir -> + if (dir.exists()) { + delete dir + } + } + + println "[SUCCESS] Build artifacts cleaned" + } +} + +// Task: Verify build environment +tasks.register('verify') { + group = 'verification' + description = 'Verify build environment and dependencies' + + doLast { + println "Verifying build environment for module-nodejs..." + + def checks = [:] + + // Check Java version + def javaVersion = JavaVersion.current() + checks['Java 8+'] = javaVersion >= JavaVersion.VERSION_1_8 + + // Check required files + checks['build.xml'] = file('build.xml').exists() + checks['build.properties'] = file('build.properties').exists() + checks['releases.properties'] = file('releases.properties').exists() + + // Check dev directory and required build files + checks['dev directory'] = file(devPath).exists() + checks['build-commons.xml'] = file("${devPath}/build/build-commons.xml").exists() + checks['build-bundle.xml'] = file("${devPath}/build/build-bundle.xml").exists() + + println "\nEnvironment Check Results:" + println "-".multiply(60) + checks.each { name, passed -> + def status = passed ? "[PASS]" : "[FAIL]" + println " ${status.padRight(10)} ${name}" + } + println "-".multiply(60) + + def allPassed = checks.values().every { it } + if (allPassed) { + println "\n[SUCCESS] All checks passed! Build environment is ready." + println "\nYou can now run:" + println " gradle release - Interactive release" + println " gradle release \"-PbundleVersion=22.13.0\" - Non-interactive release" + } else { + println "\n[WARNING] Some checks failed. Please review the requirements." + throw new GradleException("Build environment verification failed") + } + } +} + +// Task: List all bundle versions from releases.properties +tasks.register('listReleases') { + group = 'help' + description = 'List all available releases from releases.properties' + + doLast { + def releasesFile = file('releases.properties') + if (!releasesFile.exists()) { + println "releases.properties not found" + return + } + + def releases = new Properties() + releasesFile.withInputStream { releases.load(it) } + + println "\nAvailable Node.js Releases:" + println "-".multiply(80) + releases.sort { it.key }.each { version, url -> + println " ${version.padRight(10)} -> ${url}" + } + println "-".multiply(80) + println "Total releases: ${releases.size()}" + } +} + +// Task: List available bundle versions in bin directory +tasks.register('listVersions') { + group = 'help' + description = 'List all available bundle versions in bin/ directory' + + doLast { + def binDir = file("${projectDir}/bin") + if (!binDir.exists()) { + println "bin/ directory not found" + return + } + + def versions = binDir.listFiles() + .findAll { it.isDirectory() && it.name.startsWith(bundleName) } + .collect { it.name.replace(bundleName, '') } + .sort() + + println "\nAvailable ${bundleName} versions in bin/:" + println "-".multiply(60) + versions.each { version -> + println " ${version}" + } + println "-".multiply(60) + println "Total versions: ${versions.size()}" + println "\nTo build a specific version:" + println " gradle release \"-PbundleVersion=${versions.last()}\"" + } +} + +// Task: Validate build.properties +tasks.register('validateProperties') { + group = 'verification' + description = 'Validate build.properties configuration' + + doLast { + println "Validating build.properties..." + + def required = ['bundle.name', 'bundle.release', 'bundle.type', 'bundle.format'] + def missing = [] + + required.each { prop -> + if (!buildProps.containsKey(prop) || buildProps.getProperty(prop).trim().isEmpty()) { + missing.add(prop) + } + } + + if (missing.isEmpty()) { + println "[SUCCESS] All required properties are present:" + required.each { prop -> + println " ${prop} = ${buildProps.getProperty(prop)}" + } + } else { + println "[ERROR] Missing required properties:" + missing.each { prop -> + println " - ${prop}" + } + throw new GradleException("build.properties validation failed") + } + } +} + +// ============================================================================ +// BUILD LIFECYCLE HOOKS +// ============================================================================ + +gradle.taskGraph.whenReady { graph -> + println """ + ================================================================ + Bearsampp Module Node.js - Gradle + Ant Hybrid Build + ================================================================ + """.stripIndent() +} + +// ============================================================================ +// DEFAULT TASK +// ============================================================================ + +defaultTasks 'info' diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..eab38d9d --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Gradle Build Properties for Bearsampp Module Node.js + +# Gradle daemon configuration +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true + +# JVM settings for Gradle +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError + +# Configure console output +org.gradle.console=auto +org.gradle.warning.mode=all + +# Build performance +org.gradle.configureondemand=false + +# Gradle version compatibility +# This project is compatible with Gradle 7.0+ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..53e2de93 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,25 @@ +/* + * Bearsampp Module Node.js - Gradle Settings + */ + +rootProject.name = 'module-nodejs' + +// Enable Gradle features for better performance +enableFeaturePreview('STABLE_CONFIGURATION_CACHE') + +// Configure build cache for faster builds +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + } +} + +// Display initialization message +gradle.rootProject { + println """ + ================================================================ + Initializing Bearsampp Module Node.js Build + ================================================================ + """.stripIndent() +} From 7b0a8d5a5bf4d253ec9d52f7689148a5c51c286b Mon Sep 17 00:00:00 2001 From: Bear Date: Fri, 14 Nov 2025 21:09:32 -0600 Subject: [PATCH 2/4] gradle now works 100% --- README.md | 43 + .../nodejs22.17.0/bearsampp.conf | 0 bin/{ => archived}/nodejs22.17.0/etc/npmrc | 0 .../nodejs22.17.0/etc/npmrc.ber | 0 bin/{ => archived}/nodejs22.17.0/launch.bat | 0 .../nodejs22.17.0/node_modules/npm/npmrc | 0 .../nodejs22.17.0/node_modules/npm/npmrc.ber | 0 .../nodejs22.18.0/bearsampp.conf | 0 bin/{ => archived}/nodejs22.18.0/etc/npmrc | 0 .../nodejs22.18.0/etc/npmrc.ber | 0 bin/{ => archived}/nodejs22.18.0/launch.bat | 0 .../nodejs22.18.0/node_modules/npm/npmrc | 0 .../nodejs22.18.0/node_modules/npm/npmrc.ber | 0 build.gradle | 898 ++++++++++++++---- 14 files changed, 776 insertions(+), 165 deletions(-) rename bin/{ => archived}/nodejs22.17.0/bearsampp.conf (100%) rename bin/{ => archived}/nodejs22.17.0/etc/npmrc (100%) rename bin/{ => archived}/nodejs22.17.0/etc/npmrc.ber (100%) rename bin/{ => archived}/nodejs22.17.0/launch.bat (100%) rename bin/{ => archived}/nodejs22.17.0/node_modules/npm/npmrc (100%) rename bin/{ => archived}/nodejs22.17.0/node_modules/npm/npmrc.ber (100%) rename bin/{ => archived}/nodejs22.18.0/bearsampp.conf (100%) rename bin/{ => archived}/nodejs22.18.0/etc/npmrc (100%) rename bin/{ => archived}/nodejs22.18.0/etc/npmrc.ber (100%) rename bin/{ => archived}/nodejs22.18.0/launch.bat (100%) rename bin/{ => archived}/nodejs22.18.0/node_modules/npm/npmrc (100%) rename bin/{ => archived}/nodejs22.18.0/node_modules/npm/npmrc.ber (100%) diff --git a/README.md b/README.md index 3015d9b7..ba3e6985 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,53 @@ This is a module of [Bearsampp project](https://github.com/bearsampp/bearsampp) involving Node.js. +## Build (Gradle) + +This module now uses a pure Gradle build similar to the Bruno module. + +Quick commands: + +- List tasks: `gradle tasks` +- Show build info: `gradle info` +- Verify environment: `gradle verify` +- List local versions (bin and bin/archived): `gradle listVersions` +- List releases from modules-untouched: `gradle listReleases` +- Build a specific version: `gradle release -PbundleVersion=24.6.0` +- Build interactively (choose from local versions): `gradle release` +- Build all local versions (prep/copy flow): `gradle releaseAll` +- Clean: `gradle clean` + +Version resolution strategy: + +1. Remote `modules-untouched` `nodejs.properties` + - URL: `https://github.com/Bearsampp/modules-untouched/blob/main/modules/nodejs.properties` +2. Fallback constructed URL: `.../releases/download/nodejs-{version}/nodejs-{version}-win-x64.7z` + +Output locations and overrides: + +- Default base output: `/../bearsampp-build` +- Override base output via either: + - `build.properties` property `build.path` + - Environment variable `BEARSAMPP_BUILD_PATH` + +Packaging settings come from `build.properties`: + +- `bundle.name = nodejs` +- `bundle.type = bins` +- `bundle.format = 7z` (requires 7‑Zip) + +7‑Zip detection (Windows): + +- Auto-detects from `7Z_HOME` or common install paths, falls back to `where 7z.exe`. + +Documentation index: see `/.gradle-docs/README.md`. + ## Documentation and downloads https://bearsampp.com/module/nodejs +Additional Gradle build docs for this module live in `/.gradle-docs/` of this repository. + ## Issues Issues must be reported on [Bearsampp repository](https://github.com/bearsampp/bearsampp/issues). diff --git a/bin/nodejs22.17.0/bearsampp.conf b/bin/archived/nodejs22.17.0/bearsampp.conf similarity index 100% rename from bin/nodejs22.17.0/bearsampp.conf rename to bin/archived/nodejs22.17.0/bearsampp.conf diff --git a/bin/nodejs22.17.0/etc/npmrc b/bin/archived/nodejs22.17.0/etc/npmrc similarity index 100% rename from bin/nodejs22.17.0/etc/npmrc rename to bin/archived/nodejs22.17.0/etc/npmrc diff --git a/bin/nodejs22.17.0/etc/npmrc.ber b/bin/archived/nodejs22.17.0/etc/npmrc.ber similarity index 100% rename from bin/nodejs22.17.0/etc/npmrc.ber rename to bin/archived/nodejs22.17.0/etc/npmrc.ber diff --git a/bin/nodejs22.17.0/launch.bat b/bin/archived/nodejs22.17.0/launch.bat similarity index 100% rename from bin/nodejs22.17.0/launch.bat rename to bin/archived/nodejs22.17.0/launch.bat diff --git a/bin/nodejs22.17.0/node_modules/npm/npmrc b/bin/archived/nodejs22.17.0/node_modules/npm/npmrc similarity index 100% rename from bin/nodejs22.17.0/node_modules/npm/npmrc rename to bin/archived/nodejs22.17.0/node_modules/npm/npmrc diff --git a/bin/nodejs22.17.0/node_modules/npm/npmrc.ber b/bin/archived/nodejs22.17.0/node_modules/npm/npmrc.ber similarity index 100% rename from bin/nodejs22.17.0/node_modules/npm/npmrc.ber rename to bin/archived/nodejs22.17.0/node_modules/npm/npmrc.ber diff --git a/bin/nodejs22.18.0/bearsampp.conf b/bin/archived/nodejs22.18.0/bearsampp.conf similarity index 100% rename from bin/nodejs22.18.0/bearsampp.conf rename to bin/archived/nodejs22.18.0/bearsampp.conf diff --git a/bin/nodejs22.18.0/etc/npmrc b/bin/archived/nodejs22.18.0/etc/npmrc similarity index 100% rename from bin/nodejs22.18.0/etc/npmrc rename to bin/archived/nodejs22.18.0/etc/npmrc diff --git a/bin/nodejs22.18.0/etc/npmrc.ber b/bin/archived/nodejs22.18.0/etc/npmrc.ber similarity index 100% rename from bin/nodejs22.18.0/etc/npmrc.ber rename to bin/archived/nodejs22.18.0/etc/npmrc.ber diff --git a/bin/nodejs22.18.0/launch.bat b/bin/archived/nodejs22.18.0/launch.bat similarity index 100% rename from bin/nodejs22.18.0/launch.bat rename to bin/archived/nodejs22.18.0/launch.bat diff --git a/bin/nodejs22.18.0/node_modules/npm/npmrc b/bin/archived/nodejs22.18.0/node_modules/npm/npmrc similarity index 100% rename from bin/nodejs22.18.0/node_modules/npm/npmrc rename to bin/archived/nodejs22.18.0/node_modules/npm/npmrc diff --git a/bin/nodejs22.18.0/node_modules/npm/npmrc.ber b/bin/archived/nodejs22.18.0/node_modules/npm/npmrc.ber similarity index 100% rename from bin/nodejs22.18.0/node_modules/npm/npmrc.ber rename to bin/archived/nodejs22.18.0/node_modules/npm/npmrc.ber diff --git a/build.gradle b/build.gradle index 9e9f2473..26018b40 100644 --- a/build.gradle +++ b/build.gradle @@ -1,23 +1,38 @@ /* - * Bearsampp Module Node.js - Gradle Build + * Bearsampp Module Node.js - Gradle Build (Bruno-style) * - * This is a hybrid build configuration that: - * 1. Imports existing Ant build files for backward compatibility - * 2. Provides modern Gradle features (caching, incremental builds, parallel execution) - * 3. Allows gradual migration from Ant to Gradle + * This is a 100% Gradle build configuration for the Node.js module. + * It handles downloading, extracting, and packaging Node.js releases. + * + * VERSION RESOLUTION STRATEGY: + * 1. Remote modules-untouched nodejs.properties (primary source) + * URL: https://github.com/Bearsampp/modules-untouched/blob/main/modules/nodejs.properties + * 2. Standard URL format construction (fallback) + * + * DOCUMENTATION: + * All build documentation is located in /.gradle-docs/ + * See /.gradle-docs/README.md for complete documentation index * * Usage: * gradle tasks - List all available tasks - * gradle release - Interactive release (prompts for version) - * gradle release "-PbundleVersion=22.13.0" - Non-interactive release + * gradle release -PbundleVersion=24.6.0 - Build release for specific version + * gradle releaseAll - Build all versions * gradle clean - Clean build artifacts * gradle info - Display build information + * gradle verify - Verify build environment + * gradle listVersions - List available versions + * gradle listReleases - List releases from modules-untouched + * gradle checkModulesUntouched - Check modules-untouched integration */ plugins { id 'base' } +// ============================================================================ +// PROJECT CONFIGURATION +// ============================================================================ + // Load build properties def buildProps = new Properties() file('build.properties').withInputStream { buildProps.load(it) } @@ -32,51 +47,224 @@ ext { projectBasedir = projectDir.absolutePath rootDir = projectDir.parent devPath = file("${rootDir}/dev").absolutePath - buildPropertiesFile = file('build.properties').absolutePath // Bundle properties from build.properties bundleName = buildProps.getProperty('bundle.name', 'nodejs') bundleRelease = buildProps.getProperty('bundle.release', '1.0.0') bundleType = buildProps.getProperty('bundle.type', 'bins') bundleFormat = buildProps.getProperty('bundle.format', '7z') + + // Build paths - with configurable base path + def buildPathFromProps = buildProps.getProperty('build.path', '').trim() + def buildPathFromEnv = System.getenv('BEARSAMPP_BUILD_PATH') ?: '' + def defaultBuildPath = "${rootDir}/bearsampp-build" + + buildBasePath = buildPathFromProps ?: (buildPathFromEnv ?: defaultBuildPath) + + // Shared bearsampp-build/tmp structure + buildTmpPath = file("${buildBasePath}/tmp").absolutePath + bundleTmpBuildPath = file("${buildTmpPath}/bundles_build/${bundleType}/${bundleName}").absolutePath + bundleTmpPrepPath = file("${buildTmpPath}/bundles_prep/${bundleType}/${bundleName}").absolutePath + bundleTmpSrcPath = file("${buildTmpPath}/bundles_src").absolutePath + + // Download and extract paths + bundleTmpDownloadPath = file("${buildTmpPath}/downloads/${bundleName}").absolutePath + bundleTmpExtractPath = file("${buildTmpPath}/extract/${bundleName}").absolutePath } +// Align with Bruno: place Gradle's own buildDir under the shared bearsampp-build tmp tree +// This prevents creating a local ./build folder in the repository +buildDir = file("${buildBasePath}/tmp/gradle/${bundleName}") + // Verify dev path exists if (!file(ext.devPath).exists()) { throw new GradleException("Dev path not found: ${ext.devPath}. Please ensure the 'dev' project exists in ${ext.rootDir}") } -// Configure repositories for dependencies +// Repositories repositories { mavenCentral() } // ============================================================================ -// ANT INTEGRATION - Import existing Ant build files +// HELPER FUNCTIONS // ============================================================================ -// Set Ant properties before importing -ant.properties['project.basedir'] = ext.projectBasedir -ant.properties['root.dir'] = ext.rootDir -ant.properties['dev.path'] = ext.devPath -ant.properties['build.properties'] = ext.buildPropertiesFile - -// Load build.properties into Ant -ant.property(file: ext.buildPropertiesFile) - -// Import the main Ant build file -// This preserves all existing Ant functionality -ant.importBuild('build.xml') { antTargetName -> - // Map Ant target names to Gradle task names - // Prefix all with 'ant-' to avoid conflicts - return "ant-${antTargetName}".toString() +// Function to fetch nodejs.properties from modules-untouched repository +def fetchModulesUntouchedProperties() { + def propsUrl = "https://raw.githubusercontent.com/Bearsampp/modules-untouched/main/modules/nodejs.properties" + + println "Fetching nodejs.properties from modules-untouched repository..." + println " URL: ${propsUrl}" + + def tempFile = file("${bundleTmpDownloadPath}/nodejs-untouched.properties") + tempFile.parentFile.mkdirs() + + try { + new URL(propsUrl).withInputStream { input -> + tempFile.withOutputStream { output -> + output << input + } + } + + def props = new Properties() + tempFile.withInputStream { props.load(it) } + + println " ✓ Successfully loaded ${props.size()} versions from modules-untouched" + return props + } catch (Exception e) { + println " ✗ Warning: Could not fetch nodejs.properties from modules-untouched: ${e.message}" + println " Will fall back to standard URL format if needed" + return null + } +} + +// Function to download from modules-untouched repository (or fallback) +def downloadFromModulesUntouched(String version, File destDir) { + println "Checking modules-untouched repository..." + + def untouchedProps = fetchModulesUntouchedProperties() + def untouchedUrl = null + + if (untouchedProps) { + untouchedUrl = untouchedProps.getProperty(version) + if (untouchedUrl) { + println "Found version ${version} in modules-untouched nodejs.properties" + println "Downloading from:" + println " ${untouchedUrl}" + } else { + println "Version ${version} not found in modules-untouched nodejs.properties" + println "Attempting to construct URL based on standard format..." + // Windows x64 standard URL (fallback) — aligns with Bearsampp packaging + untouchedUrl = "https://github.com/Bearsampp/modules-untouched/releases/download/nodejs-${version}/nodejs-${version}-win-x64.7z" + println " ${untouchedUrl}" + } + } else { + println "Could not fetch nodejs.properties, using standard URL format..." + untouchedUrl = "https://github.com/Bearsampp/modules-untouched/releases/download/nodejs-${version}/nodejs-${version}-win-x64.7z" + println " ${untouchedUrl}" + } + + // Determine filename and ensure download dir + def filename = untouchedUrl.substring(untouchedUrl.lastIndexOf('/') + 1) + def downloadDir = file(bundleTmpDownloadPath) + downloadDir.mkdirs() + + def downloadedFile = file("${downloadDir}/${filename}") + + if (!downloadedFile.exists()) { + println " Downloading to: ${downloadedFile}" + try { + new URL(untouchedUrl).withInputStream { input -> + downloadedFile.withOutputStream { output -> + def buffer = new byte[8192] + def bytesRead + while ((bytesRead = input.read(buffer)) != -1) { + output.write(buffer, 0, bytesRead) + } + } + } + println " Download complete from modules-untouched" + } catch (Exception e) { + throw new GradleException(""" + Failed to download from modules-untouched: ${e.message} + + Tried URL: ${untouchedUrl} + + Please verify: + 1. Version ${version} exists in modules-untouched repository + 2. The URL is correct in nodejs.properties or matches format: nodejs-{version}/nodejs-{version}-win-x64.7z + 3. You have internet connectivity + """.stripIndent()) + } + } else { + println " Using cached file: ${downloadedFile}" + } + + return downloadedFile +} + +// Download and extract Node.js binaries +def downloadAndExtractNode(String version, File destDir) { + def downloadedFile = downloadFromModulesUntouched(version, destDir) + + def extractDir = file(bundleTmpExtractPath) + extractDir.mkdirs() + println " Extracting archive..." + def extractPath = file("${extractDir}/${version}") + if (extractPath.exists()) { delete extractPath } + extractPath.mkdirs() + + def filename = downloadedFile.name + + if (filename.endsWith('.7z')) { + def sevenZipPath = find7ZipExecutable() + if (sevenZipPath) { + def command = [ + sevenZipPath.toString(), + 'x', + downloadedFile.absolutePath.toString(), + "-o${extractPath.absolutePath}".toString(), + '-y' + ] + def process = new ProcessBuilder(command as String[]) + .directory(extractPath) + .redirectErrorStream(true) + .start() + + process.inputStream.eachLine { line -> if (line.trim()) println " ${line}" } + def exitCode = process.waitFor() + if (exitCode != 0) { + throw new GradleException("7zip extraction failed with exit code: ${exitCode}") + } + } else { + throw new GradleException("7zip not found. Please install 7zip or extract manually.") + } + } else if (filename.endsWith('.zip')) { + copy { from zipTree(downloadedFile); into extractPath } + } else { + throw new GradleException("Unsupported archive format: ${filename}") + } + + println " Extraction complete" + + def nodeDir = findNodeDirectory(extractPath) + if (!nodeDir) { + throw new GradleException("Could not find Node.js directory in extracted files") + } + + println " Found Node.js directory: ${nodeDir.name}" + println "" + println "NOTE: Version ${version} was sourced from modules-untouched (or fallback URL)." + + return nodeDir +} + +// Find Node.js directory (looks for node.exe) +def findNodeDirectory(File extractPath) { + def hasNodeExe = { File dir -> + new File(dir, 'node.exe').exists() || new File(dir, 'Node.exe').exists() + } + + if (!extractPath?.exists()) { return null } + if (hasNodeExe(extractPath)) { return extractPath } + + File found = null + def stack = new ArrayDeque() + extractPath.listFiles()?.findAll { it.isDirectory() }?.each { stack.push(it) } + while (!stack.isEmpty() && found == null) { + def dir = stack.pop() + if (hasNodeExe(dir)) { found = dir; break } + dir.listFiles()?.findAll { it.isDirectory() }?.each { stack.push(it) } + } + return found } // ============================================================================ -// GRADLE NATIVE TASKS - Modern alternatives and enhancements +// GRADLE TASKS // ============================================================================ -// Task: Display build information +// Info task tasks.register('info') { group = 'help' description = 'Display build configuration information' @@ -84,8 +272,24 @@ tasks.register('info') { def projectName = project.name def projectVersion = project.version def projectDescription = project.description + def projectBasedirValue = projectBasedir + def rootDirValue = rootDir + def devPathValue = devPath + def bundleNameValue = bundleName + def bundleReleaseValue = bundleRelease + def bundleTypeValue = bundleType + def bundleFormatValue = bundleFormat + def buildBasePathValue = buildBasePath + def buildTmpPathValue = buildTmpPath + def bundleTmpPrepPathValue = bundleTmpPrepPath + def bundleTmpBuildPathValue = bundleTmpBuildPath + def bundleTmpSrcPathValue = bundleTmpSrcPath + def bundleTmpDownloadPathValue = bundleTmpDownloadPath + def bundleTmpExtractPathValue = bundleTmpExtractPath + def javaVersion = JavaVersion.current() + def javaHome = System.getProperty('java.home') def gradleVersion = gradle.gradleVersion - def gradleHomeDir = gradle.gradleHomeDir + def gradleHome = gradle.gradleHomeDir doLast { println """ @@ -98,162 +302,476 @@ tasks.register('info') { Description: ${projectDescription} Bundle Properties: - Name: ${bundleName} - Release: ${bundleRelease} - Type: ${bundleType} - Format: ${bundleFormat} + Name: ${bundleNameValue} + Release: ${bundleReleaseValue} + Type: ${bundleTypeValue} + Format: ${bundleFormatValue} Paths: - Project Dir: ${projectBasedir} - Root Dir: ${rootDir} - Dev Path: ${devPath} + Project Dir: ${projectBasedirValue} + Root Dir: ${rootDirValue} + Dev Path: ${devPathValue} + Build Base: ${buildBasePathValue} + Build Tmp: ${buildTmpPathValue} + Tmp Prep: ${bundleTmpPrepPathValue} + Tmp Build: ${bundleTmpBuildPathValue} + Tmp Src: ${bundleTmpSrcPathValue} + Tmp Download: ${bundleTmpDownloadPathValue} + Tmp Extract: ${bundleTmpExtractPathValue} Java: - Version: ${JavaVersion.current()} - Home: ${System.getProperty('java.home')} + Version: ${javaVersion} + Home: ${javaHome} Gradle: Version: ${gradleVersion} - Home: ${gradleHomeDir} + Home: ${gradleHome} Available Task Groups: * build - Build and package tasks - * ant tasks - Legacy Ant tasks (prefixed with 'ant-') * help - Help and information tasks + * verification - Verification tasks Quick Start: gradle tasks - List all available tasks gradle info - Show this information - gradle release - Interactive release build - gradle release "-PbundleVersion=22.13.0" - Non-interactive release + gradle release -PbundleVersion=24.6.0 - Build specific version + gradle releaseAll - Build all versions gradle clean - Clean build artifacts gradle verify - Verify build environment """.stripIndent() } } -// Task: Main release task - supports both interactive and non-interactive modes +// Main release task - build a specific version tasks.register('release') { group = 'build' - description = 'Build release package (interactive or use -PbundleVersion=X.X.X for non-interactive)' + description = 'Build release package for a specific version (use -PbundleVersion=X.X.X or run interactively)' - // Ensure libraries are loaded first - dependsOn 'ant-load.lib' + def versionProperty = project.findProperty('bundleVersion') doLast { - def versionToBuild = project.findProperty('bundleVersion') + def versionToBuild = versionProperty + + if (!versionToBuild) { + // Interactive prompt + def availableVersions = getAvailableVersions() + if (availableVersions.isEmpty()) { + throw new GradleException("No versions found in bin/ directory") + } - if (versionToBuild) { - // Non-interactive mode with specified version + println "" println "=".multiply(70) - println "Building release for ${bundleName} version ${versionToBuild}..." + println "Interactive Release Mode" println "=".multiply(70) + println "" + println "Available versions:" + + def binDir = file("${projectDir}/bin") + def archivedDir = file("${projectDir}/bin/archived") + + availableVersions.eachWithIndex { version, index -> + def location = "" + if (binDir.exists() && file("${binDir}/${bundleName}${version}").exists()) { + location = "[bin]" + } else if (archivedDir.exists() && file("${archivedDir}/${bundleName}${version}").exists()) { + location = "[bin/archived]" + } + println " ${(index + 1).toString().padLeft(2)}. ${version.padRight(15)} ${location}" + } + println "" + println "Enter version to build (index or version string):" + println "" - def bundlePath = file("${projectDir}/bin/${bundleName}${versionToBuild}") + def input = null + try { + def reader = new BufferedReader(new InputStreamReader(System.in)) + input = reader.readLine() + } catch (Exception e) { + throw new GradleException(""" + Failed to read input. Please use non-interactive mode: + gradle release -PbundleVersion=X.X.X + + Available versions: ${availableVersions.join(', ')} + """.stripIndent()) + } - if (!bundlePath.exists()) { - def availableVersions = file("${projectDir}/bin").listFiles() - .findAll { it.isDirectory() && it.name.startsWith(bundleName) } - .collect { " - " + it.name.replace(bundleName, '') } - .join('\n') + if (!input || input.trim().isEmpty()) { + throw new GradleException(""" + No version selected. Please use non-interactive mode: + gradle release -PbundleVersion=X.X.X - throw new GradleException("Bundle version not found: ${bundlePath}\n\nAvailable versions in bin/:\n${availableVersions}") + Available versions: ${availableVersions.join(', ')} + """.stripIndent()) } - println "Bundle path: ${bundlePath}" - println "" + def cleaned = input.trim() + if (cleaned.isInteger()) { + def idx = cleaned.toInteger() + if (idx < 1 || idx > availableVersions.size()) { + throw new GradleException(""" + Invalid selection index: ${cleaned} + + Please choose a number between 1 and ${availableVersions.size()} or enter a version string. + """.stripIndent()) + } + versionToBuild = availableVersions[idx - 1] + } else { + versionToBuild = cleaned + if (!availableVersions.contains(versionToBuild)) { + throw new GradleException(""" + Invalid version: ${versionToBuild} + + Please choose from available versions: + ${availableVersions.collect { " - ${it}" }.join('\n')} + """.stripIndent()) + } + } - // Execute Ant command directly to avoid Gradle Ant integration issues - def antCommand = ["cmd", "/c", "ant", "release", "-Dinput.bundle=${versionToBuild}"] - println "Executing: ant release -Dinput.bundle=${versionToBuild}" println "" + println "Selected version: ${versionToBuild}" + } - def process = antCommand.execute(null, projectDir) - process.consumeProcessOutput(System.out, System.err) - def exitCode = process.waitFor() + println "" + println "=".multiply(70) + println "Building ${bundleName} ${versionToBuild}" + println "=".multiply(70) + println "" - if (exitCode != 0) { - throw new GradleException("Ant release failed with exit code: ${exitCode}") + // Validate version exists in bin or archived + def bundlePath = file("${projectDir}/bin/${bundleName}${versionToBuild}") + if (!bundlePath.exists()) { + bundlePath = file("${projectDir}/bin/archived/${bundleName}${versionToBuild}") + if (!bundlePath.exists()) { + throw new GradleException("Bundle version not found in bin/ or bin/archived/\n\nAvailable versions:\n${getAvailableVersions().collect { " - ${it}" }.join('\n')}") } + } - println "" - println "=".multiply(70) - println "[SUCCESS] Release build completed successfully for version ${versionToBuild}" - println "=".multiply(70) + println "Bundle path: ${bundlePath}" + println "" + + def bundleFolder = bundlePath.name + def bundleVersion = bundleFolder.replace(bundleName, '') + + def bundleSrcDest = bundlePath + def bundleSrcFinal = bundleSrcDest + + def nodeExe = file("${bundleSrcFinal}/node.exe") + if (!nodeExe.exists()) { + // Try cached extract first + def tmpExtractPath = file("${bundleTmpExtractPath}/${bundleVersion}") + def tmpNodeDir = findNodeDirectory(tmpExtractPath) + + if (tmpNodeDir && tmpNodeDir.exists()) { + println "Using cached Node.js binaries from bearsampp-build/tmp" + bundleSrcFinal = tmpNodeDir + } else { + println "" + println "Node.js binaries not found" + println "Downloading Node.js ${bundleVersion}..." + println "" + + try { + bundleSrcFinal = downloadAndExtractNode(bundleVersion, file(bundleTmpExtractPath)) + } catch (Exception e) { + throw new GradleException(""" + Failed to download Node.js binaries: ${e.message} + + You can manually download and extract Node.js binaries to: + ${bundleSrcDest}/ + + Or check that version ${bundleVersion} exists in modules-untouched nodejs.properties + """.stripIndent()) + } + } + } + + nodeExe = file("${bundleSrcFinal}/node.exe") + if (!nodeExe.exists()) { + throw new GradleException("node.exe not found at ${nodeExe}") + } + + println "Source folder: ${bundleSrcFinal}" + println "" + + // Prep directory + def prepPath = file("${bundleTmpPrepPath}/${bundleName}${bundleVersion}") + if (prepPath.exists()) { delete prepPath } + prepPath.mkdirs() + + // Copy Node.js files from extracted/downloaded location + println "Copying Node.js files..." + copy { from bundleSrcFinal; into prepPath } + + // Overlay files from bin bundle directory + println "Overlaying bundle files from bin directory..." + copy { from bundleSrcDest; into prepPath } + + println "" + println "Copying to bundles_build directory..." + def buildPathOut = file("${bundleTmpBuildPath}/${bundleName}${bundleVersion}") + if (buildPathOut.exists()) { delete buildPathOut } + buildPathOut.mkdirs() + copy { from prepPath; into buildPathOut } + println "Non-zip version available at: ${buildPathOut}" + + println "" + println "Preparing archive..." + + // Output path bearsampp-build/{type}/{name}/{release} + def buildPath = file(buildBasePath) + def buildBinsPath = file("${buildPath}/${bundleType}/${bundleName}/${bundleRelease}") + buildBinsPath.mkdirs() + + def destFile = file("${buildBinsPath}/bearsampp-${bundleName}-${bundleVersion}-${bundleRelease}") + + if (bundleFormat == '7z') { + def archiveFile = file("${destFile}.7z") + if (archiveFile.exists()) { delete archiveFile } + + println "Compressing ${bundleName}${bundleVersion} to ${archiveFile.name}..." + + def sevenZipExe = find7ZipExecutable() + if (!sevenZipExe) { throw new GradleException("7-Zip not found. Please install 7-Zip or set 7Z_HOME environment variable.") } + println "Using 7-Zip: ${sevenZipExe}" + + def command = [ sevenZipExe, 'a', '-t7z', archiveFile.absolutePath.toString(), '.' ] + def process = new ProcessBuilder(command as String[]) + .directory(prepPath) + .redirectErrorStream(true) + .start() + process.inputStream.eachLine { line -> if (line.trim()) println " ${line}" } + def exitCode = process.waitFor() + if (exitCode != 0) { throw new GradleException("7zip compression failed with exit code: ${exitCode}") } + + println "Archive created: ${archiveFile}" + println "Generating hash files..." + generateHashFiles(archiveFile) } else { - // Interactive mode - call Ant release target which will prompt for input + def archiveFile = file("${destFile}.zip") + if (archiveFile.exists()) { delete archiveFile } + + println "Compressing ${bundleName}${bundleVersion} to ${archiveFile.name}..." + task("zipArchive_${bundleVersion}", type: Zip) { + from prepPath + destinationDirectory = archiveFile.parentFile + archiveFileName = archiveFile.name + }.execute() + + println "Archive created: ${archiveFile}" + println "Generating hash files..." + generateHashFiles(archiveFile) + } + + println "" + println "=".multiply(70) + println "[SUCCESS] Release build completed successfully for version ${versionToBuild}" + println "Output directory: ${buildPathOut}" + println "Archive: ${destFile}.${bundleFormat}" + println "=".multiply(70) + } +} + +// Find 7-Zip executable +def find7ZipExecutable() { + def sevenZipHome = System.getenv('7Z_HOME') + if (sevenZipHome) { + def exe = file("${sevenZipHome}/7z.exe") + if (exe.exists()) { return exe.absolutePath } + } + def commonPaths = [ + 'C:/Program Files/7-Zip/7z.exe', + 'C:/Program Files (x86)/7-Zip/7z.exe', + 'D:/Program Files/7-Zip/7z.exe', + 'D:/Program Files (x86)/7-Zip/7z.exe' + ] + for (path in commonPaths) { + def exe = file(path) + if (exe.exists()) { return exe.absolutePath } + } + try { + def process = ['where', '7z.exe'].execute() + process.waitFor() + if (process.exitValue() == 0) { + def output = process.text.trim() + if (output) { return output.split('\n')[0].trim() } + } + } catch (Exception e) { } + return null +} + +// Generate hash files for an archive +def generateHashFiles(File file) { + if (!file.exists()) { throw new GradleException("File not found for hashing: ${file}") } + + def md5File = new File("${file.absolutePath}.md5") + def md5Hash = calculateHash(file, 'MD5') + md5File.text = "${md5Hash} ${file.name}\n" + println " Created: ${md5File.name}" + + def sha1File = new File("${file.absolutePath}.sha1") + def sha1Hash = calculateHash(file, 'SHA-1') + sha1File.text = "${sha1Hash} ${file.name}\n" + println " Created: ${sha1File.name}" + + def sha256File = new File("${file.absolutePath}.sha256") + def sha256Hash = calculateHash(file, 'SHA-256') + sha256File.text = "${sha256Hash} ${file.name}\n" + println " Created: ${sha256File.name}" + + def sha512File = new File("${file.absolutePath}.sha512") + def sha512Hash = calculateHash(file, 'SHA-512') + sha512File.text = "${sha512Hash} ${file.name}\n" + println " Created: ${sha512File.name}" +} + +// Calculate hash +def calculateHash(File file, String algorithm) { + def digest = java.security.MessageDigest.getInstance(algorithm) + file.withInputStream { stream -> + def buffer = new byte[8192] + def bytesRead + while ((bytesRead = stream.read(buffer)) != -1) { + digest.update(buffer, 0, bytesRead) + } + } + return digest.digest().collect { String.format('%02x', it) }.join('') +} + +// Get available versions from bin and bin/archived +def getAvailableVersions() { + def versions = [] + + def binDir = file("${projectDir}/bin") + if (binDir.exists()) { + def binVersions = binDir.listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) && it.name != 'archived' } + ?.collect { it.name.replace(bundleName, '') } ?: [] + versions.addAll(binVersions) + } + + def archivedDir = file("${projectDir}/bin/archived") + if (archivedDir.exists()) { + def archivedVersions = archivedDir.listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) } + ?.collect { it.name.replace(bundleName, '') } ?: [] + versions.addAll(archivedVersions) + } + + return versions.unique().sort() +} + +// Build all available versions (prep only) +tasks.register('releaseAll') { + group = 'build' + description = 'Build release packages for all available versions in bin/ directory' + + doLast { + def binDir = file("${projectDir}/bin") + if (!binDir.exists()) { throw new GradleException("bin/ directory not found") } + + def versions = getAvailableVersions() + if (versions.isEmpty()) { throw new GradleException("No versions found in bin/ directory") } + + println "" + println "=".multiply(70) + println "Building releases for ${versions.size()} ${bundleName} versions" + println "=".multiply(70) + println "" + + def successCount = 0 + def failedVersions = [] + + versions.each { version -> println "=".multiply(70) - println "Starting interactive release build..." - println "You will be prompted to enter the bundle version." + println "[${successCount + 1}/${versions.size()}] Building ${bundleName} ${version}..." println "=".multiply(70) - println "" - // Call the imported ant-release target for interactive mode - tasks.getByName('ant-release').actions.each { action -> - action.execute(tasks.getByName('ant-release')) + try { + def bundlePath = file("${projectDir}/bin/${bundleName}${version}") + if (!bundlePath.exists()) { throw new GradleException("Bundle path not found: ${bundlePath}") } + + println "Bundle path: ${bundlePath}" + println "" + + def bundleFolder = bundlePath.name + def bundleVersion = bundleFolder.replace(bundleName, '') + def bundleSrcDest = bundlePath + + def nodeExe = file("${bundleSrcDest}/node.exe") + if (!nodeExe.exists()) { throw new GradleException("node.exe not found at ${nodeExe}") } + + println "Source folder: ${bundleSrcDest}" + println "" + + def prepPath = file("${bundleTmpPrepPath}/${bundleName}${bundleVersion}") + if (prepPath.exists()) { delete prepPath } + prepPath.mkdirs() + + println "Copying Node.js files..." + copy { from bundleSrcDest; into prepPath } + + println "" + println "[SUCCESS] ${bundleName} ${version} completed" + println "Output: ${prepPath}" + successCount++ + + } catch (Exception e) { + println "" + println "[FAILED] ${bundleName} ${version}: ${e.message}" + failedVersions.add(version) } println "" - println "=".multiply(70) - println "[SUCCESS] Release build completed" - println "=".multiply(70) + } + + println "=".multiply(70) + println "Build Summary" + println "=".multiply(70) + println "Total versions: ${versions.size()}" + println "Successful: ${successCount}" + println "Failed: ${failedVersions.size()}" + + if (!failedVersions.isEmpty()) { + println "" + println "Failed versions:" + failedVersions.each { v -> println " - ${v}" } + } + + println "=".multiply(70) + + if (failedVersions.isEmpty()) { + println "[SUCCESS] All versions built successfully!" + } else { + throw new GradleException("${failedVersions.size()} version(s) failed to build") } } } -// Task: Enhanced clean task +// Clean task enhancement (only Gradle artifacts for this script) tasks.named('clean') { group = 'build' description = 'Clean build artifacts and temporary files' - doLast { - // Clean Gradle build directory def buildDir = file("${projectDir}/build") - if (buildDir.exists()) { - delete buildDir - } - - // Clean any temporary directories that might be created - // Use manual directory traversal to avoid fileTree default excludes issue - def tmpDirs = [] - projectDir.eachFileRecurse { file -> - if (file.isDirectory() && (file.name == 'tmp' || file.name == '.tmp')) { - tmpDirs.add(file) - } - } - tmpDirs.each { dir -> - if (dir.exists()) { - delete dir - } - } - + if (buildDir.exists()) { delete buildDir } println "[SUCCESS] Build artifacts cleaned" } } -// Task: Verify build environment +// Verify environment tasks.register('verify') { group = 'verification' description = 'Verify build environment and dependencies' - doLast { println "Verifying build environment for module-nodejs..." - def checks = [:] - - // Check Java version def javaVersion = JavaVersion.current() checks['Java 8+'] = javaVersion >= JavaVersion.VERSION_1_8 - - // Check required files - checks['build.xml'] = file('build.xml').exists() checks['build.properties'] = file('build.properties').exists() - checks['releases.properties'] = file('releases.properties').exists() - - // Check dev directory and required build files checks['dev directory'] = file(devPath).exists() - checks['build-commons.xml'] = file("${devPath}/build/build-commons.xml").exists() - checks['build-bundle.xml'] = file("${devPath}/build/build-bundle.xml").exists() + checks['bin directory'] = file("${projectDir}/bin").exists() + if (bundleFormat == '7z') { checks['7-Zip'] = find7ZipExecutable() != null } println "\nEnvironment Check Results:" println "-".multiply(60) @@ -267,8 +785,8 @@ tasks.register('verify') { if (allPassed) { println "\n[SUCCESS] All checks passed! Build environment is ready." println "\nYou can now run:" - println " gradle release - Interactive release" - println " gradle release \"-PbundleVersion=22.13.0\" - Non-interactive release" + println " gradle release -PbundleVersion=24.6.0 - Build release for version" + println " gradle listVersions - List available versions" } else { println "\n[WARNING] Some checks failed. Please review the requirements." throw new GradleException("Build environment verification failed") @@ -276,92 +794,142 @@ tasks.register('verify') { } } -// Task: List all bundle versions from releases.properties +// List releases from modules-untouched tasks.register('listReleases') { group = 'help' - description = 'List all available releases from releases.properties' - + description = 'List all available releases from modules-untouched nodejs.properties' doLast { - def releasesFile = file('releases.properties') - if (!releasesFile.exists()) { - println "releases.properties not found" + def props = fetchModulesUntouchedProperties() + if (!props) { + println "\n[WARNING] Could not fetch modules-untouched nodejs.properties." + println "No release information available." return } - - def releases = new Properties() - releasesFile.withInputStream { releases.load(it) } - - println "\nAvailable Node.js Releases:" + println "\nAvailable Node.js Releases (modules-untouched):" println "-".multiply(80) - releases.sort { it.key }.each { version, url -> - println " ${version.padRight(10)} -> ${url}" - } + props.sort { a, b -> a.key <=> b.key }.each { version, url -> println " ${version.padRight(10)} -> ${url}" } println "-".multiply(80) - println "Total releases: ${releases.size()}" + println "Total releases: ${props.size()}" } } -// Task: List available bundle versions in bin directory +// List versions available locally tasks.register('listVersions') { group = 'help' - description = 'List all available bundle versions in bin/ directory' - + description = 'List all available bundle versions in bin/ and bin/archived/ directories' doLast { - def binDir = file("${projectDir}/bin") - if (!binDir.exists()) { - println "bin/ directory not found" - return - } - - def versions = binDir.listFiles() - .findAll { it.isDirectory() && it.name.startsWith(bundleName) } - .collect { it.name.replace(bundleName, '') } - .sort() + def versions = getAvailableVersions() + if (versions.isEmpty()) { println "\nNo versions found in bin/ or bin/archived/ directories"; return } - println "\nAvailable ${bundleName} versions in bin/:" + println "\nAvailable ${bundleName} versions:" println "-".multiply(60) + + def binDir = file("${projectDir}/bin") + def archivedDir = file("${projectDir}/bin/archived") + versions.each { version -> - println " ${version}" + def location = "" + if (binDir.exists() && file("${binDir}/${bundleName}${version}").exists()) { location = "[bin]" } + else if (archivedDir.exists() && file("${archivedDir}/${bundleName}${version}").exists()) { location = "[bin/archived]" } + println " ${version.padRight(15)} ${location}" } println "-".multiply(60) println "Total versions: ${versions.size()}" - println "\nTo build a specific version:" - println " gradle release \"-PbundleVersion=${versions.last()}\"" + if (!versions.isEmpty()) { + println "\nTo build a specific version:" + println " gradle release -PbundleVersion=${versions.last()}" + } } } -// Task: Validate build.properties +// Validate build.properties tasks.register('validateProperties') { group = 'verification' description = 'Validate build.properties configuration' - doLast { println "Validating build.properties..." - def required = ['bundle.name', 'bundle.release', 'bundle.type', 'bundle.format'] def missing = [] - - required.each { prop -> - if (!buildProps.containsKey(prop) || buildProps.getProperty(prop).trim().isEmpty()) { - missing.add(prop) - } - } - + required.each { prop -> if (!buildProps.containsKey(prop) || buildProps.getProperty(prop).trim().isEmpty()) { missing.add(prop) } } if (missing.isEmpty()) { println "[SUCCESS] All required properties are present:" - required.each { prop -> - println " ${prop} = ${buildProps.getProperty(prop)}" - } + required.each { prop -> println " ${prop} = ${buildProps.getProperty(prop)}" } } else { println "[ERROR] Missing required properties:" - missing.each { prop -> - println " - ${prop}" - } + missing.each { prop -> println " - ${prop}" } throw new GradleException("build.properties validation failed") } } } +// Check modules-untouched integration +tasks.register('checkModulesUntouched') { + group = 'verification' + description = 'Check modules-untouched repository integration and available versions' + doLast { + println "" + println "=".multiply(70) + println "Modules-Untouched Integration Check" + println "=".multiply(70) + println "" + + def propsUrl = "https://raw.githubusercontent.com/Bearsampp/modules-untouched/main/modules/nodejs.properties" + println "Repository URL:" + println " ${propsUrl}" + println "" + + println "Fetching nodejs.properties from modules-untouched..." + def untouchedProps = fetchModulesUntouchedProperties() + + if (untouchedProps) { + println "" + println "=".multiply(70) + println "Available Versions in modules-untouched" + println "=".multiply(70) + + def sortedVersions = untouchedProps.sort { a, b -> + def aParts = a.key.tokenize('.') + def bParts = b.key.tokenize('.') + for (int i = 0; i < Math.min(aParts.size(), bParts.size()); i++) { + def aNum = aParts[i].toInteger() + def bNum = bParts[i].toInteger() + if (aNum != bNum) return aNum <=> bNum + } + return aParts.size() <=> bParts.size() + } + + sortedVersions.each { version, url -> println " ${version.padRight(10)}" } + + println "=".multiply(70) + println "Total versions: ${untouchedProps.size()}" + println "" + println "" + println "=".multiply(70) + println "[SUCCESS] modules-untouched integration is working" + println "=".multiply(70) + println "" + println "Version Resolution Strategy:" + println " 1. Check modules-untouched nodejs.properties (remote)" + println " 2. Construct standard URL format (fallback)" + println "" + println "Documentation: /.gradle-docs/MODULES_UNTOUCHED_INTEGRATION.md" + } else { + println "" + println "=".multiply(70) + println "[WARNING] Could not fetch nodejs.properties from modules-untouched" + println "=".multiply(70) + println "" + println "This may be due to:" + println " - Network connectivity issues" + println " - Repository access problems" + println " - File not available at expected location" + println "" + println "The build system will fall back to:" + println " 1. Standard URL format construction" + } + } +} + // ============================================================================ // BUILD LIFECYCLE HOOKS // ============================================================================ @@ -369,7 +937,7 @@ tasks.register('validateProperties') { gradle.taskGraph.whenReady { graph -> println """ ================================================================ - Bearsampp Module Node.js - Gradle + Ant Hybrid Build + Bearsampp Module Node.js - Gradle Build ================================================================ """.stripIndent() } From 47fd6eb498c2abb3983da9c422b038d0e4af1f4c Mon Sep 17 00:00:00 2001 From: Bear Date: Sun, 16 Nov 2025 02:03:47 -0600 Subject: [PATCH 3/4] fixes version folder not being used --- .gradle-docs/PACKAGING.md | 54 +++++++++++++++++++++++++++++++++++++++ .gradle-docs/README.md | 13 ++++++++++ README.md | 10 ++++++++ build.gradle | 16 ++++++++---- 4 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 .gradle-docs/PACKAGING.md create mode 100644 .gradle-docs/README.md diff --git a/.gradle-docs/PACKAGING.md b/.gradle-docs/PACKAGING.md new file mode 100644 index 00000000..065b06e7 --- /dev/null +++ b/.gradle-docs/PACKAGING.md @@ -0,0 +1,54 @@ +### Packaging and Archive Layout + +This module’s Gradle build produces archives that include the top-level version folder, matching the behavior used by the Bruno module. + +Example structure for version 24.6.0: + +``` +bearsampp-nodejs-24.6.0-2025.8.21.7z +└─ nodejs24.6.0/ + ├─ node.exe + ├─ npm + ├─ etc/ + └─ ... +``` + +Key implementation detail in `build.gradle`: + +- The compression is run from the parent directory of the prep folder and the folder name (e.g. `nodejs24.6.0`) is passed explicitly to the archiver. This guarantees the archive contains the version folder at the root. + +7‑Zip flow: + +``` +ProcessBuilder([7z.exe, 'a', '-t7z', , ]) + .directory() +``` + +Zip flow (Gradle `Zip` task): + +``` +from(prepPath.parentFile) { + include "${prepPath.name}/**" +} +``` + +### How to verify locally + +- Build a release for a specific version: + - `gradle release -PbundleVersion=24.6.0` + +- Locate the output archive under: + - `////` + - Example: `../bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z` + +- Verify with 7‑Zip (Windows): + - Command prompt: `7z l bearsampp-nodejs-24.6.0-2025.8.21.7z | findstr nodejs24.6.0` + - You should see entries starting with `nodejs24.6.0/`. + +- Verify with any Zip tool (if `bundle.format=zip`): + - The first entry should be `nodejs/`. + +### Notes + +- The legacy Ant build (`build.xml`) delegates compression to `dev/build/build-bundle.xml`. The Gradle build is the primary supported path for this module and enforces the folder-in-archive layout directly in this repository. +- Packaging format is controlled by `bundle.format` in `build.properties` (`7z` or `zip`). diff --git a/.gradle-docs/README.md b/.gradle-docs/README.md new file mode 100644 index 00000000..5b300d3a --- /dev/null +++ b/.gradle-docs/README.md @@ -0,0 +1,13 @@ +Gradle Build Documentation (module-nodejs) + +This folder contains additional documentation for the Gradle build used by the Bearsampp Node.js module. + +Contents: + +- PACKAGING.md — Archive layout, how compression works, and how to verify results + +Quick links: + +- Build tasks overview is in the repository README.md under the "Build (Gradle)" section. +- Typical command to build a specific version: + - gradle release -PbundleVersion=24.6.0 diff --git a/README.md b/README.md index ba3e6985..e371f6b8 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,16 @@ Quick commands: - Build all local versions (prep/copy flow): `gradle releaseAll` - Clean: `gradle clean` +Archive layout assurance: + +- The packaged archive includes the top-level version folder (e.g., `nodejs24.6.0/`). +- Example: `bearsampp-nodejs-24.6.0-2025.8.21.7z` contains `nodejs24.6.0/` as the root, with files inside it. + +Verify quickly after a build: + +- 7z: `7z l bearsampp-nodejs--.7z | findstr nodejs` should list the folder. +- Zip: Inspect contents; the first entry should be `nodejs/`. + Version resolution strategy: 1. Remote `modules-untouched` `nodejs.properties` diff --git a/build.gradle b/build.gradle index 26018b40..a9b92e0e 100644 --- a/build.gradle +++ b/build.gradle @@ -529,15 +529,18 @@ tasks.register('release') { def archiveFile = file("${destFile}.7z") if (archiveFile.exists()) { delete archiveFile } - println "Compressing ${bundleName}${bundleVersion} to ${archiveFile.name}..." + println "Compressing (including top-level folder) ${bundleName}${bundleVersion} to ${archiveFile.name}..." def sevenZipExe = find7ZipExecutable() if (!sevenZipExe) { throw new GradleException("7-Zip not found. Please install 7-Zip or set 7Z_HOME environment variable.") } println "Using 7-Zip: ${sevenZipExe}" - def command = [ sevenZipExe, 'a', '-t7z', archiveFile.absolutePath.toString(), '.' ] + // IMPORTANT: run from the parent directory and add the folder name explicitly + def parentDir = prepPath.parentFile + def folderName = prepPath.name + def command = [ sevenZipExe, 'a', '-t7z', archiveFile.absolutePath.toString(), folderName ] def process = new ProcessBuilder(command as String[]) - .directory(prepPath) + .directory(parentDir) .redirectErrorStream(true) .start() process.inputStream.eachLine { line -> if (line.trim()) println " ${line}" } @@ -551,9 +554,12 @@ tasks.register('release') { def archiveFile = file("${destFile}.zip") if (archiveFile.exists()) { delete archiveFile } - println "Compressing ${bundleName}${bundleVersion} to ${archiveFile.name}..." + println "Compressing (including top-level folder) ${bundleName}${bundleVersion} to ${archiveFile.name}..." + // Use Zip task but include the folder itself so the archive contains nodejs{version}/... task("zipArchive_${bundleVersion}", type: Zip) { - from prepPath + from(prepPath.parentFile) { + include "${prepPath.name}/**" + } destinationDirectory = archiveFile.parentFile archiveFileName = archiveFile.name }.execute() From 99eaf4b148ec18345e200fb05199734b91eb66e7 Mon Sep 17 00:00:00 2001 From: Bear Date: Mon, 17 Nov 2025 06:43:28 -0600 Subject: [PATCH 4/4] remove ant left overs --- .gradle-docs/MIGRATION.md | 365 +++++++++++++++++++++++++ .gradle-docs/PACKAGING.md | 392 ++++++++++++++++++++++++--- .gradle-docs/README.md | 501 ++++++++++++++++++++++++++++++++++- README.md | 84 +++--- build.xml | 47 ---- module-nodejs.RELEASE.launch | 19 -- 6 files changed, 1262 insertions(+), 146 deletions(-) create mode 100644 .gradle-docs/MIGRATION.md delete mode 100644 build.xml delete mode 100644 module-nodejs.RELEASE.launch diff --git a/.gradle-docs/MIGRATION.md b/.gradle-docs/MIGRATION.md new file mode 100644 index 00000000..50d99164 --- /dev/null +++ b/.gradle-docs/MIGRATION.md @@ -0,0 +1,365 @@ +# Migration Guide: Ant to Gradle + +This document provides guidance for migrating from the legacy Ant build system to the new Gradle build system. + +## Overview + +The Bearsampp Module Node.js project has been fully migrated from Apache Ant to Gradle. The Gradle build system provides better performance, modern tooling, and improved maintainability. + +## What Changed + +### Removed Files + +The following files have been **removed** from the repository: + +| File | Status | Notes | +|-------------------------------|-----------|------------------------------------------| +| `build.xml` | ✗ Removed | Replaced by `build.gradle` | +| `module-nodejs.RELEASE.launch`| ✗ Removed | Eclipse Ant launcher, no longer needed | + +**Note**: These legacy Ant build files have been completely removed. The project now uses pure Gradle for all build operations. + +### New Files + +| File | Purpose | +|-------------------------------|----------------------------------------------| +| `build.gradle` | Main Gradle build script | +| `settings.gradle` | Gradle project settings | +| `gradle.properties` | Gradle configuration properties | +| `.gradle-docs/` | Gradle build documentation directory | +| `.gradle-docs/README.md` | Main build documentation | +| `.gradle-docs/PACKAGING.md` | Packaging and archive structure guide | +| `.gradle-docs/MIGRATION.md` | This migration guide | + +## Command Mapping + +### Basic Commands + +| Ant Command | Gradle Command | Notes | +|--------------------------------------|---------------------------------------------|------------------------------------------| +| `ant release` | `gradle release` | Interactive mode (prompts for version) | +| `ant release -Dinput.bundle=24.6.0` | `gradle release -PbundleVersion=24.6.0` | Non-interactive mode | +| `ant clean` | `gradle clean` | Clean build artifacts | + +### New Commands + +Gradle provides additional commands not available in Ant: + +| Command | Description | +|-------------------------------|----------------------------------------------| +| `gradle info` | Display build configuration information | +| `gradle tasks` | List all available tasks | +| `gradle verify` | Verify build environment and dependencies | +| `gradle listVersions` | List available versions in bin/ | +| `gradle listReleases` | List releases from modules-untouched | +| `gradle releaseAll` | Build all versions in bin/ | +| `gradle validateProperties` | Validate build.properties configuration | +| `gradle checkModulesUntouched`| Check modules-untouched integration | + +## Key Differences + +### 1. Build File Format + +**Ant (build.xml):** +```xml + + + + + + + +``` + +**Gradle (build.gradle):** +```groovy +tasks.register('release') { + group = 'build' + description = 'Build release package' + + doLast { + copy { + from nodeExtractPath + into bundlePrepPath + } + } +} +``` + +### 2. Property Handling + +**Ant:** +```xml + + +``` + +**Gradle:** +```groovy +def buildProps = new Properties() +file('build.properties').withInputStream { buildProps.load(it) } + +ext { + bundleName = buildProps.getProperty('bundle.name', 'nodejs') +} +``` + +### 3. Task Execution + +**Ant:** +- Tasks defined as `` elements +- Dependencies specified with `depends` attribute +- Sequential execution by default + +**Gradle:** +- Tasks defined with `tasks.register()` +- Dependencies specified with `dependsOn` +- Parallel execution possible +- Incremental builds supported + +### 4. Dependency Management + +**Ant:** +- Manual download and extraction +- No built-in dependency management +- Custom scripts required + +**Gradle:** +- Built-in dependency management +- Automatic download and caching +- Repository support (Maven, etc.) + +### 5. IDE Integration + +**Ant:** +- Limited IDE support +- Manual configuration required +- Eclipse `.launch` files needed + +**Gradle:** +- Excellent IDE support (IntelliJ IDEA, Eclipse, VS Code) +- Automatic project import +- No manual configuration needed + +## Migration Steps + +If you're migrating from Ant to Gradle in your own project: + +### Step 1: Install Gradle + +```bash +# Windows (Chocolatey) +choco install gradle + +# macOS (Homebrew) +brew install gradle + +# Linux (SDKMAN!) +sdk install gradle + +# Verify installation +gradle --version +``` + +### Step 2: Create build.gradle + +Create a new `build.gradle` file based on the current implementation. See [build.gradle](../build.gradle) for reference. + +### Step 3: Create settings.gradle + +```groovy +rootProject.name = 'module-nodejs' +``` + +### Step 4: Test the Build + +```bash +# Verify environment +gradle verify + +# List available tasks +gradle tasks + +# Test a build +gradle release -PbundleVersion=24.6.0 +``` + +### Step 5: Update Documentation + +Update your README.md and other documentation to reference Gradle commands instead of Ant. + +### Step 6: Deprecate Ant Files + +Mark `build.xml` and related files as deprecated. You can keep them for reference but note they're no longer used. + +## Troubleshooting Migration Issues + +### Issue: "Cannot find dev project" + +**Ant Behavior:** +```xml + + +``` + +**Gradle Behavior:** +```groovy +ext { + devPath = file("${rootDir}/dev").absolutePath +} + +if (!file(ext.devPath).exists()) { + throw new GradleException("Dev path not found: ${ext.devPath}") +} +``` + +**Solution:** +Ensure the `dev` project exists in the parent directory, or modify the build script if your structure is different. + +### Issue: "Property not found" + +**Ant Behavior:** +Properties loaded from `build.properties` are automatically available. + +**Gradle Behavior:** +Properties must be explicitly loaded: + +```groovy +def buildProps = new Properties() +file('build.properties').withInputStream { buildProps.load(it) } +``` + +**Solution:** +Check that `build.properties` exists and properties are loaded correctly. + +### Issue: "Task not found" + +**Ant Behavior:** +```bash +ant release +``` + +**Gradle Behavior:** +```bash +gradle release +``` + +**Solution:** +Use `gradle tasks` to list all available tasks and verify the task name. + +## Benefits of Gradle + +### 1. Performance + +- **Incremental builds**: Only rebuild what changed +- **Build cache**: Reuse outputs from previous builds +- **Parallel execution**: Run tasks in parallel when possible + +### 2. Maintainability + +- **Groovy DSL**: More readable and maintainable than XML +- **Modular**: Easy to split build logic into multiple files +- **Reusable**: Share build logic across projects + +### 3. Tooling + +- **IDE integration**: Excellent support in IntelliJ IDEA, Eclipse, VS Code +- **Build scans**: Detailed build performance analysis +- **Dependency insight**: Understand dependency trees + +### 4. Ecosystem + +- **Plugins**: Thousands of plugins available +- **Community**: Large and active community +- **Documentation**: Comprehensive official documentation + +## Best Practices + +### 1. Use Gradle Wrapper (Optional) + +While this project doesn't include the Gradle Wrapper, you can add it: + +```bash +gradle wrapper --gradle-version 8.5 +``` + +This creates: +- `gradlew` (Unix) +- `gradlew.bat` (Windows) +- `gradle/wrapper/` directory + +Benefits: +- Ensures consistent Gradle version across team +- No need to install Gradle separately + +### 2. Organize Build Logic + +Keep build logic organized: +- Main build logic in `build.gradle` +- Configuration in `build.properties` +- Documentation in `.gradle-docs/` + +### 3. Use Task Groups + +Organize tasks into logical groups: + +```groovy +tasks.register('myTask') { + group = 'build' // or 'verification', 'help', etc. + description = 'My task description' +} +``` + +### 4. Leverage Gradle Features + +- Use `ext` for shared properties +- Use `doFirst` and `doLast` for task actions +- Use `dependsOn` for task dependencies +- Use `mustRunAfter` for task ordering + +## Additional Resources + +### Official Documentation + +- [Gradle User Manual](https://docs.gradle.org/current/userguide/userguide.html) +- [Gradle DSL Reference](https://docs.gradle.org/current/dsl/) +- [Gradle Build Language Reference](https://docs.gradle.org/current/userguide/writing_build_scripts.html) + +### Tutorials + +- [Getting Started with Gradle](https://docs.gradle.org/current/userguide/getting_started.html) +- [Migrating from Ant to Gradle](https://docs.gradle.org/current/userguide/migrating_from_ant.html) +- [Gradle Best Practices](https://docs.gradle.org/current/userguide/authoring_maintainable_build_scripts.html) + +### Bearsampp Resources + +- [Bearsampp Project](https://github.com/bearsampp/bearsampp) +- [Module PHP (Gradle)](https://github.com/Bearsampp/module-php/tree/gradle-convert) +- [modules-untouched Repository](https://github.com/Bearsampp/modules-untouched) + +## Support + +If you encounter issues during migration: + +1. Check this migration guide +2. Review the [main documentation](README.md) +3. Check [troubleshooting guide](README.md#troubleshooting) +4. Open an issue on [GitHub](https://github.com/bearsampp/module-nodejs/issues) + +--- + +**Last Updated**: 2025-01-31 +**Version**: 2025.8.21 +**Build System**: Pure Gradle + +## Summary + +The migration from Ant to Gradle provides: + +✅ **Better Performance** - Incremental builds and caching +✅ **Modern Tooling** - Excellent IDE integration +✅ **Easier Maintenance** - Readable Groovy DSL +✅ **More Features** - Rich plugin ecosystem +✅ **Better Documentation** - Comprehensive guides + +The Gradle build system is now the primary and recommended way to build Bearsampp Node.js modules. diff --git a/.gradle-docs/PACKAGING.md b/.gradle-docs/PACKAGING.md index 065b06e7..ebcc99b1 100644 --- a/.gradle-docs/PACKAGING.md +++ b/.gradle-docs/PACKAGING.md @@ -1,54 +1,384 @@ -### Packaging and Archive Layout +# Packaging and Archive Layout -This module’s Gradle build produces archives that include the top-level version folder, matching the behavior used by the Bruno module. +This document describes how the Bearsampp Node.js module packages releases and the structure of the resulting archives. -Example structure for version 24.6.0: +## Overview + +The Gradle build produces archives that include the top-level version folder, matching the behavior used across all Bearsampp modules (PHP, MySQL, etc.). This ensures consistency and proper extraction behavior. + +## Archive Structure + +### Example for Node.js 24.6.0 ``` bearsampp-nodejs-24.6.0-2025.8.21.7z -└─ nodejs24.6.0/ - ├─ node.exe - ├─ npm - ├─ etc/ - └─ ... +└── nodejs24.6.0/ ← Version folder at root + ├── node.exe ← Node.js executable + ├── npm ← NPM script + ├── npm.cmd ← NPM Windows command + ├── npx ← NPX script + ├── npx.cmd ← NPX Windows command + ├── node_modules/ ← Node modules directory + │ ├── npm/ + │ └── ... + ├── LICENSE + ├── README.md + └── ... ``` -Key implementation detail in `build.gradle`: +### Key Points + +1. **Top-level folder**: The archive contains `nodejs{version}/` as the root directory +2. **Version naming**: Format is `nodejs` + version number (e.g., `nodejs24.6.0`) +3. **Complete structure**: All Node.js files and directories are inside the version folder +4. **Consistency**: Matches the pattern used by other Bearsampp modules -- The compression is run from the parent directory of the prep folder and the folder name (e.g. `nodejs24.6.0`) is passed explicitly to the archiver. This guarantees the archive contains the version folder at the root. +## Implementation Details -7‑Zip flow: +### Compression Process +The build system uses two different approaches depending on the archive format: + +#### 7-Zip Compression + +```groovy +// Run from parent directory and include folder name explicitly +def parentDir = prepPath.parentFile +def folderName = prepPath.name // e.g., "nodejs24.6.0" + +ProcessBuilder([ + sevenZipExe, + 'a', // Add to archive + '-t7z', // 7z format + archiveFile.absolutePath, // Output archive + folderName // Folder to include +]) +.directory(parentDir) // Run from parent directory +.start() ``` -ProcessBuilder([7z.exe, 'a', '-t7z', , ]) - .directory() + +**Why this works:** +- Running from the parent directory ensures the folder name is included in the archive +- Passing the folder name (not path) as the argument includes it at the root level +- Result: Archive contains `nodejs24.6.0/` at the root + +#### ZIP Compression + +```groovy +task("zipArchive_${bundleVersion}", type: Zip) { + from(prepPath.parentFile) { + include "${prepPath.name}/**" + } + destinationDirectory = archiveFile.parentFile + archiveFileName = archiveFile.name +} ``` -Zip flow (Gradle `Zip` task): +**Why this works:** +- `from(prepPath.parentFile)` starts from the parent directory +- `include "${prepPath.name}/**"` includes the folder and all its contents +- Result: Archive contains `nodejs24.6.0/` at the root + +## Archive Naming Convention + +Archives follow this naming pattern: ``` -from(prepPath.parentFile) { - include "${prepPath.name}/**" -} +bearsampp-{bundle.name}-{version}-{bundle.release}.{format} +``` + +**Example:** +``` +bearsampp-nodejs-24.6.0-2025.8.21.7z +``` + +**Components:** +- `bearsampp` - Project prefix +- `nodejs` - Bundle name (from build.properties) +- `24.6.0` - Node.js version +- `2025.8.21` - Bundle release date (from build.properties) +- `7z` - Archive format (from build.properties) + +## Hash Files + +Each archive is accompanied by multiple hash files for integrity verification: + +``` +bearsampp-nodejs-24.6.0-2025.8.21.7z +bearsampp-nodejs-24.6.0-2025.8.21.7z.md5 ← MD5 checksum +bearsampp-nodejs-24.6.0-2025.8.21.7z.sha1 ← SHA-1 checksum +bearsampp-nodejs-24.6.0-2025.8.21.7z.sha256 ← SHA-256 checksum +bearsampp-nodejs-24.6.0-2025.8.21.7z.sha512 ← SHA-512 checksum +``` + +### Hash File Format + +Each hash file contains: +``` +{hash_value} {filename} ``` -### How to verify locally +**Example (MD5):** +``` +a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 bearsampp-nodejs-24.6.0-2025.8.21.7z +``` + +### Verification + +To verify archive integrity: + +```bash +# Windows (PowerShell) +# MD5 +Get-FileHash bearsampp-nodejs-24.6.0-2025.8.21.7z -Algorithm MD5 + +# SHA256 +Get-FileHash bearsampp-nodejs-24.6.0-2025.8.21.7z -Algorithm SHA256 + +# Linux/macOS +# MD5 +md5sum bearsampp-nodejs-24.6.0-2025.8.21.7z + +# SHA256 +sha256sum bearsampp-nodejs-24.6.0-2025.8.21.7z +``` + +## Output Locations + +### Default Structure + +``` +bearsampp-build/ +├── tmp/ # Temporary build files +│ ├── bundles_prep/bins/nodejs/ # Prepared bundles +│ │ └── nodejs24.6.0/ # Prepared version +│ ├── bundles_build/bins/nodejs/ # Build staging +│ │ └── nodejs24.6.0/ # Built version (non-archived) +│ ├── downloads/nodejs/ # Downloaded archives +│ │ └── nodejs-24.6.0-win-x64.7z +│ └── extract/nodejs/ # Extracted archives +│ └── 24.6.0/ +│ └── node-v24.6.0-win-x64/ +└── bins/nodejs/ # Final packaged archives + └── 2025.8.21/ # Release version + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z.md5 + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha1 + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha256 + └── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha512 +``` + +### Customizing Output Location + +You can override the default output location in two ways: + +#### 1. build.properties + +```properties +build.path = C:/Custom-Build-Path +``` + +#### 2. Environment Variable + +```bash +# Windows (PowerShell) +$env:BEARSAMPP_BUILD_PATH = "C:\Custom-Build-Path" + +# Windows (Command Prompt) +set BEARSAMPP_BUILD_PATH=C:\Custom-Build-Path + +# Linux/macOS +export BEARSAMPP_BUILD_PATH=/path/to/custom/build +``` + +**Priority:** +1. `build.properties` `build.path` property (highest) +2. `BEARSAMPP_BUILD_PATH` environment variable +3. Default: `{repo-parent}/bearsampp-build` (lowest) + +## Verification Guide + +### How to Verify Archive Structure + +After building a release, verify the archive structure: -- Build a release for a specific version: - - `gradle release -PbundleVersion=24.6.0` +#### Method 1: Using 7-Zip Command Line -- Locate the output archive under: - - `////` - - Example: `../bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z` +```bash +# List archive contents +7z l bearsampp-nodejs-24.6.0-2025.8.21.7z + +# Filter for the version folder +7z l bearsampp-nodejs-24.6.0-2025.8.21.7z | findstr nodejs24.6.0 + +# Expected output should show entries like: +# nodejs24.6.0\node.exe +# nodejs24.6.0\npm +# nodejs24.6.0\node_modules\... +``` + +#### Method 2: Using PowerShell (ZIP) + +```powershell +# Extract to temporary directory +Expand-Archive -Path bearsampp-nodejs-24.6.0-2025.8.21.zip -DestinationPath .\_inspect + +# List contents +Get-ChildItem .\_inspect + +# Expected output: +# Directory: E:\...\\_inspect +# Mode LastWriteTime Length Name +# ---- ------------- ------ ---- +# d----- 1/31/2025 ... nodejs24.6.0 + +# List files inside version folder +Get-ChildItem .\_inspect\nodejs24.6.0 + +# Clean up +Remove-Item .\_inspect -Recurse -Force +``` + +#### Method 3: Using 7-Zip GUI + +1. Open the archive in 7-Zip +2. The first entry should be a folder named `nodejs{version}/` +3. All files should be inside this folder + +### Quick Verification Script + +```bash +# Build a release +gradle release -PbundleVersion=24.6.0 + +# Verify the archive +7z l bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z | findstr /C:"nodejs24.6.0" + +# If successful, you should see multiple lines starting with "nodejs24.6.0\" +``` + +## Build Process Flow + +### Step-by-Step Packaging + +1. **Preparation Phase** + ``` + tmp/bundles_prep/bins/nodejs/nodejs24.6.0/ + ``` + - Copy Node.js files from source (downloaded or local) + - Overlay custom files from bin/nodejs24.6.0/ + - Result: Complete Node.js installation ready for packaging + +2. **Build Phase** + ``` + tmp/bundles_build/bins/nodejs/nodejs24.6.0/ + ``` + - Copy prepared files to build directory + - This is the non-archived version + - Can be used for testing before packaging + +3. **Packaging Phase** + ``` + bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z + ``` + - Compress from parent directory + - Include version folder at root + - Generate hash files + +## Troubleshooting + +### Issue: Archive doesn't contain version folder + +**Symptom:** +``` +Archive contains files directly at root instead of nodejs24.6.0/ folder +``` + +**Solution:** +This should not happen with the current build system. If it does: +1. Check that you're using the latest build.gradle +2. Verify the compression command is running from the parent directory +3. Check the Gradle output for any errors during packaging + +### Issue: Wrong folder name in archive + +**Symptom:** +``` +Archive contains "node-v24.6.0-win-x64" instead of "nodejs24.6.0" +``` + +**Solution:** +This indicates the preparation phase didn't complete correctly: +1. Check that the prep directory was created: `tmp/bundles_prep/bins/nodejs/nodejs24.6.0/` +2. Verify files were copied to the prep directory +3. Run with `--info` flag to see detailed output: `gradle release -PbundleVersion=24.6.0 --info` + +### Issue: Hash files not generated + +**Symptom:** +``` +Archive created but no .md5, .sha1, etc. files +``` + +**Solution:** +1. Check Gradle output for hash generation errors +2. Verify Java has permissions to write to the output directory +3. Try running with `--stacktrace` to see detailed error: `gradle release -PbundleVersion=24.6.0 --stacktrace` + +## Best Practices + +### 1. Always Verify After Build + +After building a release, always verify the archive structure: + +```bash +gradle release -PbundleVersion=24.6.0 +7z l bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z | findstr nodejs24.6.0 +``` + +### 2. Test Extraction + +Before distributing, test that the archive extracts correctly: + +```bash +# Create test directory +mkdir test-extract +cd test-extract + +# Extract archive +7z x ../bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z + +# Verify structure +dir nodejs24.6.0 + +# Test Node.js +nodejs24.6.0\node.exe --version + +# Clean up +cd .. +rmdir /s /q test-extract +``` + +### 3. Verify Hash Files + +Always verify hash files are generated and correct: + +```bash +# Check hash file exists +dir bearsampp-build\bins\nodejs\2025.8.21\*.md5 + +# Verify hash matches +Get-FileHash bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z -Algorithm MD5 +type bearsampp-build\bins\nodejs\2025.8.21\bearsampp-nodejs-24.6.0-2025.8.21.7z.md5 +``` -- Verify with 7‑Zip (Windows): - - Command prompt: `7z l bearsampp-nodejs-24.6.0-2025.8.21.7z | findstr nodejs24.6.0` - - You should see entries starting with `nodejs24.6.0/`. +## Related Documentation -- Verify with any Zip tool (if `bundle.format=zip`): - - The first entry should be `nodejs/`. +- [Main Build Documentation](README.md) - Complete build system documentation +- [build.gradle](../build.gradle) - Build script implementation +- [build.properties](../build.properties) - Build configuration -### Notes +--- -- The legacy Ant build (`build.xml`) delegates compression to `dev/build/build-bundle.xml`. The Gradle build is the primary supported path for this module and enforces the folder-in-archive layout directly in this repository. -- Packaging format is controlled by `bundle.format` in `build.properties` (`7z` or `zip`). +**Last Updated**: 2025-01-31 +**Version**: 2025.8.21 diff --git a/.gradle-docs/README.md b/.gradle-docs/README.md index 5b300d3a..9a8e97dc 100644 --- a/.gradle-docs/README.md +++ b/.gradle-docs/README.md @@ -1,13 +1,498 @@ -Gradle Build Documentation (module-nodejs) +# Bearsampp Module Node.js - Gradle Build Documentation -This folder contains additional documentation for the Gradle build used by the Bearsampp Node.js module. +## Table of Contents -Contents: +- [Overview](#overview) +- [Quick Start](#quick-start) +- [Installation](#installation) +- [Build Tasks](#build-tasks) +- [Configuration](#configuration) +- [Architecture](#architecture) +- [Troubleshooting](#troubleshooting) +- [Additional Documentation](#additional-documentation) -- PACKAGING.md — Archive layout, how compression works, and how to verify results +--- -Quick links: +## Overview -- Build tasks overview is in the repository README.md under the "Build (Gradle)" section. -- Typical command to build a specific version: - - gradle release -PbundleVersion=24.6.0 +The Bearsampp Module Node.js project has been converted to a **pure Gradle build system**, replacing the legacy Ant build configuration. This provides: + +- **Modern Build System** - Native Gradle tasks and conventions +- **Better Performance** - Incremental builds and caching +- **Simplified Maintenance** - Pure Groovy/Gradle DSL +- **Enhanced Tooling** - IDE integration and dependency management +- **Cross-Platform Support** - Works on Windows, Linux, and macOS + +### Project Information + +| Property | Value | +|-------------------|------------------------------------------| +| **Project Name** | module-nodejs | +| **Group** | com.bearsampp.modules | +| **Type** | Node.js 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=24.6.0 + +# Clean build artifacts +gradle clean +``` + +--- + +## Installation + +### 1. Clone the Repository + +```bash +git clone https://github.com/bearsampp/module-nodejs.git +cd module-nodejs +``` + +### 2. Verify Environment + +```bash +gradle verify +``` + +This will check: +- Java version (8+) +- Required files (build.properties) +- Directory structure (bin/) +- Build dependencies + +### 3. List Available Versions + +```bash +gradle listVersions +``` + +### 4. Build Your First Release + +```bash +# Interactive mode (prompts for version) +gradle release + +# Or specify version directly +gradle release -PbundleVersion=24.6.0 +``` + +--- + +## Build Tasks + +### Core Build Tasks + +| Task | Description | Example | +|-----------------------|--------------------------------------------------|------------------------------------------| +| `release` | Build and package release (interactive/non-interactive) | `gradle release -PbundleVersion=24.6.0` | +| `releaseAll` | Build all available versions in bin/ | `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` | + +### 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 modules-untouched | `gradle listReleases` | +| `checkModulesUntouched` | Check modules-untouched integration | `gradle checkModulesUntouched` | + +### 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: + +```properties +bundle.name = nodejs +bundle.release = 2025.8.21 +bundle.type = bins +bundle.format = 7z +``` + +| Property | Description | Example Value | +|-------------------|--------------------------------------|----------------| +| `bundle.name` | Name of the bundle | `nodejs` | +| `bundle.release` | Release version | `2025.8.21` | +| `bundle.type` | Type of bundle | `bins` | +| `bundle.format` | Archive format | `7z` | + +### gradle.properties + +Gradle-specific configuration: + +```properties +# 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-nodejs/ +├── .gradle-docs/ # Gradle documentation +│ ├── README.md # Main documentation +│ └── PACKAGING.md # Packaging guide +├── bin/ # Node.js version bundles +│ ├── nodejs24.6.0/ +│ ├── nodejs22.11.0/ +│ ├── archived/ # Archived versions +│ └── ... +├── img/ # Images and assets +│ └── Bearsampp-logo.svg +├── build.gradle # Main Gradle build script +├── settings.gradle # Gradle settings +├── build.properties # Build configuration +├── releases.properties # Available Node.js releases +└── README.md # Main project README + +bearsampp-build/ # External build directory (outside repo) +├── tmp/ # Temporary build files +│ ├── bundles_prep/bins/nodejs/ # Prepared bundles +│ ├── bundles_build/bins/nodejs/ # Build staging +│ ├── downloads/nodejs/ # Downloaded dependencies +│ └── extract/nodejs/ # Extracted archives +└── bins/nodejs/ # Final packaged archives + └── 2025.8.21/ # Release version + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z + ├── bearsampp-nodejs-24.6.0-2025.8.21.7z.md5 + └── ... +``` + +--- + +## Architecture + +### Build Process Flow + +``` +1. User runs: gradle release -PbundleVersion=24.6.0 + ↓ +2. Validate environment and version + ↓ +3. Check if Node.js binaries exist in bin/nodejs24.6.0/ + ↓ +4. If not found, download from modules-untouched + - Check nodejs.properties for version URL + - Fallback to standard URL format + - Extract to tmp/extract/ + ↓ +5. Create preparation directory (tmp/bundles_prep/) + ↓ +6. Copy Node.js files to prep directory + ↓ +7. Overlay any custom files from bin/nodejs24.6.0/ + ↓ +8. Copy to bundles_build directory + ↓ +9. Package prepared folder into archive + - Archive includes top-level folder: nodejs24.6.0/ + - Generate hash files (MD5, SHA1, SHA256, SHA512) + ↓ +10. Output to bearsampp-build/bins/nodejs/{bundle.release}/ +``` + +### Packaging Details + +- **Archive name format**: `bearsampp-nodejs-{version}-{bundle.release}.{7z|zip}` +- **Location**: `bearsampp-build/bins/nodejs/{bundle.release}/` + - Example: `bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z` +- **Content root**: The top-level folder inside the archive is `nodejs{version}/` (e.g., `nodejs24.6.0/`) +- **Structure**: The archive contains the Node.js version folder at the root with all files inside + +**Archive Structure Example**: +``` +bearsampp-nodejs-24.6.0-2025.8.21.7z +└── nodejs24.6.0/ ← Version folder at root + ├── node.exe + ├── npm + ├── npm.cmd + ├── npx + ├── npx.cmd + ├── node_modules/ + └── ... +``` + +**Verification Commands**: + +```bash +# List archive contents with 7z +7z l bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.7z | more + +# You should see entries beginning with: +# nodejs24.6.0/node.exe +# nodejs24.6.0/npm +# nodejs24.6.0/node_modules/ +# nodejs24.6.0/... + +# Extract and inspect with PowerShell (zip example) +Expand-Archive -Path bearsampp-build/bins/nodejs/2025.8.21/bearsampp-nodejs-24.6.0-2025.8.21.zip -DestinationPath .\_inspect +Get-ChildItem .\_inspect\nodejs24.6.0 | Select-Object Name + +# Expected output: +# node.exe +# npm +# npm.cmd +# node_modules/ +# ... +``` + +**Note**: This archive structure matches other Bearsampp modules (PHP, MySQL) where archives contain `{module}{version}/` at the root. This ensures consistency across all Bearsampp modules. + +**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 + +Example: +``` +bearsampp-build/bins/nodejs/2025.8.21/ +├── bearsampp-nodejs-24.6.0-2025.8.21.7z +├── bearsampp-nodejs-24.6.0-2025.8.21.7z.md5 +├── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha1 +├── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha256 +└── bearsampp-nodejs-24.6.0-2025.8.21.7z.sha512 +``` + +### Version Resolution Strategy + +The build system uses a two-tier strategy to locate Node.js binaries: + +1. **modules-untouched nodejs.properties** (Primary) + - URL: `https://github.com/Bearsampp/modules-untouched/blob/main/modules/nodejs.properties` + - Contains version-to-URL mappings + - Example: `24.6.0=https://github.com/Bearsampp/modules-untouched/releases/download/nodejs-24.6.0/nodejs-24.6.0-win-x64.7z` + +2. **Standard URL Format** (Fallback) + - Format: `https://github.com/Bearsampp/modules-untouched/releases/download/nodejs-{version}/nodejs-{version}-win-x64.7z` + - Used when version not found in nodejs.properties + - Assumes standard naming convention + +--- + +## 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 in bin/ or bin/archived/ +``` + +**Solution:** +1. List available versions: `gradle listVersions` +2. Use an existing version: `gradle release -PbundleVersion=24.6.0` +3. Or the build will automatically download from modules-untouched + +--- + +#### Issue: "Failed to download from modules-untouched" + +**Symptom:** +``` +Failed to download from modules-untouched: Connection refused +``` + +**Solution:** +1. Check internet connectivity +2. Verify version exists: `gradle listReleases` +3. Check modules-untouched repository is accessible +4. Try again later if repository is temporarily unavailable + +--- + +#### 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 + +--- + +#### 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. Or set `7Z_HOME` environment variable to 7-Zip installation directory +3. Or change `bundle.format` to `zip` in build.properties + +--- + +### Debug Mode + +Run Gradle with debug output: + +```bash +gradle release -PbundleVersion=24.6.0 --info +gradle release -PbundleVersion=24.6.0 --debug +``` + +### Clean Build + +If you encounter issues, try a clean build: + +```bash +gradle clean +gradle release -PbundleVersion=24.6.0 +``` + +--- + +## 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` | `gradle release` | +| `ant release -Dinput.bundle=24.6.0` | `gradle release -PbundleVersion=24.6.0` | +| `ant clean` | `gradle clean` | + +#### Key Differences + +| Aspect | Ant | Gradle | +|---------------------|------------------------------|----------------------------------| +| **Build File** | XML (build.xml) | Groovy DSL (build.gradle) | +| **Task Definition** | `` | `tasks.register('...')` | +| **Properties** | `` | `ext { ... }` | +| **Dependencies** | Manual downloads | Automatic with repositories | +| **Caching** | None | Built-in incremental builds | +| **IDE Support** | Limited | Excellent (IntelliJ, Eclipse) | + +--- + +## Additional Documentation + +This documentation is part of a comprehensive guide for the Bearsampp Node.js module build system: + +### Documentation Files + +| Document | Description | +|---------------------------|--------------------------------------------------| +| [README.md](README.md) | Main build documentation (this file) | +| [PACKAGING.md](PACKAGING.md) | Packaging and archive structure guide | +| [MIGRATION.md](MIGRATION.md) | Migration guide from Ant to Gradle | + +### Quick Links + +- **Main Project README**: [../README.md](../README.md) +- **Build Script**: [../build.gradle](../build.gradle) +- **Build Configuration**: [../build.properties](../build.properties) +- **Gradle Settings**: [../settings.gradle](../settings.gradle) + +### External Resources + +- [Gradle Documentation](https://docs.gradle.org/) +- [Bearsampp Project](https://github.com/bearsampp/bearsampp) +- [Node.js Downloads](https://nodejs.org/en/download/) +- [modules-untouched Repository](https://github.com/Bearsampp/modules-untouched) + +--- + +## Support + +For issues and questions: + +- **GitHub Issues**: https://github.com/bearsampp/module-nodejs/issues +- **Bearsampp Issues**: https://github.com/bearsampp/bearsampp/issues +- **Documentation**: https://bearsampp.com/module/nodejs + +--- + +**Last Updated**: 2025-01-31 +**Version**: 2025.8.21 +**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. The project now uses pure Gradle for all build operations. +- See [MIGRATION.md](MIGRATION.md) for details on the Ant to Gradle migration. diff --git a/README.md b/README.md index e371f6b8..0ec08f1f 100644 --- a/README.md +++ b/README.md @@ -5,63 +5,65 @@ This is a module of [Bearsampp project](https://github.com/bearsampp/bearsampp) involving Node.js. -## Build (Gradle) +## Build System -This module now uses a pure Gradle build similar to the Bruno module. +This project uses **Gradle** as its build system. The legacy Ant build has been fully replaced with a modern, pure Gradle implementation. -Quick commands: +### Quick Start -- List tasks: `gradle tasks` -- Show build info: `gradle info` -- Verify environment: `gradle verify` -- List local versions (bin and bin/archived): `gradle listVersions` -- List releases from modules-untouched: `gradle listReleases` -- Build a specific version: `gradle release -PbundleVersion=24.6.0` -- Build interactively (choose from local versions): `gradle release` -- Build all local versions (prep/copy flow): `gradle releaseAll` -- Clean: `gradle clean` +```bash +# Display build information +gradle info -Archive layout assurance: +# List all available tasks +gradle tasks -- The packaged archive includes the top-level version folder (e.g., `nodejs24.6.0/`). -- Example: `bearsampp-nodejs-24.6.0-2025.8.21.7z` contains `nodejs24.6.0/` as the root, with files inside it. +# Verify build environment +gradle verify -Verify quickly after a build: +# Build a release (interactive) +gradle release -- 7z: `7z l bearsampp-nodejs--.7z | findstr nodejs` should list the folder. -- Zip: Inspect contents; the first entry should be `nodejs/`. +# Build a specific version (non-interactive) +gradle release -PbundleVersion=24.6.0 -Version resolution strategy: +# Clean build artifacts +gradle clean +``` -1. Remote `modules-untouched` `nodejs.properties` - - URL: `https://github.com/Bearsampp/modules-untouched/blob/main/modules/nodejs.properties` -2. Fallback constructed URL: `.../releases/download/nodejs-{version}/nodejs-{version}-win-x64.7z` +### Prerequisites -Output locations and overrides: +| Requirement | Version | Purpose | +|-------------------|---------------|------------------------------------------| +| **Java** | 8+ | Required for Gradle execution | +| **Gradle** | 8.0+ | Build automation tool | +| **7-Zip** | Latest | Archive creation (optional for zip) | -- Default base output: `/../bearsampp-build` -- Override base output via either: - - `build.properties` property `build.path` - - Environment variable `BEARSAMPP_BUILD_PATH` +### Available Tasks -Packaging settings come from `build.properties`: +| Task | Description | +|-----------------------|--------------------------------------------------| +| `release` | Build release package (interactive/non-interactive) | +| `releaseAll` | Build all versions in bin/ directory | +| `clean` | Clean build artifacts and temporary files | +| `verify` | Verify build environment and dependencies | +| `info` | Display build configuration information | +| `listVersions` | List available bundle versions in bin/ | +| `listReleases` | List releases from modules-untouched | +| `validateProperties` | Validate build.properties configuration | +| `checkModulesUntouched` | Check modules-untouched integration | -- `bundle.name = nodejs` -- `bundle.type = bins` -- `bundle.format = 7z` (requires 7‑Zip) +For complete documentation, see [.gradle-docs/README.md](.gradle-docs/README.md) -7‑Zip detection (Windows): +## Documentation -- Auto-detects from `7Z_HOME` or common install paths, falls back to `where 7z.exe`. - -Documentation index: see `/.gradle-docs/README.md`. - -## Documentation and downloads - -https://bearsampp.com/module/nodejs - -Additional Gradle build docs for this module live in `/.gradle-docs/` of this repository. +- **Build Documentation**: [.gradle-docs/README.md](.gradle-docs/README.md) +- **Module Downloads**: https://bearsampp.com/module/nodejs ## Issues Issues must be reported on [Bearsampp repository](https://github.com/bearsampp/bearsampp/issues). + +## Statistics + +![Alt](https://repobeats.axiom.co/api/embed/YOUR_EMBED_ID_HERE.svg "Repobeats analytics image") diff --git a/build.xml b/build.xml deleted file mode 100644 index 11933307..00000000 --- a/build.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/module-nodejs.RELEASE.launch b/module-nodejs.RELEASE.launch deleted file mode 100644 index d6908ad3..00000000 --- a/module-nodejs.RELEASE.launch +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - -