From 2c9259514e14cae5357ddff8a3fb155d6ad0a6e0 Mon Sep 17 00:00:00 2001 From: jwaisner Date: Sat, 8 Nov 2025 22:48:15 -0600 Subject: [PATCH 1/3] Added Gradle to build process. --- .gitignore | 5 + build.gradle | 537 ++++++++++++++++++++++++++++++++++++++++++++++ gradle.properties | 19 ++ settings.gradle | 25 +++ 4 files changed, 586 insertions(+) create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index 207bc8a7..6182c491 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,10 @@ # ignore "current" directories /**/current +# Gradle +.gradle/ +build/ +.gradle-cache/ + # Qodo /.qodo diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..51c58130 --- /dev/null +++ b/build.gradle @@ -0,0 +1,537 @@ +/* + * Bearsampp Module Python - 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 + * 4. Handles Python-specific build dependencies (PIP upgrades, wheel installations) + * + * Usage: + * gradle tasks - List all available tasks + * gradle release - Interactive release (prompts for version) + * gradle release "-PbundleVersion=3.13.5" - 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', 'python')}" + +// 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', 'python') + bundleRelease = buildProps.getProperty('bundle.release', '1.0.0') + bundleType = buildProps.getProperty('bundle.type', 'tools') + 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 including Python-specific build steps +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' + + doLast { + println """ + ================================================================ + Bearsampp Module Python - Build Info + ================================================================ + + Project: ${project.name} + Version: ${project.version} + Description: ${project.description} + + 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: ${gradle.gradleVersion} + Home: ${gradle.gradleHomeDir} + + Python Build Features: + * Automatic PIP upgrade during build + * Wheel package download and installation + * Support for multiple Python versions + * PyQt5 exclusion handling + + Available Task Groups: + * build - Build and package tasks + * ant tasks - Legacy Ant tasks (prefixed with 'ant-') + * help - Help and information tasks + * verification - Verification and validation tasks + + Quick Start: + gradle tasks - List all available tasks + gradle info - Show this information + gradle release - Interactive release build + gradle release "-PbundleVersion=3.13.5" - Non-interactive release + gradle clean - Clean build artifacts + gradle verify - Verify build environment + gradle listVersions - List available Python versions + """.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 "" + println "Python-specific build steps will be executed:" + println " 1. Upgrade PIP to latest version" + println " 2. Download wheel packages from wheel.properties" + println " 3. Install wheel packages using install.bat" + 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-python..." + + 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() + + // Check bin directory for Python versions + def binDir = file("${projectDir}/bin") + checks['bin directory'] = binDir.exists() + + if (binDir.exists()) { + def pythonVersions = binDir.listFiles() + .findAll { it.isDirectory() && it.name.startsWith(bundleName) } + checks['Python versions available'] = pythonVersions.size() > 0 + } + + 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=3.13.5\" - Non-interactive release" + println " gradle listVersions - List available Python versions" + } 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 Python Releases:" + println "-".multiply(80) + releases.sort { it.key }.each { version, url -> + println " ${version.padRight(15)} -> ${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 Python 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 -> + def versionDir = file("${binDir}/${bundleName}${version}") + def wheelDir = file("${versionDir}/wheel") + def hasWheel = wheelDir.exists() + def wheelInfo = "" + + if (hasWheel) { + def wheelProps = file("${wheelDir}/wheel.properties") + if (wheelProps.exists()) { + def props = new Properties() + wheelProps.withInputStream { props.load(it) } + def wheelUrl = props.getProperty('wheel', '') + def wheelFile = wheelUrl.tokenize('/').last() + wheelInfo = " [wheel: ${wheelFile}]" + } + } + + println " ${version}${wheelInfo}" + } + 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") + } + } +} + +// Task: Validate Python version structure +tasks.register('validatePythonVersion') { + group = 'verification' + description = 'Validate Python version directory structure (use -PbundleVersion=X.X.X)' + + doLast { + def versionToValidate = project.findProperty('bundleVersion') + + if (!versionToValidate) { + println "[ERROR] Please specify a version using -PbundleVersion=X.X.X" + println "\nExample: gradle validatePythonVersion \"-PbundleVersion=3.13.5\"" + throw new GradleException("Bundle version not specified") + } + + def versionDir = file("${projectDir}/bin/${bundleName}${versionToValidate}") + + if (!versionDir.exists()) { + println "[ERROR] Version directory not found: ${versionDir}" + throw new GradleException("Python version ${versionToValidate} not found") + } + + println "Validating Python version ${versionToValidate}..." + println "-".multiply(60) + + def checks = [:] + + // Check required directories + checks['bin directory'] = file("${versionDir}/bin").exists() + checks['wheel directory'] = file("${versionDir}/wheel").exists() + + // Check required files + checks['bearsampp.conf'] = file("${versionDir}/bearsampp.conf").exists() + checks['bin/python.bat'] = file("${versionDir}/bin/python.bat").exists() + + // Check wheel configuration + def wheelDir = file("${versionDir}/wheel") + if (wheelDir.exists()) { + checks['wheel.properties'] = file("${wheelDir}/wheel.properties").exists() + checks['install.bat'] = file("${wheelDir}/install.bat").exists() + + // Validate wheel.properties content + def wheelProps = file("${wheelDir}/wheel.properties") + if (wheelProps.exists()) { + def props = new Properties() + wheelProps.withInputStream { props.load(it) } + checks['wheel URL defined'] = props.containsKey('wheel') && !props.getProperty('wheel').trim().isEmpty() + } + } + + println "\nValidation 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] Python version ${versionToValidate} structure is valid" + } else { + println "\n[WARNING] Some validation checks failed" + throw new GradleException("Python version validation failed") + } + } +} + +// Task: Display wheel information for a Python version +tasks.register('showWheelInfo') { + group = 'help' + description = 'Display wheel package information for a Python version (use -PbundleVersion=X.X.X)' + + doLast { + def versionToCheck = project.findProperty('bundleVersion') + + if (!versionToCheck) { + println "[ERROR] Please specify a version using -PbundleVersion=X.X.X" + println "\nExample: gradle showWheelInfo \"-PbundleVersion=3.13.5\"" + return + } + + def versionDir = file("${projectDir}/bin/${bundleName}${versionToCheck}") + def wheelDir = file("${versionDir}/wheel") + + if (!wheelDir.exists()) { + println "[ERROR] Wheel directory not found for version ${versionToCheck}" + return + } + + println "\nWheel Information for Python ${versionToCheck}:" + println "=".multiply(70) + + def wheelProps = file("${wheelDir}/wheel.properties") + if (wheelProps.exists()) { + def props = new Properties() + wheelProps.withInputStream { props.load(it) } + + def wheelUrl = props.getProperty('wheel', 'Not defined') + def wheelFile = wheelUrl.tokenize('/').last() + + println " Wheel URL: ${wheelUrl}" + println " Wheel File: ${wheelFile}" + println " Location: ${wheelDir}" + } else { + println " [WARNING] wheel.properties not found" + } + + def installBat = file("${wheelDir}/install.bat") + if (installBat.exists()) { + println "\n Install Script: ${installBat}" + println " Content:" + println " " + "-".multiply(66) + installBat.eachLine { line -> + println " ${line}" + } + } + + println "=".multiply(70) + } +} + +// ============================================================================ +// BUILD LIFECYCLE HOOKS +// ============================================================================ + +gradle.taskGraph.whenReady { graph -> + println """ + ================================================================ + Bearsampp Module Python - Gradle + Ant Hybrid Build + ================================================================ + """.stripIndent() +} + +// ============================================================================ +// DEFAULT TASK +// ============================================================================ + +defaultTasks 'info' diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 00000000..07bb9b2c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Gradle Build Properties for Bearsampp Module Python + +# 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..00c8c600 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,25 @@ +/* + * Bearsampp Module Python - Gradle Settings + */ + +rootProject.name = 'module-python' + +// 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 Python Build + ================================================================ + """.stripIndent() +} From 4ecd270d701807342a7ad651de11c852775ed190 Mon Sep 17 00:00:00 2001 From: Bear Date: Mon, 17 Nov 2025 23:24:56 -0600 Subject: [PATCH 2/3] Update README with comprehensive Gradle build system documentation complete migration to pure gradle fix incorect build process --- .gradle-docs/BUILD_SYSTEM.md | 502 ++++++++ .gradle-docs/CHANGELOG.md | 229 ++++ .gradle-docs/CONFIGURATION.md | 652 ++++++++++ .gradle-docs/GETTING_STARTED.md | 215 ++++ .gradle-docs/QUICK_REFERENCE.md | 191 +++ .gradle-docs/README.md | 363 ++++++ .gradle-docs/TASK_REFERENCE.md | 605 +++++++++ README.md | 107 +- .../python3.10.6/bearsampp.conf | 0 .../python3.10.6/bin/python.bat | 0 .../python3.10.6/wheel/install.bat | 0 .../python3.10.6/wheel/wheel.properties | 0 .../python3.10.9/bearsampp.conf | 0 .../python3.10.9/bin/python.bat | 0 .../python3.10.9/wheel/install.bat | 0 .../python3.10.9/wheel/wheel.properties | 0 .../python3.11.5/bearsampp.conf | 0 .../python3.11.5/bin/python.bat | 0 .../python3.11.5/wheel/install.bat | 0 .../python3.11.5/wheel/wheel.properties | 0 .../python3.11.6b0/bearsampp.conf | 0 .../python3.11.6b0/bin/python.bat | 0 .../python3.11.6b0/wheel/install.bat | 0 .../python3.11.6b0/wheel/wheel.properties | 0 .../python3.11.8/bearsampp.conf | 0 .../python3.11.8/bin/python.bat | 0 .../python3.11.8/wheel/install.bat | 0 .../python3.11.8/wheel/wheel.properties | 0 .../python3.12.2/bearsampp.conf | 0 .../python3.12.2/bin/python.bat | 0 .../python3.12.2/wheel/install.bat | 0 .../python3.12.2/wheel/wheel.properties | 0 .../python3.12.6.0/bearsampp.conf | 0 .../python3.12.6.0/bin/python.bat | 0 .../python3.12.6.0/wheel/install.bat | 0 .../python3.12.6.0/wheel/wheel.properties | 0 .../python3.12.8.0-b2/bearsampp.conf | 0 .../python3.12.8.0-b2/bin/python.bat | 0 .../python3.12.8.0-b2/wheel/install.bat | 0 .../python3.12.8.0-b2/wheel/wheel.properties | 0 .../python3.12.9/bearsampp.conf | 0 .../python3.12.9/bin/python.bat | 0 .../python3.12.9/wheel/install.bat | 0 .../python3.12.9/wheel/wheel.properties | 0 .../python3.13.2/bearsampp.conf | 0 .../python3.13.2/bin/python.bat | 0 .../python3.13.2/wheel/install.bat | 0 .../python3.13.2/wheel/wheel.properties | 0 .../python3.13.3/bearsampp.conf | 0 .../python3.13.3/bin/python.bat | 0 .../python3.13.3/wheel/install.bat | 0 .../python3.13.3/wheel/wheel.properties | 0 build.gradle | 1094 ++++++++++++++--- build.xml | 66 - 54 files changed, 3805 insertions(+), 219 deletions(-) create mode 100644 .gradle-docs/BUILD_SYSTEM.md create mode 100644 .gradle-docs/CHANGELOG.md create mode 100644 .gradle-docs/CONFIGURATION.md create mode 100644 .gradle-docs/GETTING_STARTED.md create mode 100644 .gradle-docs/QUICK_REFERENCE.md create mode 100644 .gradle-docs/README.md create mode 100644 .gradle-docs/TASK_REFERENCE.md rename bin/{ => archived}/python3.10.6/bearsampp.conf (100%) rename bin/{ => archived}/python3.10.6/bin/python.bat (100%) rename bin/{ => archived}/python3.10.6/wheel/install.bat (100%) rename bin/{ => archived}/python3.10.6/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.10.9/bearsampp.conf (100%) rename bin/{ => archived}/python3.10.9/bin/python.bat (100%) rename bin/{ => archived}/python3.10.9/wheel/install.bat (100%) rename bin/{ => archived}/python3.10.9/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.11.5/bearsampp.conf (100%) rename bin/{ => archived}/python3.11.5/bin/python.bat (100%) rename bin/{ => archived}/python3.11.5/wheel/install.bat (100%) rename bin/{ => archived}/python3.11.5/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.11.6b0/bearsampp.conf (100%) rename bin/{ => archived}/python3.11.6b0/bin/python.bat (100%) rename bin/{ => archived}/python3.11.6b0/wheel/install.bat (100%) rename bin/{ => archived}/python3.11.6b0/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.11.8/bearsampp.conf (100%) rename bin/{ => archived}/python3.11.8/bin/python.bat (100%) rename bin/{ => archived}/python3.11.8/wheel/install.bat (100%) rename bin/{ => archived}/python3.11.8/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.12.2/bearsampp.conf (100%) rename bin/{ => archived}/python3.12.2/bin/python.bat (100%) rename bin/{ => archived}/python3.12.2/wheel/install.bat (100%) rename bin/{ => archived}/python3.12.2/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.12.6.0/bearsampp.conf (100%) rename bin/{ => archived}/python3.12.6.0/bin/python.bat (100%) rename bin/{ => archived}/python3.12.6.0/wheel/install.bat (100%) rename bin/{ => archived}/python3.12.6.0/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.12.8.0-b2/bearsampp.conf (100%) rename bin/{ => archived}/python3.12.8.0-b2/bin/python.bat (100%) rename bin/{ => archived}/python3.12.8.0-b2/wheel/install.bat (100%) rename bin/{ => archived}/python3.12.8.0-b2/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.12.9/bearsampp.conf (100%) rename bin/{ => archived}/python3.12.9/bin/python.bat (100%) rename bin/{ => archived}/python3.12.9/wheel/install.bat (100%) rename bin/{ => archived}/python3.12.9/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.13.2/bearsampp.conf (100%) rename bin/{ => archived}/python3.13.2/bin/python.bat (100%) rename bin/{ => archived}/python3.13.2/wheel/install.bat (100%) rename bin/{ => archived}/python3.13.2/wheel/wheel.properties (100%) rename bin/{ => archived}/python3.13.3/bearsampp.conf (100%) rename bin/{ => archived}/python3.13.3/bin/python.bat (100%) rename bin/{ => archived}/python3.13.3/wheel/install.bat (100%) rename bin/{ => archived}/python3.13.3/wheel/wheel.properties (100%) delete mode 100644 build.xml diff --git a/.gradle-docs/BUILD_SYSTEM.md b/.gradle-docs/BUILD_SYSTEM.md new file mode 100644 index 00000000..071f65de --- /dev/null +++ b/.gradle-docs/BUILD_SYSTEM.md @@ -0,0 +1,502 @@ +# Build System Guide + +This document provides detailed information about the Gradle build system for the Bearsampp Python module. + +## Overview + +The build system is implemented using pure Gradle (no wrapper) and provides: + +- **Pure Gradle Build**: No Ant dependencies, fully native Gradle implementation +- **Python-Specific Features**: PIP upgrades, wheel package management +- **Multiple Version Support**: Build any Python version in the `bin/` directory +- **Incremental Builds**: Gradle caching for faster builds +- **Parallel Execution**: Multi-threaded build execution +- **Interactive & Non-Interactive Modes**: Flexible build workflows + +## Architecture + +### Build Script Structure + +The main `build.gradle` file is organized into several sections: + +1. **Plugin Configuration**: Base plugin for fundamental build capabilities +2. **Property Loading**: Loads configuration from `build.properties` +3. **Project Configuration**: Sets up project metadata and paths +4. **Task Definitions**: Defines all build, verification, and help tasks +5. **Lifecycle Hooks**: Configures build lifecycle events + +### Key Components + +#### Properties Management + +The build system uses multiple property sources: + +- **build.properties**: Bundle configuration (name, version, type, format) +- **gradle.properties**: Gradle daemon and JVM settings +- **releases.properties**: Available Python release versions +- **wheel.properties**: Wheel package URLs (per Python version) + +#### Path Configuration + +```groovy +ext { + projectBasedir = projectDir.absolutePath + rootDir = projectDir.parent + devPath = file("${rootDir}/dev").absolutePath + buildPath = "${System.getProperty('user.home')}/Bearsampp-build" + tmpPath = "${buildPath}/tmp" + releasePath = "${buildPath}/release" +} +``` + +## Build Tasks + +### Core Build Tasks + +#### release + +Main task for building release packages. + +**Usage:** +```bash +# Interactive mode (lists available versions) +gradle release + +# Non-interactive mode (specify version) +gradle release "-PbundleVersion=3.13.5" +``` + +**Process:** +1. Validates Python version exists +2. Creates temporary build directory +3. Copies bundle files (excludes pyqt5) +4. Upgrades PIP to latest version +5. Downloads wheel packages +6. Installs wheel packages +7. Creates 7z archive +8. Cleans up temporary files + +**Properties:** +- `bundleVersion`: Python version to build (e.g., "3.13.5") + +#### clean + +Removes build artifacts and temporary files. + +**Usage:** +```bash +gradle clean +``` + +**Cleans:** +- `build/` directory +- Temporary build directories in configured build path + +### Verification Tasks + +#### verify + +Comprehensive environment verification. + +**Usage:** +```bash +gradle verify +``` + +**Checks:** +- Java version (8+) +- Required files (build.gradle, build.properties, releases.properties) +- Dev directory structure +- Python versions in bin/ +- 7-Zip availability + +#### validateProperties + +Validates build.properties configuration. + +**Usage:** +```bash +gradle validateProperties +``` + +**Validates:** +- bundle.name +- bundle.release +- bundle.type +- bundle.format + +#### validatePythonVersion + +Validates Python version directory structure. + +**Usage:** +```bash +gradle validatePythonVersion "-PbundleVersion=3.13.5" +``` + +**Checks:** +- Version directory exists +- bin/ subdirectory +- wheel/ subdirectory +- bearsampp.conf file +- bin/python.bat file +- wheel.properties file +- install.bat file +- Wheel URL configuration + +### Information Tasks + +#### info + +Displays comprehensive build information. + +**Usage:** +```bash +gradle info +``` + +**Shows:** +- Project metadata +- Bundle properties +- Path configuration +- Java version +- Gradle version +- Available features +- Quick start commands + +#### listVersions + +Lists available Python versions in bin/ directory. + +**Usage:** +```bash +gradle listVersions +``` + +**Output:** +- All Python versions found +- Wheel package information (if available) +- Example build command + +#### listReleases + +Lists all releases from releases.properties. + +**Usage:** +```bash +gradle listReleases +``` + +**Output:** +- Version numbers +- Download URLs +- Total count + +#### showWheelInfo + +Displays wheel package information for a specific version. + +**Usage:** +```bash +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +**Shows:** +- Wheel URL +- Wheel filename +- Wheel directory location +- Install script content + +## Build Configuration + +### Gradle Properties + +Configure Gradle behavior in `gradle.properties`: + +```properties +# Enable Gradle daemon for faster builds +org.gradle.daemon=true + +# Enable parallel execution +org.gradle.parallel=true + +# Enable build caching +org.gradle.caching=true + +# JVM settings +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError + +# Console output +org.gradle.console=auto +org.gradle.warning.mode=all +``` + +### Bundle Properties + +Configure bundle in `build.properties`: + +```properties +# Bundle identification +bundle.name = python +bundle.release = 2025.8.21 +bundle.type = tools +bundle.format = 7z + +# Optional: Custom build path +#build.path = C:/Bearsampp-build +``` + +### Settings Configuration + +Configure Gradle features in `settings.gradle`: + +```groovy +rootProject.name = 'module-python' + +// Enable stable configuration cache +enableFeaturePreview('STABLE_CONFIGURATION_CACHE') + +// Configure build cache +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + } +} +``` + +## Python Version Structure + +Each Python version in `bin/` must follow this structure: + +``` +bin/python{version}/ +├── bin/ +│ ├── python.bat # Python launcher script +│ └── python.exe # Python executable +├── wheel/ +│ ├── wheel.properties # Wheel package URL +│ └── install.bat # Wheel installation script +├── bearsampp.conf # Bearsampp configuration +└── [other Python files] +``` + +### wheel.properties Format + +```properties +wheel=https://example.com/path/to/package.whl +``` + +### install.bat Example + +```batch +@echo off +python.bat -m pip install wheel-package.whl +``` + +## Build Lifecycle + +### Task Execution Order + +When running `gradle release`: + +1. **Initialization Phase** + - Load settings.gradle + - Configure build cache + - Initialize project + +2. **Configuration Phase** + - Load build.gradle + - Load properties files + - Configure tasks + - Validate environment + +3. **Execution Phase** + - Execute release task + - Run Python-specific steps + - Create archive + - Clean up + +### Lifecycle Hooks + +```groovy +gradle.taskGraph.whenReady { graph -> + // Executed when task graph is ready + println "Starting Bearsampp Module Python Build" +} +``` + +## Advanced Features + +### Build Caching + +Gradle caching is enabled by default: + +- **Local Cache**: `.gradle/build-cache/` +- **Configuration Cache**: Speeds up configuration phase +- **Task Output Caching**: Reuses task outputs when inputs haven't changed + +### Parallel Execution + +Multiple tasks can run in parallel when enabled: + +```properties +org.gradle.parallel=true +``` + +### Incremental Builds + +Gradle tracks task inputs and outputs: + +- Only runs tasks when inputs change +- Skips up-to-date tasks +- Provides "FROM-CACHE" indicators + +## Customization + +### Custom Build Path + +Override the default build path: + +```properties +# In build.properties +build.path = D:/CustomBuildPath +``` + +### Custom Archive Format + +Change the archive format: + +```properties +# In build.properties +bundle.format = zip +``` + +Supported formats: 7z, zip, tar, tar.gz + +### Adding Custom Tasks + +Add custom tasks to `build.gradle`: + +```groovy +tasks.register('myCustomTask') { + group = 'custom' + description = 'My custom task' + + doLast { + println "Executing custom task" + } +} +``` + +## Performance Optimization + +### JVM Tuning + +Adjust JVM settings for better performance: + +```properties +# Increase heap size for large builds +org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g + +# Enable G1GC for better garbage collection +org.gradle.jvmargs=-Xmx2g -XX:+UseG1GC +``` + +### Daemon Configuration + +The Gradle daemon improves build performance: + +```properties +# Enable daemon (default) +org.gradle.daemon=true + +# Daemon idle timeout (milliseconds) +org.gradle.daemon.idletimeout=3600000 +``` + +### Build Cache + +Optimize cache settings: + +```groovy +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + removeUnusedEntriesAfterDays = 30 + } +} +``` + +## Troubleshooting + +### Common Issues + +#### "Dev path not found" + +**Cause**: Missing dev project in parent directory + +**Solution**: Ensure dev project exists: +``` +Bearsampp-development/ +├── module-python/ +└── dev/ +``` + +#### "7-Zip not found" + +**Cause**: 7z command not in PATH + +**Solution**: Install 7-Zip and add to PATH + +#### "Bundle version not found" + +**Cause**: Python version doesn't exist in bin/ + +**Solution**: Verify version directory exists: +```bash +gradle listVersions +``` + +#### Build Hangs + +**Cause**: Gradle daemon issues + +**Solution**: Stop daemon and retry: +```bash +gradle --stop +gradle release "-PbundleVersion=3.13.5" +``` + +### Debug Mode + +Run with debug output: + +```bash +gradle release "-PbundleVersion=3.13.5" --debug +``` + +### Stack Traces + +Show full stack traces: + +```bash +gradle release "-PbundleVersion=3.13.5" --stacktrace +``` + +## Best Practices + +1. **Always verify environment first**: Run `gradle verify` before building +2. **Use specific versions**: Specify `-PbundleVersion` for reproducible builds +3. **Clean between major changes**: Run `gradle clean` when switching versions +4. **Monitor build cache**: Periodically clean old cache entries +5. **Keep Gradle updated**: Use latest stable Gradle version +6. **Document custom changes**: Add comments for any build script modifications + +## References + +- [Gradle Documentation](https://docs.gradle.org/) +- [Gradle Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) +- [Gradle Performance](https://docs.gradle.org/current/userguide/performance.html) +- [Bearsampp Project](https://github.com/bearsampp/bearsampp) diff --git a/.gradle-docs/CHANGELOG.md b/.gradle-docs/CHANGELOG.md new file mode 100644 index 00000000..0b0737aa --- /dev/null +++ b/.gradle-docs/CHANGELOG.md @@ -0,0 +1,229 @@ +# Gradle Build System Changelog + +## Version 2025.8.21 - Pure Gradle Migration + +### Major Changes + +#### ✅ Pure Gradle Implementation +- **Removed**: All Ant dependencies and build files +- **Removed**: `build.xml` (Ant build file) +- **Removed**: Ant task imports from `build.gradle` +- **Removed**: `ant.get()` calls replaced with native Groovy URL download +- **Added**: Pure Gradle implementation using native Gradle/Groovy APIs + +#### ✅ No Gradle Wrapper +- Project uses pure Gradle installation (no wrapper scripts) +- Users must have Gradle 7.0+ installed on their system +- Provides better control over Gradle version +- Reduces repository size + +#### ✅ Comprehensive Documentation +- **Added**: `.gradle-docs/` directory with complete documentation +- **Added**: `GETTING_STARTED.md` - Setup and quick start guide +- **Added**: `BUILD_SYSTEM.md` - Detailed build system documentation +- **Added**: `TASK_REFERENCE.md` - Complete task reference +- **Added**: `CONFIGURATION.md` - Configuration options and tuning +- **Added**: `README.md` - Documentation index and overview +- **Updated**: Main `README.md` with build system information + +### Features + +#### Build Tasks +- ✅ `release` - Build release packages (interactive and non-interactive modes) +- ✅ `clean` - Clean build artifacts and temporary files + +#### Verification Tasks +- ✅ `verify` - Comprehensive environment verification +- ✅ `validateProperties` - Validate build.properties configuration +- ✅ `validatePythonVersion` - Validate Python version structure + +#### Help Tasks +- ✅ `info` - Display build configuration information +- ✅ `listVersions` - List available Python versions +- ✅ `listReleases` - List releases from releases.properties +- ✅ `showWheelInfo` - Display wheel package information + +### Technical Improvements + +#### Native Gradle Features +- **Build Caching**: Enabled for faster incremental builds +- **Parallel Execution**: Support for multi-threaded builds +- **Configuration Cache**: Experimental support for faster configuration +- **File System Watching**: Automatic change detection + +#### Python-Specific Features +- **PIP Upgrades**: Automatic PIP upgrade during build +- **Wheel Management**: Download and install wheel packages +- **Multi-Version Support**: Build any Python version in bin/ +- **PyQt5 Exclusion**: Automatic exclusion of PyQt5 directories + +#### Build Process +- **Pure Groovy**: All file operations use native Groovy APIs +- **No External Dependencies**: No Ant or other build tool dependencies +- **Native Downloads**: URL downloads using Groovy's built-in capabilities +- **Process Execution**: Direct command execution for Python and 7z + +### Migration Details + +#### Removed Files +``` +- build.xml # Ant build file +``` + +#### Modified Files +``` +~ build.gradle # Converted to pure Gradle +~ README.md # Updated with build system info +``` + +#### Added Files +``` ++ .gradle-docs/README.md # Documentation index ++ .gradle-docs/GETTING_STARTED.md # Getting started guide ++ .gradle-docs/BUILD_SYSTEM.md # Build system guide ++ .gradle-docs/TASK_REFERENCE.md # Task reference ++ .gradle-docs/CONFIGURATION.md # Configuration guide ++ .gradle-docs/CHANGELOG.md # This file +``` + +### Breaking Changes + +#### None - Fully Compatible +- Same build output format +- Same directory structure +- Same Python version support +- Same wheel package handling +- Same configuration files + +### Upgrade Path + +#### From Ant Build +1. Remove any Ant-specific scripts or references +2. Ensure Gradle 7.0+ is installed +3. Run `gradle verify` to check environment +4. Use `gradle release` instead of `ant release` + +#### Command Mapping +``` +ant release -Dinput.bundle=3.13.5 → gradle release "-PbundleVersion=3.13.5" +ant clean → gradle clean +``` + +### Benefits + +#### Performance +- ⚡ Faster builds with Gradle caching +- ⚡ Parallel task execution +- ⚡ Incremental builds +- ⚡ Configuration cache support + +#### Maintainability +- 🔧 Pure Gradle - no mixed build systems +- 🔧 Better IDE integration +- 🔧 Modern build practices +- 🔧 Comprehensive documentation + +#### Developer Experience +- 📚 Complete documentation +- 📚 Interactive and non-interactive modes +- 📚 Comprehensive verification tasks +- 📚 Clear error messages + +### System Requirements + +#### Required +- Java 8 or higher +- Gradle 7.0 or higher +- 7-Zip (for archive creation) +- Python versions in bin/ directory + +#### Recommended +- Java 11 or higher +- Gradle 8.0 or higher +- 4GB RAM +- SSD storage + +### Configuration + +#### build.properties +```properties +bundle.name = python +bundle.release = 2025.8.21 +bundle.type = tools +bundle.format = 7z +``` + +#### gradle.properties +```properties +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m +``` + +### Known Issues + +None at this time. + +### Future Enhancements + +#### Planned +- [ ] Remote build cache support +- [ ] Multi-platform support (Linux, macOS) +- [ ] Automated testing integration +- [ ] Dependency version management +- [ ] Custom plugin development + +#### Under Consideration +- [ ] Docker build support +- [ ] CI/CD pipeline templates +- [ ] Automated release notes generation +- [ ] Version bump automation + +### Testing + +#### Verified Scenarios +- ✅ Fresh environment setup +- ✅ Building single Python version +- ✅ Building multiple Python versions +- ✅ Clean and rebuild +- ✅ Incremental builds +- ✅ Wheel package download and installation +- ✅ PIP upgrade process +- ✅ Archive creation (7z format) + +#### Test Environment +- Windows 10/11 +- Java 17 +- Gradle 8.5 +- Python 3.10.6 through 3.13.5 + +### Documentation + +#### Available Guides +1. **Getting Started** - Setup and basic usage +2. **Build System** - Architecture and internals +3. **Task Reference** - Complete task documentation +4. **Configuration** - Configuration options and tuning + +#### Quick Links +- [Getting Started](.gradle-docs/GETTING_STARTED.md) +- [Build System](.gradle-docs/BUILD_SYSTEM.md) +- [Task Reference](.gradle-docs/TASK_REFERENCE.md) +- [Configuration](.gradle-docs/CONFIGURATION.md) + +### Contributors + +- Bearsampp Team + +### License + +See [LICENSE](../LICENSE) for details. + +--- + +**Migration Date**: 2025-08-21 + +**Status**: ✅ Complete + +**Compatibility**: Fully backward compatible diff --git a/.gradle-docs/CONFIGURATION.md b/.gradle-docs/CONFIGURATION.md new file mode 100644 index 00000000..855c958d --- /dev/null +++ b/.gradle-docs/CONFIGURATION.md @@ -0,0 +1,652 @@ +# Configuration Guide + +This guide covers all configuration options for the Bearsampp Python module build system. + +## Configuration Files + +### build.properties + +Main bundle configuration file. + +**Location**: `build.properties` + +**Format**: Java Properties + +**Required Properties**: + +```properties +# Bundle name (used for directory naming) +bundle.name = python + +# Bundle release version +bundle.release = 2025.8.21 + +# Bundle type (tools, apps, bins) +bundle.type = tools + +# Archive format (7z, zip, tar, tar.gz) +bundle.format = 7z +``` + +**Optional Properties**: + +```properties +# Custom build path (defaults to ~/Bearsampp-build) +build.path = C:/Bearsampp-build + +# Custom temporary path (defaults to {build.path}/tmp) +#tmp.path = C:/Bearsampp-build/tmp + +# Custom release path (defaults to {build.path}/release) +#release.path = C:/Bearsampp-build/release +``` + +**Example**: + +```properties +bundle.name = python +bundle.release = 2025.8.21 +bundle.type = tools +bundle.format = 7z +build.path = D:/CustomBuildPath +``` + +--- + +### gradle.properties + +Gradle build configuration. + +**Location**: `gradle.properties` + +**Format**: Java Properties + +**Daemon Configuration**: + +```properties +# Enable Gradle daemon for faster builds +org.gradle.daemon=true + +# Daemon idle timeout in milliseconds (default: 3 hours) +org.gradle.daemon.idletimeout=10800000 +``` + +**Performance Configuration**: + +```properties +# Enable parallel execution +org.gradle.parallel=true + +# Maximum number of worker processes +org.gradle.workers.max=4 + +# Enable build caching +org.gradle.caching=true + +# Enable configuration on demand +org.gradle.configureondemand=false +``` + +**JVM Configuration**: + +```properties +# JVM arguments for Gradle +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError + +# For larger builds +#org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -XX:+UseG1GC +``` + +**Console Configuration**: + +```properties +# Console output mode (auto, plain, rich, verbose) +org.gradle.console=auto + +# Warning mode (all, fail, summary, none) +org.gradle.warning.mode=all + +# Logging level (quiet, warn, lifecycle, info, debug) +org.gradle.logging.level=lifecycle +``` + +**Build Configuration**: + +```properties +# Enable configuration cache (experimental) +org.gradle.unsafe.configuration-cache=true + +# Enable file system watching +org.gradle.vfs.watch=true + +# Enable verbose logging +org.gradle.logging.stacktrace=internal +``` + +**Example**: + +```properties +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g +org.gradle.console=rich +org.gradle.warning.mode=all +``` + +--- + +### settings.gradle + +Gradle settings configuration. + +**Location**: `settings.gradle` + +**Format**: Groovy DSL + +**Basic Configuration**: + +```groovy +// Project name +rootProject.name = 'module-python' +``` + +**Feature Previews**: + +```groovy +// Enable stable configuration cache +enableFeaturePreview('STABLE_CONFIGURATION_CACHE') + +// Enable type-safe project accessors +enableFeaturePreview('TYPESAFE_PROJECT_ACCESSORS') +``` + +**Build Cache Configuration**: + +```groovy +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + removeUnusedEntriesAfterDays = 30 + } +} +``` + +**Plugin Management**: + +```groovy +pluginManagement { + repositories { + gradlePluginPortal() + mavenCentral() + } +} +``` + +**Example**: + +```groovy +rootProject.name = 'module-python' + +enableFeaturePreview('STABLE_CONFIGURATION_CACHE') + +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + removeUnusedEntriesAfterDays = 30 + } +} + +gradle.rootProject { + println "Initializing Bearsampp Module Python Build" +} +``` + +--- + +### releases.properties + +Available Python releases configuration. + +**Location**: `releases.properties` + +**Format**: Java Properties + +**Structure**: + +```properties +{version}={download_url} +``` + +**Example**: + +```properties +3.10.6=https://www.python.org/ftp/python/3.10.6/python-3.10.6-amd64.exe +3.10.9=https://www.python.org/ftp/python/3.10.9/python-3.10.9-amd64.exe +3.11.5=https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe +3.11.8=https://www.python.org/ftp/python/3.11.8/python-3.11.8-amd64.exe +3.12.2=https://www.python.org/ftp/python/3.12.2/python-3.12.2-amd64.exe +3.12.9=https://www.python.org/ftp/python/3.12.9/python-3.12.9-amd64.exe +3.13.2=https://www.python.org/ftp/python/3.13.2/python-3.13.2-amd64.exe +3.13.5=https://www.python.org/ftp/python/3.13.5/python-3.13.5-amd64.exe +``` + +--- + +### wheel.properties + +Wheel package configuration (per Python version). + +**Location**: `bin/python{version}/wheel/wheel.properties` + +**Format**: Java Properties + +**Structure**: + +```properties +wheel={wheel_package_url} +``` + +**Example**: + +```properties +wheel=https://files.pythonhosted.org/packages/28/6c/640e3f5c734c296a7193a483a1a120ae66e0c3a5a562e6b3c4b8f8f3e1f/PyQt5-5.15.9-cp313-cp313-win_amd64.whl +``` + +**Multiple Wheels** (if needed): + +```properties +wheel.pyqt5=https://files.pythonhosted.org/packages/.../PyQt5-5.15.9-cp313-cp313-win_amd64.whl +wheel.numpy=https://files.pythonhosted.org/packages/.../numpy-1.24.3-cp313-cp313-win_amd64.whl +``` + +--- + +## Python Version Configuration + +### Directory Structure + +Each Python version must follow this structure: + +``` +bin/python{version}/ +├── bin/ +│ ├── python.bat # Python launcher +│ ├── python.exe # Python executable +│ └── [other binaries] +├── wheel/ +│ ├── wheel.properties # Wheel configuration +│ └── install.bat # Installation script +├── bearsampp.conf # Bearsampp configuration +├── Lib/ # Python libraries +├── DLLs/ # Python DLLs +└── [other Python files] +``` + +### bearsampp.conf + +Bearsampp module configuration. + +**Location**: `bin/python{version}/bearsampp.conf` + +**Format**: INI + +**Example**: + +```ini +[python] +name = "Python" +version = "3.13.5" +release = "2025.8.21" +``` + +### install.bat + +Wheel installation script. + +**Location**: `bin/python{version}/wheel/install.bat` + +**Format**: Batch Script + +**Example**: + +```batch +@echo off +cd .. +bin\python.bat -m pip install wheel\PyQt5-5.15.9-cp313-cp313-win_amd64.whl +``` + +**Multiple Wheels**: + +```batch +@echo off +cd .. +bin\python.bat -m pip install wheel\PyQt5-5.15.9-cp313-cp313-win_amd64.whl +bin\python.bat -m pip install wheel\numpy-1.24.3-cp313-cp313-win_amd64.whl +``` + +--- + +## Build Path Configuration + +### Default Paths + +```groovy +buildPath = "${System.getProperty('user.home')}/Bearsampp-build" +tmpPath = "${buildPath}/tmp" +releasePath = "${buildPath}/release" +``` + +**Windows Example**: +- Build Path: `C:/Users/username/Bearsampp-build` +- Temp Path: `C:/Users/username/Bearsampp-build/tmp` +- Release Path: `C:/Users/username/Bearsampp-build/release` + +### Custom Paths + +Override in `build.properties`: + +```properties +build.path = D:/CustomBuildPath +``` + +Results in: +- Build Path: `D:/CustomBuildPath` +- Temp Path: `D:/CustomBuildPath/tmp` +- Release Path: `D:/CustomBuildPath/release` + +--- + +## Archive Format Configuration + +### Supported Formats + +- **7z** (default): 7-Zip format, best compression +- **zip**: Standard ZIP format +- **tar**: TAR archive +- **tar.gz**: Compressed TAR archive + +### Configuration + +In `build.properties`: + +```properties +bundle.format = 7z +``` + +### Format Comparison + +| Format | Compression | Speed | Compatibility | +|--------|-------------|-------|---------------| +| 7z | Excellent | Medium| Requires 7-Zip| +| zip | Good | Fast | Universal | +| tar | None | Fast | Unix/Linux | +| tar.gz | Good | Medium| Unix/Linux | + +--- + +## JVM Configuration + +### Memory Settings + +**Small Builds** (< 1GB): +```properties +org.gradle.jvmargs=-Xmx1g -XX:MaxMetaspaceSize=256m +``` + +**Medium Builds** (1-2GB): +```properties +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m +``` + +**Large Builds** (> 2GB): +```properties +org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g +``` + +### Garbage Collection + +**G1GC** (recommended for large heaps): +```properties +org.gradle.jvmargs=-Xmx4g -XX:+UseG1GC +``` + +**Parallel GC** (default): +```properties +org.gradle.jvmargs=-Xmx2g -XX:+UseParallelGC +``` + +### Debug Options + +**Heap Dump on OOM**: +```properties +org.gradle.jvmargs=-Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap-dump.hprof +``` + +**GC Logging**: +```properties +org.gradle.jvmargs=-Xmx2g -Xlog:gc*:file=gc.log +``` + +--- + +## Performance Tuning + +### Parallel Execution + +Enable parallel task execution: + +```properties +org.gradle.parallel=true +org.gradle.workers.max=4 +``` + +**Recommended Workers**: +- 2-4 cores: `workers.max=2` +- 4-8 cores: `workers.max=4` +- 8+ cores: `workers.max=8` + +### Build Cache + +Enable build caching: + +```properties +org.gradle.caching=true +``` + +Configure cache in `settings.gradle`: + +```groovy +buildCache { + local { + enabled = true + directory = file("${rootDir}/.gradle/build-cache") + removeUnusedEntriesAfterDays = 30 + } +} +``` + +### Configuration Cache + +Enable configuration cache (experimental): + +```properties +org.gradle.unsafe.configuration-cache=true +``` + +Or use feature preview in `settings.gradle`: + +```groovy +enableFeaturePreview('STABLE_CONFIGURATION_CACHE') +``` + +### File System Watching + +Enable file system watching: + +```properties +org.gradle.vfs.watch=true +``` + +--- + +## Environment Variables + +### Gradle Environment Variables + +```bash +# Gradle user home +GRADLE_USER_HOME=C:/Users/username/.gradle + +# Gradle options +GRADLE_OPTS=-Xmx2g -XX:MaxMetaspaceSize=512m + +# Java home +JAVA_HOME=C:/Program Files/Java/jdk-17 +``` + +### Build Environment Variables + +```bash +# Custom build path +BEARSAMPP_BUILD_PATH=D:/CustomBuildPath + +# Python version +PYTHON_VERSION=3.13.5 +``` + +--- + +## Advanced Configuration + +### Custom Task Configuration + +Add custom configuration to `build.gradle`: + +```groovy +ext { + // Custom properties + customBuildPath = System.getenv('CUSTOM_BUILD_PATH') ?: buildPath + skipWheelInstall = project.hasProperty('skipWheels') +} + +tasks.register('customRelease') { + group = 'build' + description = 'Custom release with additional steps' + + doLast { + // Custom build logic + } +} +``` + +### Conditional Configuration + +```groovy +if (project.hasProperty('production')) { + // Production configuration + ext.buildPath = 'D:/Production/Bearsampp-build' +} else { + // Development configuration + ext.buildPath = "${System.getProperty('user.home')}/Bearsampp-build" +} +``` + +### Profile-Based Configuration + +Create profile-specific properties: + +**gradle-dev.properties**: +```properties +org.gradle.jvmargs=-Xmx1g +build.path=./build-dev +``` + +**gradle-prod.properties**: +```properties +org.gradle.jvmargs=-Xmx4g +build.path=D:/Production/Bearsampp-build +``` + +Use with: +```bash +gradle release -Pprofile=prod +``` + +--- + +## Configuration Validation + +### Validate Configuration + +```bash +# Validate build.properties +gradle validateProperties + +# Validate Python version +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# Verify entire environment +gradle verify +``` + +### Configuration Checklist + +- [ ] `build.properties` has all required properties +- [ ] `gradle.properties` has appropriate JVM settings +- [ ] Python versions exist in `bin/` directory +- [ ] Each version has `wheel.properties` and `install.bat` +- [ ] 7-Zip is installed and in PATH +- [ ] Dev directory exists in parent directory +- [ ] Build path is writable + +--- + +## Troubleshooting Configuration + +### Common Issues + +**Issue**: Out of memory errors + +**Solution**: Increase heap size in `gradle.properties`: +```properties +org.gradle.jvmargs=-Xmx4g +``` + +**Issue**: Slow builds + +**Solution**: Enable parallel execution and caching: +```properties +org.gradle.parallel=true +org.gradle.caching=true +``` + +**Issue**: Configuration cache warnings + +**Solution**: Disable configuration cache: +```properties +org.gradle.unsafe.configuration-cache=false +``` + +--- + +## Best Practices + +1. **Use version control**: Track all configuration files in Git +2. **Document changes**: Add comments for custom configurations +3. **Test configurations**: Validate after changes with `gradle verify` +4. **Use profiles**: Separate dev and production configurations +5. **Monitor performance**: Adjust JVM settings based on build times +6. **Keep updated**: Use latest stable Gradle version +7. **Backup configurations**: Keep copies of working configurations + +--- + +## See Also + +- [Getting Started Guide](GETTING_STARTED.md) +- [Build System Guide](BUILD_SYSTEM.md) +- [Task Reference](TASK_REFERENCE.md) +- [Gradle Configuration](https://docs.gradle.org/current/userguide/build_environment.html) diff --git a/.gradle-docs/GETTING_STARTED.md b/.gradle-docs/GETTING_STARTED.md new file mode 100644 index 00000000..9ca67e56 --- /dev/null +++ b/.gradle-docs/GETTING_STARTED.md @@ -0,0 +1,215 @@ +# Getting Started with Bearsampp Module Python Build + +This guide will help you get started with building the Bearsampp Python module using Gradle. + +## Prerequisites + +Before you begin, ensure you have the following installed: + +1. **Java Development Kit (JDK) 8 or higher** + - Required to run Gradle + - Check version: `java -version` + +2. **Gradle 7.0 or higher** + - Install from: https://gradle.org/install/ + - Check version: `gradle --version` + - **Note**: This project uses pure Gradle without wrapper scripts + +3. **7-Zip** + - Required for creating release archives + - Install from: https://www.7-zip.org/ + - Ensure `7z` command is available in your PATH + +4. **Python** + - Python versions should be placed in the `bin/` directory + - Each version should follow the naming convention: `python{version}` + - Example: `bin/python3.13.5/` + +## Project Structure + +``` +module-python/ +├── bin/ # Python version directories +│ ├── python3.13.5/ +│ │ ├── bin/ +│ │ │ └── python.bat +│ │ ├── wheel/ +│ │ │ ├── wheel.properties +│ │ │ └── install.bat +│ │ └── bearsampp.conf +│ └── python3.12.9/ +├── build.gradle # Main Gradle build script +├── settings.gradle # Gradle settings +├── gradle.properties # Gradle configuration +├── build.properties # Bundle configuration +└── releases.properties # Available releases +``` + +## Quick Start + +### 1. Verify Your Environment + +First, verify that your build environment is properly configured: + +```bash +gradle verify +``` + +This will check: +- Java version +- Required files +- Dev directory structure +- Available Python versions +- 7-Zip availability + +### 2. List Available Python Versions + +To see which Python versions are available for building: + +```bash +gradle listVersions +``` + +### 3. Build a Release + +To build a release for a specific Python version: + +```bash +gradle release "-PbundleVersion=3.13.5" +``` + +Or run interactively to see available versions: + +```bash +gradle release +``` + +### 4. View Build Information + +To display detailed build configuration: + +```bash +gradle info +``` + +## Common Tasks + +### List All Available Tasks + +```bash +gradle tasks +``` + +### Clean Build Artifacts + +```bash +gradle clean +``` + +### Validate Build Properties + +```bash +gradle validateProperties +``` + +### Validate Python Version Structure + +```bash +gradle validatePythonVersion "-PbundleVersion=3.13.5" +``` + +### Show Wheel Package Information + +```bash +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +### List Available Releases + +```bash +gradle listReleases +``` + +## Build Process + +When you run `gradle release`, the following steps are executed: + +1. **Validation**: Verifies the specified Python version exists +2. **Copy Files**: Copies bundle files to temporary directory +3. **Upgrade PIP**: Upgrades PIP to the latest version +4. **Download Wheels**: Downloads wheel packages specified in `wheel.properties` +5. **Install Wheels**: Installs wheel packages using `install.bat` +6. **Create Archive**: Creates a 7z archive of the bundle +7. **Cleanup**: Removes temporary files + +## Configuration Files + +### build.properties + +Main bundle configuration: + +```properties +bundle.name = python +bundle.release = 2025.8.21 +bundle.type = tools +bundle.format = 7z +``` + +### gradle.properties + +Gradle build configuration: + +```properties +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m +``` + +### wheel.properties + +Located in each Python version's `wheel/` directory: + +```properties +wheel=https://example.com/path/to/wheel-package.whl +``` + +## Troubleshooting + +### Build Fails with "Dev path not found" + +Ensure the `dev` project exists in the parent directory: +``` +Bearsampp-development/ +├── module-python/ +└── dev/ +``` + +### Build Fails with "7-Zip not found" + +Install 7-Zip and ensure the `7z` command is in your PATH. + +### Python Version Not Found + +Ensure the Python version directory exists in `bin/` and follows the naming convention: +``` +bin/python{version}/ +``` + +### PIP Upgrade Fails + +Ensure the Python installation is valid and `bin/python.bat` exists. + +## Next Steps + +- Read the [Build System Guide](BUILD_SYSTEM.md) for detailed information +- Check [Task Reference](TASK_REFERENCE.md) for all available tasks +- See [Configuration Guide](CONFIGURATION.md) for advanced configuration options + +## Getting Help + +- View all tasks: `gradle tasks --all` +- View build info: `gradle info` +- Check environment: `gradle verify` + +For issues, please report on the [Bearsampp repository](https://github.com/bearsampp/bearsampp/issues). diff --git a/.gradle-docs/QUICK_REFERENCE.md b/.gradle-docs/QUICK_REFERENCE.md new file mode 100644 index 00000000..4636c951 --- /dev/null +++ b/.gradle-docs/QUICK_REFERENCE.md @@ -0,0 +1,191 @@ +# Quick Reference Card + +## Essential Commands + +### Build Commands +```bash +# Build a release (interactive - shows available versions) +gradle release + +# Build a release (non-interactive - specify version) +gradle release "-PbundleVersion=3.13.5" + +# Clean build artifacts +gradle clean +``` + +### Verification Commands +```bash +# Verify build environment +gradle verify + +# Validate build.properties +gradle validateProperties + +# Validate Python version structure +gradle validatePythonVersion "-PbundleVersion=3.13.5" +``` + +### Information Commands +```bash +# Display build information +gradle info + +# List all available tasks +gradle tasks + +# List available Python versions +gradle listVersions + +# List available releases +gradle listReleases + +# Show wheel package information +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +## Common Workflows + +### First-Time Setup +```bash +gradle verify +gradle listVersions +gradle validatePythonVersion "-PbundleVersion=3.13.5" +gradle release "-PbundleVersion=3.13.5" +``` + +### Daily Development +```bash +gradle validateProperties +gradle release "-PbundleVersion=3.13.5" +gradle clean +``` + +### Troubleshooting +```bash +gradle verify +gradle validatePythonVersion "-PbundleVersion=3.13.5" +gradle showWheelInfo "-PbundleVersion=3.13.5" +gradle release "-PbundleVersion=3.13.5" --debug +``` + +## Configuration Files + +### build.properties +```properties +bundle.name = python +bundle.release = 2025.8.21 +bundle.type = tools +bundle.format = 7z +``` + +### gradle.properties +```properties +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m +``` + +## Directory Structure + +``` +module-python/ +├── .gradle-docs/ # Documentation +├── bin/ # Python versions +│ └── python{version}/ +│ ├── bin/ +│ ├── wheel/ +│ └── bearsampp.conf +├── build.gradle # Build script +├── settings.gradle # Settings +├── gradle.properties # Gradle config +└── build.properties # Bundle config +``` + +## Task Groups + +### Build +- `release` - Build release package +- `clean` - Clean build artifacts + +### Verification +- `verify` - Verify environment +- `validateProperties` - Validate properties +- `validatePythonVersion` - Validate version + +### Help +- `info` - Build information +- `listVersions` - List versions +- `listReleases` - List releases +- `showWheelInfo` - Wheel information + +## Gradle Options + +### Debug & Logging +```bash +--debug # Debug output +--info # Info output +--stacktrace # Show stack traces +--scan # Build scan +``` + +### Performance +```bash +--parallel # Parallel execution +--build-cache # Enable build cache +--no-daemon # Disable daemon +--max-workers=4 # Max workers +``` + +### Other +```bash +--dry-run # Dry run +--continue # Continue on failure +--refresh-dependencies # Refresh dependencies +``` + +## Exit Codes + +- `0` - Success +- `1` - General error +- `2` - Configuration error +- `3` - Execution error +- `4` - Validation error + +## Requirements + +### Software +- Java 8+ +- Gradle 7.0+ +- 7-Zip + +### System +- Windows +- 2GB RAM (4GB recommended) +- 1GB disk space + +## Documentation + +- [Getting Started](GETTING_STARTED.md) +- [Build System](BUILD_SYSTEM.md) +- [Task Reference](TASK_REFERENCE.md) +- [Configuration](CONFIGURATION.md) + +## Support + +- Documentation: `.gradle-docs/` +- Issues: https://github.com/bearsampp/bearsampp/issues +- Website: https://bearsampp.com + +## Quick Tips + +1. Always run `gradle verify` first +2. Use `-PbundleVersion` for non-interactive builds +3. Enable build cache for faster builds +4. Use `--debug` for troubleshooting +5. Check documentation for detailed info + +--- + +**Version**: 2025.8.21 | **Type**: Pure Gradle (No Wrapper, No Ant) diff --git a/.gradle-docs/README.md b/.gradle-docs/README.md new file mode 100644 index 00000000..3173113c --- /dev/null +++ b/.gradle-docs/README.md @@ -0,0 +1,363 @@ +# Gradle Build System Documentation + +Complete documentation for the Bearsampp Python module Gradle build system. + +## Overview + +This directory contains comprehensive documentation for building the Bearsampp Python module using pure Gradle (no wrapper, no Ant dependencies). + +## Documentation Structure + +### 🚀 [Quick Reference Card](QUICK_REFERENCE.md) + +**Essential commands and quick tips.** + +- Essential commands (build, verify, info) +- Common workflows +- Configuration file examples +- Task groups overview +- Gradle options +- Quick tips + +**Best for**: Quick lookup, command reference + +### 📘 [Getting Started Guide](GETTING_STARTED.md) + +**Start here if you're new to the build system.** + +- Prerequisites and installation +- Project structure overview +- Quick start guide +- Common tasks +- Build process explanation +- Configuration files overview +- Troubleshooting basics + +**Best for**: First-time users, setup and installation + +### 🏗️ [Build System Guide](BUILD_SYSTEM.md) + +**Deep dive into the build system architecture.** + +- Build system overview +- Architecture and components +- Build tasks in detail +- Build lifecycle +- Advanced features (caching, parallel execution) +- Customization options +- Performance optimization +- Troubleshooting and debugging + +**Best for**: Understanding how the build works, advanced usage + +### 📋 [Task Reference](TASK_REFERENCE.md) + +**Complete reference for all available tasks.** + +- Build tasks (release, clean) +- Verification tasks (verify, validate*) +- Help tasks (info, list*, show*) +- Task parameters and options +- Task dependencies +- Common task combinations +- Exit codes and output + +**Best for**: Quick reference, finding specific tasks + +### ⚙️ [Configuration Guide](CONFIGURATION.md) + +**Detailed configuration options and settings.** + +- Configuration files (build.properties, gradle.properties, etc.) +- Python version configuration +- Build path configuration +- Archive format options +- JVM configuration +- Performance tuning +- Environment variables +- Advanced configuration + +**Best for**: Customizing the build, performance tuning + +## Quick Reference + +### Essential Commands + +```bash +# Verify environment +gradle verify + +# List available Python versions +gradle listVersions + +# Build a release +gradle release "-PbundleVersion=3.13.5" + +# Clean build artifacts +gradle clean + +# View build information +gradle info + +# List all tasks +gradle tasks +``` + +### Key Files + +| File | Purpose | +|------|---------| +| `build.gradle` | Main build script | +| `settings.gradle` | Gradle settings | +| `gradle.properties` | Gradle configuration | +| `build.properties` | Bundle configuration | +| `releases.properties` | Available Python releases | + +### Directory Structure + +``` +module-python/ +├── .gradle-docs/ # This documentation +├── bin/ # Python versions +│ └── python{version}/ +│ ├── bin/ +│ ├── wheel/ +│ └── bearsampp.conf +├── build.gradle # Build script +├── settings.gradle # Settings +├── gradle.properties # Gradle config +└── build.properties # Bundle config +``` + +## Documentation Index + +### By Topic + +#### Getting Started +- [Prerequisites](GETTING_STARTED.md#prerequisites) +- [Quick Start](GETTING_STARTED.md#quick-start) +- [Common Tasks](GETTING_STARTED.md#common-tasks) + +#### Build Tasks +- [Release Task](TASK_REFERENCE.md#release) +- [Clean Task](TASK_REFERENCE.md#clean) +- [Build Process](BUILD_SYSTEM.md#build-tasks) + +#### Configuration +- [Build Properties](CONFIGURATION.md#buildproperties) +- [Gradle Properties](CONFIGURATION.md#gradleproperties) +- [Python Version Config](CONFIGURATION.md#python-version-configuration) + +#### Verification +- [Environment Verification](TASK_REFERENCE.md#verify) +- [Property Validation](TASK_REFERENCE.md#validateproperties) +- [Version Validation](TASK_REFERENCE.md#validatepythonversion) + +#### Advanced Topics +- [Build System Architecture](BUILD_SYSTEM.md#architecture) +- [Performance Optimization](BUILD_SYSTEM.md#performance-optimization) +- [Custom Tasks](BUILD_SYSTEM.md#customization) + +### By User Type + +#### New Users +1. [Getting Started Guide](GETTING_STARTED.md) +2. [Quick Start](GETTING_STARTED.md#quick-start) +3. [Common Tasks](GETTING_STARTED.md#common-tasks) + +#### Developers +1. [Build System Guide](BUILD_SYSTEM.md) +2. [Task Reference](TASK_REFERENCE.md) +3. [Configuration Guide](CONFIGURATION.md) + +#### Build Engineers +1. [Build System Architecture](BUILD_SYSTEM.md#architecture) +2. [Performance Optimization](BUILD_SYSTEM.md#performance-optimization) +3. [Advanced Configuration](CONFIGURATION.md#advanced-configuration) + +## Features + +### Pure Gradle Build +- ✅ No Gradle wrapper scripts +- ✅ No Ant dependencies +- ✅ Native Gradle implementation +- ✅ Modern build practices + +### Python-Specific Features +- ✅ Automatic PIP upgrades +- ✅ Wheel package management +- ✅ Multiple version support +- ✅ PyQt5 exclusion handling + +### Build Features +- ✅ Incremental builds +- ✅ Build caching +- ✅ Parallel execution +- ✅ Configuration cache +- ✅ Interactive & non-interactive modes + +### Verification Features +- ✅ Environment verification +- ✅ Property validation +- ✅ Version structure validation +- ✅ Dependency checking + +## Common Workflows + +### First-Time Setup + +```bash +# 1. Verify environment +gradle verify + +# 2. View available versions +gradle listVersions + +# 3. Validate a version +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# 4. Build release +gradle release "-PbundleVersion=3.13.5" +``` + +### Daily Development + +```bash +# Check configuration +gradle validateProperties + +# Build release +gradle release "-PbundleVersion=3.13.5" + +# Clean up +gradle clean +``` + +### Troubleshooting + +```bash +# Verify environment +gradle verify + +# Check version structure +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# Check wheel info +gradle showWheelInfo "-PbundleVersion=3.13.5" + +# Build with debug output +gradle release "-PbundleVersion=3.13.5" --debug +``` + +## Migration from Ant + +This build system replaces the previous Ant-based build: + +### What Changed +- ❌ Removed: `build.xml` (Ant build file) +- ❌ Removed: Ant task imports +- ❌ Removed: Ant dependencies +- ✅ Added: Pure Gradle implementation +- ✅ Added: Native Gradle tasks +- ✅ Added: Comprehensive documentation + +### Migration Benefits +- Faster builds with caching +- Better dependency management +- Modern build practices +- Improved maintainability +- Better IDE integration + +### Compatibility +- Same build output +- Same directory structure +- Same Python version support +- Same wheel package handling + +## Requirements + +### Software Requirements +- Java 8 or higher +- Gradle 7.0 or higher +- 7-Zip (for archive creation) +- Python (versions in bin/ directory) + +### System Requirements +- Windows (primary platform) +- 2GB RAM minimum (4GB recommended) +- 1GB free disk space + +## Support + +### Getting Help + +1. **Check Documentation**: Start with the [Getting Started Guide](GETTING_STARTED.md) +2. **Run Verification**: Use `gradle verify` to check your environment +3. **View Task Help**: Use `gradle tasks` to see available tasks +4. **Debug Output**: Use `--debug` or `--stacktrace` for detailed output + +### Reporting Issues + +For issues, please report on the [Bearsampp repository](https://github.com/bearsampp/bearsampp/issues). + +Include: +- Gradle version (`gradle --version`) +- Java version (`java -version`) +- Error message and stack trace +- Steps to reproduce + +## Contributing + +### Documentation Contributions + +To improve this documentation: + +1. Edit the relevant `.md` file +2. Follow the existing structure and style +3. Test any code examples +4. Submit a pull request + +### Build System Contributions + +To contribute to the build system: + +1. Read the [Build System Guide](BUILD_SYSTEM.md) +2. Test changes thoroughly +3. Update documentation +4. Submit a pull request + +## Version History + +### 2025.8.21 +- Initial pure Gradle implementation +- Removed Ant dependencies +- Added comprehensive documentation +- Added verification tasks +- Added Python-specific build features + +## License + +This documentation is part of the Bearsampp project. + +See [LICENSE](../LICENSE) for details. + +## Additional Resources + +### External Links +- [Gradle Documentation](https://docs.gradle.org/) +- [Gradle Build Cache](https://docs.gradle.org/current/userguide/build_cache.html) +- [Gradle Performance](https://docs.gradle.org/current/userguide/performance.html) +- [Bearsampp Project](https://github.com/bearsampp/bearsampp) +- [Python Official Site](https://www.python.org/) + +### Related Projects +- [Bearsampp](https://github.com/bearsampp/bearsampp) - Main project +- [module-php](https://github.com/Bearsampp/module-php) - PHP module (similar build system) + +--- + +**Last Updated**: 2025-08-21 + +**Maintained By**: Bearsampp Team + +**Questions?** Check the [Getting Started Guide](GETTING_STARTED.md) or open an issue. diff --git a/.gradle-docs/TASK_REFERENCE.md b/.gradle-docs/TASK_REFERENCE.md new file mode 100644 index 00000000..e5eb626b --- /dev/null +++ b/.gradle-docs/TASK_REFERENCE.md @@ -0,0 +1,605 @@ +# Task Reference + +Complete reference for all Gradle tasks available in the Bearsampp Python module build system. + +## Task Groups + +- [Build Tasks](#build-tasks) +- [Verification Tasks](#verification-tasks) +- [Help Tasks](#help-tasks) + +--- + +## Build Tasks + +### release + +Build a release package for a specific Python version. + +**Group**: build + +**Description**: Build release package (interactive or use -PbundleVersion=X.X.X for non-interactive) + +**Usage**: +```bash +# Interactive mode - lists available versions +gradle release + +# Non-interactive mode - specify version +gradle release "-PbundleVersion=3.13.5" +``` + +**Parameters**: +- `bundleVersion` (optional): Python version to build (e.g., "3.13.5") + +**Process**: +1. Validates Python version exists in `bin/` directory +2. Creates temporary build directory +3. Copies bundle files (excludes pyqt5) +4. Upgrades PIP to latest version +5. Downloads wheel packages from wheel.properties +6. Installs wheel packages using install.bat +7. Creates 7z archive in release directory +8. Cleans up temporary files + +**Output**: +- Release archive: `{buildPath}/release/python{version}.7z` + +**Example**: +```bash +gradle release "-PbundleVersion=3.13.5" +``` + +**Exit Codes**: +- 0: Success +- 1: Version not found +- 2: PIP upgrade failed +- 3: Wheel installation failed +- 4: Archive creation failed + +--- + +### clean + +Clean build artifacts and temporary files. + +**Group**: build + +**Description**: Clean build artifacts and temporary files + +**Usage**: +```bash +gradle clean +``` + +**Cleans**: +- `build/` directory (Gradle build output) +- Temporary build directories in configured build path + +**Example**: +```bash +gradle clean +``` + +--- + +## Verification Tasks + +### verify + +Verify build environment and dependencies. + +**Group**: verification + +**Description**: Verify build environment and dependencies + +**Usage**: +```bash +gradle verify +``` + +**Checks**: +- ✓ Java 8+ installed +- ✓ build.gradle exists +- ✓ build.properties exists +- ✓ releases.properties exists +- ✓ dev directory exists +- ✓ bin directory exists +- ✓ Python versions available +- ✓ 7-Zip command available + +**Output**: +``` +Environment Check Results: +------------------------------------------------------------ + [PASS] Java 8+ + [PASS] build.gradle + [PASS] build.properties + [PASS] releases.properties + [PASS] dev directory + [PASS] bin directory + [PASS] Python versions available + [PASS] 7-Zip available +------------------------------------------------------------ + +[SUCCESS] All checks passed! Build environment is ready. +``` + +**Example**: +```bash +gradle verify +``` + +--- + +### validateProperties + +Validate build.properties configuration. + +**Group**: verification + +**Description**: Validate build.properties configuration + +**Usage**: +```bash +gradle validateProperties +``` + +**Validates**: +- `bundle.name` is present and not empty +- `bundle.release` is present and not empty +- `bundle.type` is present and not empty +- `bundle.format` is present and not empty + +**Output**: +``` +Validating build.properties... +[SUCCESS] All required properties are present: + bundle.name = python + bundle.release = 2025.8.21 + bundle.type = tools + bundle.format = 7z +``` + +**Example**: +```bash +gradle validateProperties +``` + +--- + +### validatePythonVersion + +Validate Python version directory structure. + +**Group**: verification + +**Description**: Validate Python version directory structure (use -PbundleVersion=X.X.X) + +**Usage**: +```bash +gradle validatePythonVersion "-PbundleVersion=3.13.5" +``` + +**Parameters**: +- `bundleVersion` (required): Python version to validate + +**Checks**: +- ✓ Version directory exists +- ✓ bin/ subdirectory exists +- ✓ wheel/ subdirectory exists +- ✓ bearsampp.conf file exists +- ✓ bin/python.bat file exists +- ✓ wheel.properties file exists +- ✓ install.bat file exists +- ✓ Wheel URL is defined in wheel.properties + +**Output**: +``` +Validating Python version 3.13.5... +------------------------------------------------------------ + +Validation Results: +------------------------------------------------------------ + [PASS] bin directory + [PASS] wheel directory + [PASS] bearsampp.conf + [PASS] bin/python.bat + [PASS] wheel.properties + [PASS] install.bat + [PASS] wheel URL defined +------------------------------------------------------------ + +[SUCCESS] Python version 3.13.5 structure is valid +``` + +**Example**: +```bash +gradle validatePythonVersion "-PbundleVersion=3.13.5" +``` + +--- + +## Help Tasks + +### info + +Display build configuration information. + +**Group**: help + +**Description**: Display build configuration information + +**Usage**: +```bash +gradle info +``` + +**Displays**: +- Project name, version, description +- Bundle properties (name, release, type, format) +- Path configuration +- Java version and home +- Gradle version and home +- Python build features +- Available task groups +- Quick start commands + +**Example**: +```bash +gradle info +``` + +--- + +### listVersions + +List all available Python bundle versions in bin/ directory. + +**Group**: help + +**Description**: List all available Python bundle versions in bin/ directory + +**Usage**: +```bash +gradle listVersions +``` + +**Output**: +``` +Available python versions in bin/: +------------------------------------------------------------ + 3.10.6 + 3.10.9 + 3.11.5 + 3.11.8 + 3.12.2 + 3.12.9 [wheel: PyQt5-5.15.9-cp312-cp312-win_amd64.whl] + 3.13.2 + 3.13.3 + 3.13.5 [wheel: PyQt5-5.15.9-cp313-cp313-win_amd64.whl] +------------------------------------------------------------ +Total versions: 9 + +To build a specific version: + gradle release "-PbundleVersion=3.13.5" +``` + +**Example**: +```bash +gradle listVersions +``` + +--- + +### listReleases + +List all available releases from releases.properties. + +**Group**: help + +**Description**: List all available releases from releases.properties + +**Usage**: +```bash +gradle listReleases +``` + +**Output**: +``` +Available Python Releases: +-------------------------------------------------------------------------------- + 3.10.6 -> https://www.python.org/ftp/python/3.10.6/python-3.10.6-amd64.exe + 3.10.9 -> https://www.python.org/ftp/python/3.10.9/python-3.10.9-amd64.exe + 3.11.5 -> https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe + ... +-------------------------------------------------------------------------------- +Total releases: 12 +``` + +**Example**: +```bash +gradle listReleases +``` + +--- + +### showWheelInfo + +Display wheel package information for a Python version. + +**Group**: help + +**Description**: Display wheel package information for a Python version (use -PbundleVersion=X.X.X) + +**Usage**: +```bash +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +**Parameters**: +- `bundleVersion` (required): Python version to check + +**Output**: +``` +Wheel Information for Python 3.13.5: +====================================================================== + Wheel URL: https://files.pythonhosted.org/packages/.../PyQt5-5.15.9-cp313-cp313-win_amd64.whl + Wheel File: PyQt5-5.15.9-cp313-cp313-win_amd64.whl + Location: E:/Bearsampp-development/module-python/bin/python3.13.5/wheel + + Install Script: E:/Bearsampp-development/module-python/bin/python3.13.5/wheel/install.bat + Content: + ------------------------------------------------------------------ + @echo off + cd .. + bin\python.bat -m pip install wheel\PyQt5-5.15.9-cp313-cp313-win_amd64.whl +====================================================================== +``` + +**Example**: +```bash +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +--- + +### tasks + +List all available tasks (built-in Gradle task). + +**Group**: help + +**Description**: Displays the tasks runnable from root project 'module-python' + +**Usage**: +```bash +# List main tasks +gradle tasks + +# List all tasks including internal tasks +gradle tasks --all +``` + +**Example**: +```bash +gradle tasks +``` + +--- + +## Task Dependencies + +### Dependency Graph + +``` +release + (no dependencies) + +clean + (no dependencies) + +verify + (no dependencies) + +validateProperties + (no dependencies) + +validatePythonVersion + (no dependencies) + +info + (no dependencies) + +listVersions + (no dependencies) + +listReleases + (no dependencies) + +showWheelInfo + (no dependencies) +``` + +--- + +## Common Task Combinations + +### Full Build Workflow + +```bash +# 1. Verify environment +gradle verify + +# 2. List available versions +gradle listVersions + +# 3. Validate specific version +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# 4. Build release +gradle release "-PbundleVersion=3.13.5" +``` + +### Development Workflow + +```bash +# Check configuration +gradle validateProperties + +# View build info +gradle info + +# Build and test +gradle release "-PbundleVersion=3.13.5" + +# Clean up +gradle clean +``` + +### Troubleshooting Workflow + +```bash +# Verify environment +gradle verify + +# Check version structure +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# Check wheel configuration +gradle showWheelInfo "-PbundleVersion=3.13.5" + +# Try build with debug output +gradle release "-PbundleVersion=3.13.5" --debug +``` + +--- + +## Task Options + +### Global Options + +These options work with any task: + +```bash +# Show stack traces +gradle --stacktrace + +# Show full stack traces +gradle --full-stacktrace + +# Debug output +gradle --debug + +# Info output +gradle --info + +# Quiet output +gradle --quiet + +# Dry run (don't execute) +gradle --dry-run + +# Continue on failure +gradle --continue + +# Refresh dependencies +gradle --refresh-dependencies + +# No daemon +gradle --no-daemon + +# Offline mode +gradle --offline +``` + +### Performance Options + +```bash +# Parallel execution +gradle --parallel + +# Max workers +gradle --max-workers=4 + +# Build cache +gradle --build-cache + +# No build cache +gradle --no-build-cache + +# Configuration cache +gradle --configuration-cache + +# No configuration cache +gradle --no-configuration-cache +``` + +--- + +## Exit Codes + +All tasks follow standard exit code conventions: + +- **0**: Success +- **1**: General error +- **2**: Configuration error +- **3**: Execution error +- **4**: Validation error + +--- + +## Task Output + +### Success Output + +``` +================================================================ + Bearsampp Module Python - Pure Gradle Build +================================================================ + +Building release for python version 3.13.5... +====================================================================== +Bundle path: E:/Bearsampp-development/module-python/bin/python3.13.5 + +Python-specific build steps: + 1. Copying bundle files... + 2. Upgrading PIP to latest version... + 3. Processing wheel packages... + Downloading: PyQt5-5.15.9-cp313-cp313-win_amd64.whl + Installing wheel packages... + 4. Creating release archive... + +====================================================================== +[SUCCESS] Release build completed successfully for version 3.13.5 +Release file: C:/Users/user/Bearsampp-build/release/python3.13.5.7z +====================================================================== +``` + +### Error Output + +``` +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':release'. +> Bundle version not found: E:/Bearsampp-development/module-python/bin/python3.13.5 + +Available versions in bin/: + - 3.12.9 + - 3.13.3 + +* Try: +> Run with --stacktrace option to get the stack trace. +> Run with --info or --debug option to get more log output. +> Run with --scan to get full insights. +``` + +--- + +## See Also + +- [Getting Started Guide](GETTING_STARTED.md) +- [Build System Guide](BUILD_SYSTEM.md) +- [Configuration Guide](CONFIGURATION.md) +- [Gradle Documentation](https://docs.gradle.org/) diff --git a/README.md b/README.md index 7aa10d04..34658d25 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,117 @@ +# Bearsampp Module - Python + This is a module of [Bearsampp project](https://github.com/bearsampp/bearsampp) involving Python. -## Documentation and downloads +## About + +This module provides Python integration for Bearsampp, supporting multiple Python versions with automatic PIP upgrades and wheel package management. + +## Documentation and Downloads https://bearsampp.com/module/python +## Build System + +This module uses a pure Gradle build system (no wrapper, no Ant dependencies) for packaging Python releases. + +### Quick Start + +```bash +# Verify your build environment +gradle verify + +# List available Python versions +gradle listVersions + +# Build a release for a specific version +gradle release "-PbundleVersion=3.13.5" + +# View all available tasks +gradle tasks +``` + +### Prerequisites + +- Java 8 or higher +- Gradle 7.0 or higher +- 7-Zip (for archive creation) + +### Documentation + +Comprehensive build system documentation is available in the [`.gradle-docs/`](.gradle-docs/) directory: + +- **[Getting Started Guide](.gradle-docs/GETTING_STARTED.md)** - Setup and basic usage +- **[Build System Guide](.gradle-docs/BUILD_SYSTEM.md)** - Detailed build system information +- **[Task Reference](.gradle-docs/TASK_REFERENCE.md)** - Complete task documentation +- **[Configuration Guide](.gradle-docs/CONFIGURATION.md)** - Configuration options and tuning + +### Common Tasks + +```bash +# Display build information +gradle info + +# Verify build environment +gradle verify + +# List available Python versions +gradle listVersions + +# Build a release (interactive) +gradle release + +# Build a release (non-interactive) +gradle release "-PbundleVersion=3.13.5" + +# Clean build artifacts +gradle clean + +# Validate Python version structure +gradle validatePythonVersion "-PbundleVersion=3.13.5" + +# Show wheel package information +gradle showWheelInfo "-PbundleVersion=3.13.5" +``` + +## Features + +- ✅ Pure Gradle build system (no wrapper, no Ant) +- ✅ Support for multiple Python versions +- ✅ Automatic PIP upgrades during build +- ✅ Wheel package download and installation +- ✅ Build caching for faster builds +- ✅ Parallel execution support +- ✅ Interactive and non-interactive build modes +- ✅ Comprehensive verification and validation tasks + +## Project Structure + +``` +module-python/ +├── .gradle-docs/ # Build system documentation +├── bin/ # Python version directories +│ └── python{version}/ +│ ├── bin/ +│ ├── wheel/ +│ └── bearsampp.conf +├── build.gradle # Main build script +├── settings.gradle # Gradle settings +├── gradle.properties # Gradle configuration +├── build.properties # Bundle configuration +└── releases.properties # Available Python releases +``` + ## Issues Issues must be reported on [Bearsampp repository](https://github.com/bearsampp/bearsampp/issues). + +## Contributing + +Contributions are welcome! Please read the build system documentation before contributing. + +## License + +See [LICENSE](LICENSE) file for details. diff --git a/bin/python3.10.6/bearsampp.conf b/bin/archived/python3.10.6/bearsampp.conf similarity index 100% rename from bin/python3.10.6/bearsampp.conf rename to bin/archived/python3.10.6/bearsampp.conf diff --git a/bin/python3.10.6/bin/python.bat b/bin/archived/python3.10.6/bin/python.bat similarity index 100% rename from bin/python3.10.6/bin/python.bat rename to bin/archived/python3.10.6/bin/python.bat diff --git a/bin/python3.10.6/wheel/install.bat b/bin/archived/python3.10.6/wheel/install.bat similarity index 100% rename from bin/python3.10.6/wheel/install.bat rename to bin/archived/python3.10.6/wheel/install.bat diff --git a/bin/python3.10.6/wheel/wheel.properties b/bin/archived/python3.10.6/wheel/wheel.properties similarity index 100% rename from bin/python3.10.6/wheel/wheel.properties rename to bin/archived/python3.10.6/wheel/wheel.properties diff --git a/bin/python3.10.9/bearsampp.conf b/bin/archived/python3.10.9/bearsampp.conf similarity index 100% rename from bin/python3.10.9/bearsampp.conf rename to bin/archived/python3.10.9/bearsampp.conf diff --git a/bin/python3.10.9/bin/python.bat b/bin/archived/python3.10.9/bin/python.bat similarity index 100% rename from bin/python3.10.9/bin/python.bat rename to bin/archived/python3.10.9/bin/python.bat diff --git a/bin/python3.10.9/wheel/install.bat b/bin/archived/python3.10.9/wheel/install.bat similarity index 100% rename from bin/python3.10.9/wheel/install.bat rename to bin/archived/python3.10.9/wheel/install.bat diff --git a/bin/python3.10.9/wheel/wheel.properties b/bin/archived/python3.10.9/wheel/wheel.properties similarity index 100% rename from bin/python3.10.9/wheel/wheel.properties rename to bin/archived/python3.10.9/wheel/wheel.properties diff --git a/bin/python3.11.5/bearsampp.conf b/bin/archived/python3.11.5/bearsampp.conf similarity index 100% rename from bin/python3.11.5/bearsampp.conf rename to bin/archived/python3.11.5/bearsampp.conf diff --git a/bin/python3.11.5/bin/python.bat b/bin/archived/python3.11.5/bin/python.bat similarity index 100% rename from bin/python3.11.5/bin/python.bat rename to bin/archived/python3.11.5/bin/python.bat diff --git a/bin/python3.11.5/wheel/install.bat b/bin/archived/python3.11.5/wheel/install.bat similarity index 100% rename from bin/python3.11.5/wheel/install.bat rename to bin/archived/python3.11.5/wheel/install.bat diff --git a/bin/python3.11.5/wheel/wheel.properties b/bin/archived/python3.11.5/wheel/wheel.properties similarity index 100% rename from bin/python3.11.5/wheel/wheel.properties rename to bin/archived/python3.11.5/wheel/wheel.properties diff --git a/bin/python3.11.6b0/bearsampp.conf b/bin/archived/python3.11.6b0/bearsampp.conf similarity index 100% rename from bin/python3.11.6b0/bearsampp.conf rename to bin/archived/python3.11.6b0/bearsampp.conf diff --git a/bin/python3.11.6b0/bin/python.bat b/bin/archived/python3.11.6b0/bin/python.bat similarity index 100% rename from bin/python3.11.6b0/bin/python.bat rename to bin/archived/python3.11.6b0/bin/python.bat diff --git a/bin/python3.11.6b0/wheel/install.bat b/bin/archived/python3.11.6b0/wheel/install.bat similarity index 100% rename from bin/python3.11.6b0/wheel/install.bat rename to bin/archived/python3.11.6b0/wheel/install.bat diff --git a/bin/python3.11.6b0/wheel/wheel.properties b/bin/archived/python3.11.6b0/wheel/wheel.properties similarity index 100% rename from bin/python3.11.6b0/wheel/wheel.properties rename to bin/archived/python3.11.6b0/wheel/wheel.properties diff --git a/bin/python3.11.8/bearsampp.conf b/bin/archived/python3.11.8/bearsampp.conf similarity index 100% rename from bin/python3.11.8/bearsampp.conf rename to bin/archived/python3.11.8/bearsampp.conf diff --git a/bin/python3.11.8/bin/python.bat b/bin/archived/python3.11.8/bin/python.bat similarity index 100% rename from bin/python3.11.8/bin/python.bat rename to bin/archived/python3.11.8/bin/python.bat diff --git a/bin/python3.11.8/wheel/install.bat b/bin/archived/python3.11.8/wheel/install.bat similarity index 100% rename from bin/python3.11.8/wheel/install.bat rename to bin/archived/python3.11.8/wheel/install.bat diff --git a/bin/python3.11.8/wheel/wheel.properties b/bin/archived/python3.11.8/wheel/wheel.properties similarity index 100% rename from bin/python3.11.8/wheel/wheel.properties rename to bin/archived/python3.11.8/wheel/wheel.properties diff --git a/bin/python3.12.2/bearsampp.conf b/bin/archived/python3.12.2/bearsampp.conf similarity index 100% rename from bin/python3.12.2/bearsampp.conf rename to bin/archived/python3.12.2/bearsampp.conf diff --git a/bin/python3.12.2/bin/python.bat b/bin/archived/python3.12.2/bin/python.bat similarity index 100% rename from bin/python3.12.2/bin/python.bat rename to bin/archived/python3.12.2/bin/python.bat diff --git a/bin/python3.12.2/wheel/install.bat b/bin/archived/python3.12.2/wheel/install.bat similarity index 100% rename from bin/python3.12.2/wheel/install.bat rename to bin/archived/python3.12.2/wheel/install.bat diff --git a/bin/python3.12.2/wheel/wheel.properties b/bin/archived/python3.12.2/wheel/wheel.properties similarity index 100% rename from bin/python3.12.2/wheel/wheel.properties rename to bin/archived/python3.12.2/wheel/wheel.properties diff --git a/bin/python3.12.6.0/bearsampp.conf b/bin/archived/python3.12.6.0/bearsampp.conf similarity index 100% rename from bin/python3.12.6.0/bearsampp.conf rename to bin/archived/python3.12.6.0/bearsampp.conf diff --git a/bin/python3.12.6.0/bin/python.bat b/bin/archived/python3.12.6.0/bin/python.bat similarity index 100% rename from bin/python3.12.6.0/bin/python.bat rename to bin/archived/python3.12.6.0/bin/python.bat diff --git a/bin/python3.12.6.0/wheel/install.bat b/bin/archived/python3.12.6.0/wheel/install.bat similarity index 100% rename from bin/python3.12.6.0/wheel/install.bat rename to bin/archived/python3.12.6.0/wheel/install.bat diff --git a/bin/python3.12.6.0/wheel/wheel.properties b/bin/archived/python3.12.6.0/wheel/wheel.properties similarity index 100% rename from bin/python3.12.6.0/wheel/wheel.properties rename to bin/archived/python3.12.6.0/wheel/wheel.properties diff --git a/bin/python3.12.8.0-b2/bearsampp.conf b/bin/archived/python3.12.8.0-b2/bearsampp.conf similarity index 100% rename from bin/python3.12.8.0-b2/bearsampp.conf rename to bin/archived/python3.12.8.0-b2/bearsampp.conf diff --git a/bin/python3.12.8.0-b2/bin/python.bat b/bin/archived/python3.12.8.0-b2/bin/python.bat similarity index 100% rename from bin/python3.12.8.0-b2/bin/python.bat rename to bin/archived/python3.12.8.0-b2/bin/python.bat diff --git a/bin/python3.12.8.0-b2/wheel/install.bat b/bin/archived/python3.12.8.0-b2/wheel/install.bat similarity index 100% rename from bin/python3.12.8.0-b2/wheel/install.bat rename to bin/archived/python3.12.8.0-b2/wheel/install.bat diff --git a/bin/python3.12.8.0-b2/wheel/wheel.properties b/bin/archived/python3.12.8.0-b2/wheel/wheel.properties similarity index 100% rename from bin/python3.12.8.0-b2/wheel/wheel.properties rename to bin/archived/python3.12.8.0-b2/wheel/wheel.properties diff --git a/bin/python3.12.9/bearsampp.conf b/bin/archived/python3.12.9/bearsampp.conf similarity index 100% rename from bin/python3.12.9/bearsampp.conf rename to bin/archived/python3.12.9/bearsampp.conf diff --git a/bin/python3.12.9/bin/python.bat b/bin/archived/python3.12.9/bin/python.bat similarity index 100% rename from bin/python3.12.9/bin/python.bat rename to bin/archived/python3.12.9/bin/python.bat diff --git a/bin/python3.12.9/wheel/install.bat b/bin/archived/python3.12.9/wheel/install.bat similarity index 100% rename from bin/python3.12.9/wheel/install.bat rename to bin/archived/python3.12.9/wheel/install.bat diff --git a/bin/python3.12.9/wheel/wheel.properties b/bin/archived/python3.12.9/wheel/wheel.properties similarity index 100% rename from bin/python3.12.9/wheel/wheel.properties rename to bin/archived/python3.12.9/wheel/wheel.properties diff --git a/bin/python3.13.2/bearsampp.conf b/bin/archived/python3.13.2/bearsampp.conf similarity index 100% rename from bin/python3.13.2/bearsampp.conf rename to bin/archived/python3.13.2/bearsampp.conf diff --git a/bin/python3.13.2/bin/python.bat b/bin/archived/python3.13.2/bin/python.bat similarity index 100% rename from bin/python3.13.2/bin/python.bat rename to bin/archived/python3.13.2/bin/python.bat diff --git a/bin/python3.13.2/wheel/install.bat b/bin/archived/python3.13.2/wheel/install.bat similarity index 100% rename from bin/python3.13.2/wheel/install.bat rename to bin/archived/python3.13.2/wheel/install.bat diff --git a/bin/python3.13.2/wheel/wheel.properties b/bin/archived/python3.13.2/wheel/wheel.properties similarity index 100% rename from bin/python3.13.2/wheel/wheel.properties rename to bin/archived/python3.13.2/wheel/wheel.properties diff --git a/bin/python3.13.3/bearsampp.conf b/bin/archived/python3.13.3/bearsampp.conf similarity index 100% rename from bin/python3.13.3/bearsampp.conf rename to bin/archived/python3.13.3/bearsampp.conf diff --git a/bin/python3.13.3/bin/python.bat b/bin/archived/python3.13.3/bin/python.bat similarity index 100% rename from bin/python3.13.3/bin/python.bat rename to bin/archived/python3.13.3/bin/python.bat diff --git a/bin/python3.13.3/wheel/install.bat b/bin/archived/python3.13.3/wheel/install.bat similarity index 100% rename from bin/python3.13.3/wheel/install.bat rename to bin/archived/python3.13.3/wheel/install.bat diff --git a/bin/python3.13.3/wheel/wheel.properties b/bin/archived/python3.13.3/wheel/wheel.properties similarity index 100% rename from bin/python3.13.3/wheel/wheel.properties rename to bin/archived/python3.13.3/wheel/wheel.properties diff --git a/build.gradle b/build.gradle index 51c58130..d9674551 100644 --- a/build.gradle +++ b/build.gradle @@ -1,18 +1,16 @@ /* - * Bearsampp Module Python - Gradle Build + * Bearsampp Module Python - Pure 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 - * 4. Handles Python-specific build dependencies (PIP upgrades, wheel installations) + * This is a pure Gradle build configuration that replaces the legacy Ant build system. + * All build logic has been converted to native Gradle tasks. * * Usage: * gradle tasks - List all available tasks * gradle release - Interactive release (prompts for version) - * gradle release "-PbundleVersion=3.13.5" - Non-interactive release + * gradle release -PbundleVersion=3.13.5 - Non-interactive release * gradle clean - Clean build artifacts * gradle info - Display build information + * gradle verify - Verify build environment */ plugins { @@ -40,11 +38,26 @@ ext { bundleRelease = buildProps.getProperty('bundle.release', '1.0.0') bundleType = buildProps.getProperty('bundle.type', 'tools') bundleFormat = buildProps.getProperty('bundle.format', '7z') + + // External build base path precedence: build.properties (build.path) -> env(BEARSAMPP_BUILD_PATH) -> default /bearsampp-build + def buildPathFromProps = (buildProps.getProperty('build.path', '') ?: '').trim() + def buildPathFromEnv = System.getenv('BEARSAMPP_BUILD_PATH') ?: '' + def defaultBuildPath = "${rootDir}/bearsampp-build" + buildBasePath = buildPathFromProps ? buildPathFromProps : (buildPathFromEnv ? buildPathFromEnv : defaultBuildPath) + + // Shared external tmp tree + buildTmpPath = file("${buildBasePath}/tmp").absolutePath + bundleTmpPrepPath = file("${buildTmpPath}/bundles_prep/${bundleType}/${bundleName}").absolutePath + bundleTmpBuildPath = file("${buildTmpPath}/bundles_build/${bundleType}/${bundleName}").absolutePath + bundleTmpDownloadPath = file("${buildTmpPath}/downloads/${bundleName}").absolutePath + + // Final external output path for archives + moduleBuildOutputPath = file("${buildBasePath}/${bundleType}/${bundleName}/${bundleRelease}").absolutePath } // 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}") + logger.warn("Dev path not found: ${ext.devPath}. Some tasks may not work correctly.") } // Configure repositories for dependencies @@ -53,28 +66,237 @@ repositories { } // ============================================================================ -// 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 including Python-specific build steps -ant.importBuild('build.xml') { antTargetName -> - // Map Ant target names to Gradle task names - // Prefix all with 'ant-' to avoid conflicts - return "ant-${antTargetName}".toString() +// Helper function to find 7-Zip executable +def find7ZipExecutable() { + // Check environment variable + def sevenZipHome = System.getenv('7Z_HOME') + if (sevenZipHome) { + def exe = file("${sevenZipHome}/7z.exe") + if (exe.exists()) { + return exe.absolutePath + } + } + + // Check common installation paths + 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 to find in PATH + 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) { + // Ignore + } + + return null +} + +// Helper function to 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('') +} + +// Helper methods for version discovery +def findAvailableVersions = { + def binDir = new File(projectDir, 'bin') + def archivedDir = new File(projectDir, 'bin/archived') + def versions = [] as List + + if (binDir.exists()) { + versions.addAll( + (binDir.listFiles() ?: []) + .findAll { it.isDirectory() && it.name.startsWith(bundleName) && it.name != 'archived' && it.name != 'archi8ved' } + .collect { it.name.replace(bundleName, '') } + ) + } + + if (archivedDir.exists()) { + versions.addAll( + (archivedDir.listFiles() ?: []) + .findAll { it.isDirectory() && it.name.startsWith(bundleName) } + .collect { it.name.replace(bundleName, '') } + ) + } + + return versions.unique() +} + +// Helper: Fetch python.properties from modules-untouched repository +def fetchModulesUntouchedProperties() { + def propsUrl = "https://raw.githubusercontent.com/Bearsampp/modules-untouched/main/modules/python.properties" + + println "Checking modules-untouched repository..." + println "Fetching python.properties from modules-untouched repository..." + println " URL: ${propsUrl}" + + def tempFile = file("${bundleTmpDownloadPath}/python-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 python.properties from modules-untouched: ${e.message}" + return null + } +} + +// Helper: Download Python binaries from modules-untouched repository +def downloadFromModulesUntouched(String version) { + def untouchedProps = fetchModulesUntouchedProperties() + + if (!untouchedProps) { + throw new GradleException("Could not fetch python.properties from modules-untouched repository") + } + + def untouchedUrl = untouchedProps.getProperty(version) + if (!untouchedUrl) { + throw new GradleException("Version ${version} not found in modules-untouched python.properties") + } + + println "Found version ${version} in modules-untouched python.properties" + println "Downloading from:" + println " ${untouchedUrl}" + + 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}" + new URL(untouchedUrl).withInputStream { input -> + downloadedFile.withOutputStream { output -> + output << input + } + } + println "Download complete from modules-untouched" + } else { + println "Already downloaded: ${downloadedFile.name}" + } + + return downloadedFile +} + +// Helper: Extract Python archive +def extractPythonArchive(File archive, String version) { + def extractDir = file("${bundleTmpPath}/extract/${bundleName}") + extractDir.mkdirs() + + println "Extracting archive..." + def extractPath = file("${extractDir}/${version}") + if (extractPath.exists()) { + delete extractPath + } + extractPath.mkdirs() + + // Extract using Gradle's zipTree + copy { + from zipTree(archive) + into extractPath + } + + println "Extraction complete" + + // Find the Python directory (it might be nested) + def pythonDir = findPythonDirectory(extractPath) + if (!pythonDir) { + throw new GradleException("Could not find Python directory in extracted archive") + } + + println "Found Python directory: ${pythonDir.name}" + return pythonDir +} + +// Helper: Find Python directory containing python.exe +def findPythonDirectory(File searchDir) { + // Case 1: Check if python.exe is directly in this directory + def pythonExe = new File(searchDir, 'python.exe') + if (pythonExe.exists()) { + return searchDir + } + + // Case 2: Recursively search for a directory containing python.exe + File found = null + def stack = new ArrayDeque() + stack.push(searchDir) + + while (!stack.isEmpty() && !found) { + def current = stack.pop() + def children = current.listFiles() + if (children) { + for (def child : children) { + if (child.isDirectory()) { + def exe = new File(child, 'python.exe') + if (exe.exists()) { + found = child + break + } + stack.push(child) + } + } + } + } + + return found +} + +def latestVersion = { List versions -> + if (versions.isEmpty()) return null + return versions.max { a, b -> + def pa = a.split('\\.').collect { it.isInteger() ? it as int : 0 } + def pb = b.split('\\.').collect { it.isInteger() ? it as int : 0 } + def len = Math.max(pa.size(), pb.size()) + for (int i = 0; i < len; i++) { + def ai = i < pa.size() ? pa[i] : 0 + def bi = i < pb.size() ? pb[i] : 0 + if (ai != bi) return ai <=> bi + } + return 0 + } } // ============================================================================ -// GRADLE NATIVE TASKS - Modern alternatives and enhancements +// GRADLE NATIVE TASKS // ============================================================================ // Task: Display build information @@ -82,15 +304,21 @@ 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 gradleHome = gradle.gradleHomeDir + doLast { println """ ================================================================ Bearsampp Module Python - Build Info ================================================================ - Project: ${project.name} - Version: ${project.version} - Description: ${project.description} + Project: ${projectName} + Version: ${projectVersion} + Description: ${projectDescription} Bundle Properties: Name: ${bundleName} @@ -102,14 +330,20 @@ tasks.register('info') { Project Dir: ${projectBasedir} Root Dir: ${rootDir} Dev Path: ${devPath} + Build Base: ${buildBasePath} + Output Dir: ${moduleBuildOutputPath} + Tmp Root: ${buildTmpPath} + Tmp Prep: ${bundleTmpPrepPath} + Tmp Build: ${bundleTmpBuildPath} + Downloads: ${bundleTmpDownloadPath} Java: Version: ${JavaVersion.current()} Home: ${System.getProperty('java.home')} Gradle: - Version: ${gradle.gradleVersion} - Home: ${gradle.gradleHomeDir} + Version: ${gradleVersion} + Home: ${gradleHome} Python Build Features: * Automatic PIP upgrade during build @@ -119,7 +353,6 @@ tasks.register('info') { Available Task Groups: * build - Build and package tasks - * ant tasks - Legacy Ant tasks (prefixed with 'ant-') * help - Help and information tasks * verification - Verification and validation tasks @@ -127,7 +360,7 @@ tasks.register('info') { gradle tasks - List all available tasks gradle info - Show this information gradle release - Interactive release build - gradle release "-PbundleVersion=3.13.5" - Non-interactive release + gradle release -PbundleVersion=3.13.5 - Non-interactive release gradle clean - Clean build artifacts gradle verify - Verify build environment gradle listVersions - List available Python versions @@ -135,80 +368,6 @@ tasks.register('info') { } } -// 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 "" - println "Python-specific build steps will be executed:" - println " 1. Upgrade PIP to latest version" - println " 2. Download wheel packages from wheel.properties" - println " 3. Install wheel packages using install.bat" - 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' @@ -219,20 +378,21 @@ tasks.named('clean') { def buildDir = file("${projectDir}/build") if (buildDir.exists()) { delete buildDir + println "Cleaned: ${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) - } + // Clean temporary directories + def tmpDir = file(buildTmpPath) + if (tmpDir.exists()) { + delete tmpDir + println "Cleaned: ${tmpDir}" } - tmpDirs.each { dir -> - if (dir.exists()) { - delete dir - } + + // Clean Gradle-specific temp files + def gradleBundleVersion = file("${buildTmpPath}/.gradle-bundleVersion") + if (gradleBundleVersion.exists()) { + delete gradleBundleVersion + println "Cleaned: ${gradleBundleVersion.name}" } println "[SUCCESS] Build artifacts cleaned" @@ -254,14 +414,12 @@ tasks.register('verify') { checks['Java 8+'] = javaVersion >= JavaVersion.VERSION_1_8 // Check required files - checks['build.xml'] = file('build.xml').exists() + checks['build.gradle'] = file('build.gradle').exists() checks['build.properties'] = file('build.properties').exists() checks['releases.properties'] = file('releases.properties').exists() - // Check dev directory and required build files + // Check dev directory 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() // Check bin directory for Python versions def binDir = file("${projectDir}/bin") @@ -269,10 +427,14 @@ tasks.register('verify') { if (binDir.exists()) { def pythonVersions = binDir.listFiles() - .findAll { it.isDirectory() && it.name.startsWith(bundleName) } + .findAll { it.isDirectory() && it.name.startsWith(bundleName) && it.name != 'archived' } checks['Python versions available'] = pythonVersions.size() > 0 } + // Check for 7z command + def sevenZipExe = find7ZipExecutable() + checks['7-Zip available'] = sevenZipExe != null + println "\nEnvironment Check Results:" println "-".multiply(60) checks.each { name, passed -> @@ -286,7 +448,7 @@ tasks.register('verify') { println "\n[SUCCESS] All checks passed! Build environment is ready." println "\nYou can now run:" println " gradle release - Interactive release" - println " gradle release \"-PbundleVersion=3.13.5\" - Non-interactive release" + println " gradle release -PbundleVersion=3.13.5 - Non-interactive release" println " gradle listVersions - List available Python versions" } else { println "\n[WARNING] Some checks failed. Please review the requirements." @@ -295,6 +457,620 @@ tasks.register('verify') { } } +// Task: Resolve version (interactive by default; supports -PbundleVersion and '*') +tasks.register('resolveVersion') { + group = 'build' + description = 'Resolve bundleVersion (interactive by default, or use -PbundleVersion=*,)' + + def versionProperty = project.findProperty('bundleVersion') + + doLast { + def supplied = versionProperty as String + def all = findAvailableVersions().sort { a, b -> + def pa = a.split('\\.').collect { it.isInteger() ? it as int : 0 } + def pb = b.split('\\.').collect { it.isInteger() ? it as int : 0 } + for (int i=0; i bi + } + return 0 + } + + def inBin = new File(projectDir, 'bin').exists() ? (new File(projectDir, 'bin').listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) && it.name != 'archived' } + ?.collect { it.name.replace(bundleName, '') } ?: []) : [] + def inArchived = new File(projectDir, 'bin/archived').exists() ? (new File(projectDir, 'bin/archived').listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) } + ?.collect { it.name.replace(bundleName, '') } ?: []) : [] + + String resolved + if (supplied) { + if (supplied == '*') { + resolved = latestVersion(all) + if (!resolved) { + throw new GradleException("No versions found under bin/ to resolve latest from.") + } + println "Resolved latest version: ${resolved}" + } else { + resolved = supplied + } + } else { + println "=".multiply(70) + println "\nInteractive Release Mode\n" + println "=".multiply(70) + println "\nAvailable versions:\n" + all.eachWithIndex { v, idx -> + def indexStr = String.format('%2d', idx + 1) + def tag = inBin.contains(v) && inArchived.contains(v) ? '[bin + bin/archived]' : (inBin.contains(v) ? '[bin]' : (inArchived.contains(v) ? '[bin/archived]' : '[unknown]')) + println " ${indexStr}. ${v.padRight(12)} ${tag}" + } + println "" + print "Enter version to build (index or version string): " + System.out.flush() + def reader = new BufferedReader(new InputStreamReader(System.in)) + def input = reader.readLine()?.trim() + if (!input) { + throw new GradleException("No version specified") + } + if (input.isInteger()) { + def idx = input.toInteger() + if (idx < 1 || idx > all.size()) { + throw new GradleException("Invalid index: ${input}. Choose 1..${all.size()} or enter a version string.") + } + resolved = all[idx - 1] + } else { + resolved = input + } + } + + // Validate existence in bin/ or bin/archived/ + def bundlePath = new File(projectDir, "bin/${bundleName}${resolved}") + if (!bundlePath.exists()) { + def archivedPath = new File(projectDir, "bin/archived/${bundleName}${resolved}") + if (archivedPath.exists()) { + bundlePath = archivedPath + } else { + def listing = all.collect { " - ${it}" }.join('\n') + throw new GradleException("Bundle version not found in bin/ or bin/archived/: ${bundleName}${resolved}\n\nAvailable versions:\n${listing}") + } + } + + // Store resolved version + def propsFile = file("${buildTmpPath}/.gradle-bundleVersion") + propsFile.parentFile.mkdirs() + propsFile.text = resolved + println "\nSelected version: ${resolved}\n" + } +} + +// Provider resolves version from either -PbundleVersion or value set by resolveVersion +def bundleVersionProvider = providers.provider { + def fromProp = project.findProperty('bundleVersion') as String + if (fromProp) return fromProp + def propsFile = file("${buildTmpPath}/.gradle-bundleVersion") + if (propsFile.exists()) { + return propsFile.text.trim() + } + return null +} + +// Guard task: ensure bundleVersion is resolved before any packaging runs +tasks.register('assertVersionResolved') { + group = 'build' + description = 'Fail fast if bundleVersion was not resolved by resolveVersion' + dependsOn 'resolveVersion' + doLast { + def versionToBuild = bundleVersionProvider.getOrNull() + if (!versionToBuild) { + throw new GradleException("bundleVersion property not set. Run 'gradle resolveVersion' or invoke 'gradle release -PbundleVersion=<'*'|X.Y.Z>'") + } + } +} + +// Task: Actual release build logic +tasks.register('releaseBuild') { + group = 'build' + description = 'Execute the release build process' + dependsOn 'resolveVersion' + + doLast { + def versionToBuild = bundleVersionProvider.getOrNull() + if (!versionToBuild) { + throw new GradleException("bundleVersion property not set") + } + + // Helper: Fetch python.properties from modules-untouched repository + def fetchModulesUntouchedProperties = { + def propsUrl = "https://raw.githubusercontent.com/Bearsampp/modules-untouched/main/modules/python.properties" + + println "Checking modules-untouched repository..." + println "Fetching python.properties from modules-untouched repository..." + println " URL: ${propsUrl}" + + def tempFile = file("${bundleTmpDownloadPath}/python-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 python.properties from modules-untouched: ${e.message}" + return null + } + } + + // Helper: Download Python binaries from modules-untouched repository + def downloadFromModulesUntouched = { String version -> + def untouchedProps = fetchModulesUntouchedProperties() + + if (!untouchedProps) { + throw new GradleException("Could not fetch python.properties from modules-untouched repository") + } + + def untouchedUrl = untouchedProps.getProperty(version) + if (!untouchedUrl) { + throw new GradleException("Version ${version} not found in modules-untouched python.properties") + } + + println "Found version ${version} in modules-untouched python.properties" + println "Downloading from:" + println " ${untouchedUrl}" + + 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}" + new URL(untouchedUrl).withInputStream { input -> + downloadedFile.withOutputStream { output -> + output << input + } + } + println "Download complete from modules-untouched" + } else { + println "Already downloaded: ${downloadedFile.name}" + } + + return downloadedFile + } + + // Helper: Extract Python archive + def extractPythonArchive = { File archive, String version -> + def extractDir = file("${buildTmpPath}/extract/${bundleName}") + extractDir.mkdirs() + + println "Extracting archive..." + def extractPath = file("${extractDir}/${version}") + if (extractPath.exists()) { + delete extractPath + } + extractPath.mkdirs() + + // Extract using Gradle's zipTree or 7z + if (archive.name.endsWith('.7z')) { + // Use 7z to extract + def sevenZipExe = find7ZipExecutable() + if (!sevenZipExe) { + throw new GradleException("7-Zip not found. Cannot extract .7z archive: ${archive.name}") + } + + def command = [ + sevenZipExe, + 'x', + archive.absolutePath, + "-o${extractPath.absolutePath}", + '-y' + ] + + def process = new ProcessBuilder(command as String[]) + .redirectErrorStream(true) + .start() + + process.inputStream.eachLine { line -> + // Suppress output unless there's an error + } + + def exitCode = process.waitFor() + if (exitCode != 0) { + throw new GradleException("7-Zip extraction failed with exit code: ${exitCode}") + } + } else { + // Use Gradle's zipTree for .zip files + copy { + from zipTree(archive) + into extractPath + } + } + + println "Extraction complete" + + // Find the Python directory (it might be nested) + def pythonDir = findPythonDirectory(extractPath) + if (!pythonDir) { + throw new GradleException("Could not find Python directory in extracted archive") + } + + println "Found Python directory: ${pythonDir.name}" + return pythonDir + } + + // Resolve bundle path from bin/ or bin/archived/ + def bundlePath = new File(projectDir, "bin/${bundleName}${versionToBuild}") + if (!bundlePath.exists()) { + def archivedPath = new File(projectDir, "bin/archived/${bundleName}${versionToBuild}") + if (archivedPath.exists()) { + bundlePath = archivedPath + } else { + throw new GradleException("Bundle folder not found in bin/ or bin/archived/: ${bundleName}${versionToBuild}") + } + } + + def bundleFolder = bundlePath.name + def bundleVersion = bundleFolder.replace(bundleName, '') + + println "=".multiply(70) + println "\nBuilding ${bundleName} ${bundleVersion}\n" + println "=".multiply(70) + println "\nBundle path: ${bundlePath}" + + // Prepare Python directory + def pythonPrepPath = new File(bundleTmpPrepPath, bundleFolder) + delete pythonPrepPath + pythonPrepPath.mkdirs() + + // Determine source paths for Python binaries + def pythonSrcFinal = bundlePath + + // Check if python.exe exists in the bundle directory + def pythonExe = file("${bundlePath}/python.exe") + if (!pythonExe.exists()) { + // Python binaries not found - need to download from modules-untouched + println "\nPython binaries not found" + println "Downloading Python ${bundleVersion}..." + println "" + + try { + // Download and extract Python binaries + def downloadedArchive = downloadFromModulesUntouched(bundleVersion) + pythonSrcFinal = extractPythonArchive(downloadedArchive, bundleVersion) + + println "" + println "NOTE: Version ${bundleVersion} was sourced from modules-untouched." + println "Source folder: ${pythonSrcFinal}" + } catch (Exception e) { + throw new GradleException(""" + Failed to download Python binaries: ${e.message} + + You can manually download and extract Python binaries to: + ${bundlePath}/ + + Or check that version ${bundleVersion} exists in modules-untouched python.properties + """.stripIndent()) + } + } + + // Verify python.exe exists + pythonExe = file("${pythonSrcFinal}/python.exe") + if (!pythonExe.exists()) { + throw new GradleException("python.exe not found at ${pythonExe}") + } + + println "\nCopying Python files..." + + // For WinPython, we need the entire extracted directory structure + // which includes python/, scripts/, notebooks/, settings/, etc. + def winPythonRoot = pythonSrcFinal.parent + if (winPythonRoot && file(winPythonRoot).exists()) { + println "Copying complete WinPython distribution..." + copy { + from winPythonRoot + into pythonPrepPath + } + } else { + // Fallback: just copy the python directory + copy { + from pythonSrcFinal + into pythonPrepPath + } + } + + // Overlay configuration files from bin/ directory (temp copy for PIP/wheel operations) + println "Overlaying bundle files from bin directory..." + copy { + from bundlePath + into pythonPrepPath + exclude 'pyqt5/**' + } + + // Check if we have python.bat to run PIP upgrade (matching original build.xml) + def pythonBat = file("${pythonPrepPath}/bin/python.bat") + if (pythonBat.exists()) { + println "Upgrading PIP..." + + // Upgrade PIP using bin/python.bat (matching original build.xml) + def pipUpgrade = ["cmd", "/c", "python.bat", "-m", "pip", "install", "--upgrade", "pip"] + def pipProcess = new ProcessBuilder(pipUpgrade as String[]) + .directory(file("${pythonPrepPath}/bin")) + .redirectErrorStream(true) + .start() + + pipProcess.inputStream.eachLine { line -> + if (line.trim()) println " ${line}" + } + + def pipExitCode = pipProcess.waitFor() + if (pipExitCode != 0) { + throw new GradleException("PIP upgrade failed with exit code: ${pipExitCode}") + } + + // Download and install wheel + def wheelDir = file("${pythonPrepPath}/wheel") + if (wheelDir.exists()) { + def wheelProps = file("${wheelDir}/wheel.properties") + if (wheelProps.exists()) { + def props = new Properties() + wheelProps.withInputStream { props.load(it) } + def wheelUrl = props.getProperty('wheel') + + if (wheelUrl) { + println "Downloading Wheel..." + def wheelFile = wheelUrl.tokenize('/').last() + def wheelDest = file("${wheelDir}/${wheelFile}") + + // Download wheel file if it doesn't exist + if (!wheelDest.exists()) { + wheelDest.parentFile.mkdirs() + new URL(wheelUrl).withInputStream { input -> + wheelDest.withOutputStream { output -> + output << input + } + } + } + + // Install wheel using install.bat (matching original build.xml) + println "Installing Wheel..." + def installProcess = new ProcessBuilder(["cmd", "/c", "install.bat"] as String[]) + .directory(wheelDir) + .redirectErrorStream(true) + .start() + + installProcess.inputStream.eachLine { line -> + if (line.trim()) println " ${line}" + } + + def installExitCode = installProcess.waitFor() + if (installExitCode != 0) { + throw new GradleException("Wheel installation failed with exit code: ${installExitCode}") + } + } + } + + // Clean up wheel directory + wheelDir.deleteDir() + } + } else { + println "Skipping PIP upgrade (python.bat not found)" + println "Skipping wheel processing (python.bat not found)" + } + + // Copy to bundles_build directory + def bundlesBuildPath = file("${bundleTmpBuildPath}/${bundleFolder}") + delete bundlesBuildPath + bundlesBuildPath.mkdirs() + + println "Copying to bundles_build directory..." + copy { + from pythonPrepPath + into bundlesBuildPath + } + + println "\nNon-zip version available at: ${bundlesBuildPath}" + + // Store paths in a file for later use (avoid using project.ext at execution time) + def pathsFile = file("${buildTmpPath}/.gradle-build-paths") + pathsFile.parentFile.mkdirs() + pathsFile.text = "preparedBundlePath=${pythonPrepPath.absolutePath}\nbuildBundlePath=${bundlesBuildPath.absolutePath}" + } +} + +def externalOutputDir = file("${moduleBuildOutputPath}") + +// 7z packager +tasks.register('packageRelease7z') { + group = 'build' + description = 'Package release into a .7z archive (includes version folder at root)' + dependsOn 'assertVersionResolved', 'releaseBuild' + + doLast { + def versionToBuild = bundleVersionProvider.getOrNull() + if (!versionToBuild) { + throw new GradleException("bundleVersion property not set") + } + + def bundleFolder = "${bundleName}${versionToBuild}" + def prepRoot = file("${bundleTmpPrepPath}") + def srcDir = new File(prepRoot, bundleFolder) + if (!srcDir.exists()) { + throw new GradleException("Prepared folder not found: ${srcDir}. Run releaseBuild first.") + } + + externalOutputDir.mkdirs() + def archiveName = "bearsampp-${bundleName}-${versionToBuild}-${bundleRelease}.7z" + def archiveFile = new File(externalOutputDir, archiveName) + + if (archiveFile.exists()) { + delete archiveFile + } + + println " 5. Creating release archive..." + println "\nPreparing archive..." + println "Compressing ${bundleFolder} to ${archiveName}..." + + // Find 7z executable + def sevenZipExe = find7ZipExecutable() + if (!sevenZipExe) { + throw new GradleException(""" + 7-Zip not found. Please install 7-Zip or set 7Z_HOME environment variable. + + Download from: https://www.7-zip.org/ + Or set 7Z_HOME to your 7-Zip installation directory. + """.stripIndent()) + } + + println "Using 7-Zip: ${sevenZipExe}" + println "" + + def command = [ + sevenZipExe, + 'a', + '-t7z', + archiveFile.absolutePath.toString(), + bundleFolder + ] + + def process = new ProcessBuilder(command as String[]) + .directory(prepRoot) + .redirectErrorStream(true) + .start() + + process.inputStream.eachLine { line -> + if (line.trim()) println line + } + + def exitCode = process.waitFor() + if (exitCode != 0) { + throw new GradleException("7-Zip compression failed with exit code: ${exitCode}") + } + + println "" + println "Archive created: ${archiveFile}" + } +} + +// Zip packager +tasks.register('packageReleaseZip', Zip) { + group = 'build' + description = 'Package release into a .zip archive (includes version folder at root)' + dependsOn 'assertVersionResolved', 'releaseBuild' + + doFirst { + def versionToBuild = bundleVersionProvider.getOrNull() + if (!versionToBuild) { + throw new GradleException("bundleVersion property not set") + } + + def bundleFolder = "${bundleName}${versionToBuild}" + def prepRoot = file("${bundleTmpPrepPath}") + def srcDir = new File(prepRoot, bundleFolder) + if (!srcDir.exists()) { + throw new GradleException("Prepared folder not found: ${srcDir}. Run releaseBuild first.") + } + + archiveFileName.set("bearsampp-${bundleName}-${versionToBuild}-${bundleRelease}.zip") + destinationDirectory.set(externalOutputDir) + + from(prepRoot) { + include "${bundleFolder}/**" + } + + println " 5. Creating release archive..." + println "\nPreparing archive..." + println "Compressing ${bundleFolder} to ${archiveFileName.get()}..." + } +} + +// Dispatcher task +def archiveFormat = (bundleFormat ?: '7z').toLowerCase() +tasks.register('packageRelease') { + group = 'build' + description = 'Package release into archive (7z or zip) including the version folder at root' + dependsOn 'resolveVersion', 'releaseBuild', 'assertVersionResolved' + dependsOn archiveFormat == '7z' ? 'packageRelease7z' : 'packageReleaseZip' +} + +// Task: Generate hash files +tasks.register('generateHashes') { + group = 'build' + description = 'Generate hash sidecar files for the packaged archive' + + doLast { + def versionToBuild = bundleVersionProvider.getOrNull() + if (!versionToBuild) { + throw new GradleException("bundleVersion property not set") + } + + def extFormat = (bundleFormat ?: '7z').toLowerCase() + def archive = new File(externalOutputDir, "bearsampp-${bundleName}-${versionToBuild}-${bundleRelease}.${extFormat}") + if (!archive.exists()) { + throw new GradleException("Archive not found for hashing: ${archive}") + } + + println "\nGenerating hash files..." + + def writeHash = { String algo, String ext -> + def h = calculateHash(archive, algo) + def out = new File(archive.absolutePath + ".${ext}") + out.text = "${h} ${archive.name}\n" + println " Created: ${out.name}" + } + + writeHash('MD5', 'md5') + writeHash('SHA-1', 'sha1') + writeHash('SHA-256', 'sha256') + writeHash('SHA-512', 'sha512') + + // Print final success message - read from file to avoid deprecation warnings + def buildBundlePath = bundleTmpBuildPath + def pathsFile = file("${buildTmpPath}/.gradle-build-paths") + if (pathsFile.exists()) { + def props = new Properties() + pathsFile.withInputStream { props.load(it) } + buildBundlePath = props.getProperty('buildBundlePath', bundleTmpBuildPath) + } + + println "" + println "=".multiply(70) + println "[SUCCESS] Release build completed successfully for version ${versionToBuild}" + println "Output directory: ${buildBundlePath}" + println "Archive: ${archive.absolutePath}" + println "=".multiply(70) + } +} + +// Task: Cleanup temporary Gradle-specific files after build +tasks.register('cleanupTempFiles') { + group = 'build' + description = 'Cleanup temporary Gradle-specific files after build' + + doLast { + def gradleBundleVersion = file("${buildTmpPath}/.gradle-bundleVersion") + if (gradleBundleVersion.exists()) { + delete gradleBundleVersion + } + } +} + +// Task: Main release task +tasks.register('release') { + group = 'build' + description = 'Build release package (interactive by default; -PbundleVersion=* or X.Y.Z for non-interactive)' + dependsOn 'clean', 'resolveVersion', 'packageRelease' + finalizedBy 'generateHashes', 'cleanupTempFiles' +} + // Task: List all bundle versions from releases.properties tasks.register('listReleases') { group = 'help' @@ -327,41 +1103,56 @@ tasks.register('listVersions') { doLast { def binDir = file("${projectDir}/bin") + def archivedDir = file("${projectDir}/bin/archived") + 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 inBin = binDir.listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) && it.name != 'archived' } + ?.collect { it.name.replace(bundleName, '') } ?: [] + + def inArchived = archivedDir.exists() ? (archivedDir.listFiles() + ?.findAll { it.isDirectory() && it.name.startsWith(bundleName) } + ?.collect { it.name.replace(bundleName, '') } ?: []) : [] + + def allVersions = (inBin + inArchived).toSet().toList().sort { a, b -> + def pa = a.split('\\.').collect { it.isInteger() ? it as int : 0 } + def pb = b.split('\\.').collect { it.isInteger() ? it as int : 0 } + for (int i = 0; i < Math.max(pa.size(), pb.size()); i++) { + def ai = i < pa.size() ? pa[i] : 0 + def bi = i < pb.size() ? pb[i] : 0 + if (ai != bi) return ai <=> bi + } + return 0 + } - println "\nAvailable ${bundleName} versions in bin/:" + println "\nAvailable ${bundleName} versions (index, version, location):" println "-".multiply(60) - versions.each { version -> - def versionDir = file("${binDir}/${bundleName}${version}") - def wheelDir = file("${versionDir}/wheel") - def hasWheel = wheelDir.exists() - def wheelInfo = "" - - if (hasWheel) { - def wheelProps = file("${wheelDir}/wheel.properties") - if (wheelProps.exists()) { - def props = new Properties() - wheelProps.withInputStream { props.load(it) } - def wheelUrl = props.getProperty('wheel', '') - def wheelFile = wheelUrl.tokenize('/').last() - wheelInfo = " [wheel: ${wheelFile}]" - } + allVersions.eachWithIndex { v, idx -> + def tag + def inBinFlag = inBin.contains(v) + def inArchivedFlag = inArchived.contains(v) + if (inBinFlag && inArchivedFlag) { + tag = "[bin + bin/archived]" + } else if (inBinFlag) { + tag = "[bin]" + } else if (inArchivedFlag) { + tag = "[bin/archived]" + } else { + tag = "[unknown]" } - - println " ${version}${wheelInfo}" + def indexStr = String.format('%2d', idx + 1) + println " ${indexStr}. ${v.padRight(12)} ${tag}" } println "-".multiply(60) - println "Total versions: ${versions.size()}" - println "\nTo build a specific version:" - println " gradle release \"-PbundleVersion=${versions.last()}\"" + println "Total versions: ${allVersions.size()}" + if (!allVersions.isEmpty()) { + println "\nTo build a specific version:" + println " gradle release -PbundleVersion=${allVersions.last()}" + } } } @@ -407,7 +1198,7 @@ tasks.register('validatePythonVersion') { if (!versionToValidate) { println "[ERROR] Please specify a version using -PbundleVersion=X.X.X" - println "\nExample: gradle validatePythonVersion \"-PbundleVersion=3.13.5\"" + println "\nExample: gradle validatePythonVersion -PbundleVersion=3.13.5" throw new GradleException("Bundle version not specified") } @@ -437,7 +1228,6 @@ tasks.register('validatePythonVersion') { checks['wheel.properties'] = file("${wheelDir}/wheel.properties").exists() checks['install.bat'] = file("${wheelDir}/install.bat").exists() - // Validate wheel.properties content def wheelProps = file("${wheelDir}/wheel.properties") if (wheelProps.exists()) { def props = new Properties() @@ -474,7 +1264,7 @@ tasks.register('showWheelInfo') { if (!versionToCheck) { println "[ERROR] Please specify a version using -PbundleVersion=X.X.X" - println "\nExample: gradle showWheelInfo \"-PbundleVersion=3.13.5\"" + println "\nExample: gradle showWheelInfo -PbundleVersion=3.13.5" return } @@ -525,7 +1315,7 @@ tasks.register('showWheelInfo') { gradle.taskGraph.whenReady { graph -> println """ ================================================================ - Bearsampp Module Python - Gradle + Ant Hybrid Build + Bearsampp Module Python - Pure Gradle Build ================================================================ """.stripIndent() } diff --git a/build.xml b/build.xml deleted file mode 100644 index ed7d1717..00000000 --- a/build.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From ea67653c5e2894f97cf286f006cb7b37db7dc70a Mon Sep 17 00:00:00 2001 From: Bear Date: Tue, 18 Nov 2025 23:14:30 -0600 Subject: [PATCH 3/3] fixing output messages --- build.gradle | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index d9674551..8c2fdf64 100644 --- a/build.gradle +++ b/build.gradle @@ -1032,19 +1032,14 @@ tasks.register('generateHashes') { writeHash('SHA-256', 'sha256') writeHash('SHA-512', 'sha512') - // Print final success message - read from file to avoid deprecation warnings - def buildBundlePath = bundleTmpBuildPath - def pathsFile = file("${buildTmpPath}/.gradle-build-paths") - if (pathsFile.exists()) { - def props = new Properties() - pathsFile.withInputStream { props.load(it) } - buildBundlePath = props.getProperty('buildBundlePath', bundleTmpBuildPath) - } + // Print final success message + def bundleFolder = "${bundleName}${versionToBuild}" + def outputDir = file("${bundleTmpBuildPath}/${bundleFolder}") println "" println "=".multiply(70) println "[SUCCESS] Release build completed successfully for version ${versionToBuild}" - println "Output directory: ${buildBundlePath}" + println "Output directory: ${outputDir.absolutePath}" println "Archive: ${archive.absolutePath}" println "=".multiply(70) }