Add build scripts and configuration for Elytra PIM Client
This commit is contained in:
parent
459838b2e6
commit
b8a7fb903e
7 changed files with 940 additions and 2 deletions
377
BUILD.md
Normal file
377
BUILD.md
Normal file
|
|
@ -0,0 +1,377 @@
|
||||||
|
# Building and Distributing Elytra PIM Client
|
||||||
|
|
||||||
|
This guide explains how to build wheel distributions and upload them to PyPI or other package repositories.
|
||||||
|
|
||||||
|
## Project Version
|
||||||
|
|
||||||
|
Current version: **0.1.0** (Development Release)
|
||||||
|
|
||||||
|
The version is defined in `pyproject.toml` under `[project]` section.
|
||||||
|
|
||||||
|
## Build Tools
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Python 3.9 or higher
|
||||||
|
- pip with setuptools and wheel
|
||||||
|
|
||||||
|
### Build Dependencies
|
||||||
|
|
||||||
|
Install build requirements:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r build_requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install "setuptools>=65.0" "wheel>=0.38.0" "build>=0.10.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building Wheels
|
||||||
|
|
||||||
|
### Option 1: Using Python Script (Recommended for All Platforms)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Activate virtual environment first
|
||||||
|
.venv\Scripts\activate # Windows
|
||||||
|
source .venv/bin/activate # macOS/Linux
|
||||||
|
|
||||||
|
# Run the build script
|
||||||
|
python build_wheel.py
|
||||||
|
```
|
||||||
|
|
||||||
|
This script will:
|
||||||
|
- Clean previous build artifacts
|
||||||
|
- Build wheel (`.whl`) and source (`.tar.gz`) distributions
|
||||||
|
- Display the build results with file sizes
|
||||||
|
- Show installation instructions
|
||||||
|
|
||||||
|
### Option 2: Using PowerShell Script (Windows)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Activate virtual environment
|
||||||
|
.\.venv\Scripts\Activate.ps1
|
||||||
|
|
||||||
|
# Run the build script
|
||||||
|
.\build_wheel.ps1
|
||||||
|
|
||||||
|
# Clean and rebuild
|
||||||
|
.\build_wheel.ps1 -Clean
|
||||||
|
|
||||||
|
# Build and upload to PyPI
|
||||||
|
.\build_wheel.ps1 -Upload
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 3: Using Shell Script (macOS/Linux)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Activate virtual environment
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
# Run the build script
|
||||||
|
chmod +x build_wheel.sh # Make executable (first time only)
|
||||||
|
./build_wheel.sh
|
||||||
|
|
||||||
|
# Clean and rebuild
|
||||||
|
./build_wheel.sh --clean
|
||||||
|
|
||||||
|
# Build and upload to PyPI
|
||||||
|
./build_wheel.sh --upload
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 4: Using Modern Build Tool Directly
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install build tool
|
||||||
|
pip install build
|
||||||
|
|
||||||
|
# Build wheel and sdist in one command
|
||||||
|
python -m build
|
||||||
|
|
||||||
|
# Build only wheel
|
||||||
|
python -m build --wheel
|
||||||
|
|
||||||
|
# Build only source distribution
|
||||||
|
python -m build --sdist
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 5: Using setuptools Directly
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create wheel only
|
||||||
|
python setup.py bdist_wheel
|
||||||
|
|
||||||
|
# Create both wheel and source distribution
|
||||||
|
python setup.py sdist bdist_wheel
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Output
|
||||||
|
|
||||||
|
Distributions are created in the `dist/` directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
dist/
|
||||||
|
├── elytra_pim_client-0.1.0-py3-none-any.whl # Wheel distribution
|
||||||
|
└── elytra_pim_client-0.1.0.tar.gz # Source distribution
|
||||||
|
```
|
||||||
|
|
||||||
|
### Understanding the Wheel Filename
|
||||||
|
|
||||||
|
`elytra_pim_client-0.1.0-py3-none-any.whl`
|
||||||
|
|
||||||
|
- `elytra_pim_client` - Package name
|
||||||
|
- `0.1.0` - Version
|
||||||
|
- `py3` - Python version (3.x only)
|
||||||
|
- `none` - No C extensions (pure Python)
|
||||||
|
- `any` - Platform independent
|
||||||
|
|
||||||
|
## Installation from Built Wheel
|
||||||
|
|
||||||
|
### From Local File
|
||||||
|
|
||||||
|
After building, install the wheel locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install dist/elytra_pim_client-0.1.0-py3-none-any.whl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editable Install During Development
|
||||||
|
|
||||||
|
During development, use editable install so changes are reflected immediately:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -e .
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with dev dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -e ".[dev]"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Uploading to PyPI
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. Create PyPI account at https://pypi.org/
|
||||||
|
2. Create PyPI token: https://pypi.org/manage/account/tokens/
|
||||||
|
3. Configure credentials
|
||||||
|
|
||||||
|
### Using twine
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install twine
|
||||||
|
pip install twine
|
||||||
|
|
||||||
|
# Upload to PyPI (after building)
|
||||||
|
twine upload dist/*
|
||||||
|
|
||||||
|
# Or to TestPyPI for testing first
|
||||||
|
twine upload -r testpypi dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
**Option 1: Using .pypirc file**
|
||||||
|
|
||||||
|
Create `~/.pypirc`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[distutils]
|
||||||
|
index-servers =
|
||||||
|
pypi
|
||||||
|
testpypi
|
||||||
|
|
||||||
|
[pypi]
|
||||||
|
repository = https://upload.pypi.org/legacy/
|
||||||
|
username = __token__
|
||||||
|
password = pypi_your_token_here
|
||||||
|
|
||||||
|
[testpypi]
|
||||||
|
repository = https://test.pypi.org/legacy/
|
||||||
|
username = __token__
|
||||||
|
password = pypi_your_test_token_here
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Interactive prompt**
|
||||||
|
|
||||||
|
twine will prompt for username and password when uploading.
|
||||||
|
|
||||||
|
### Upload to Test PyPI First
|
||||||
|
|
||||||
|
Before uploading to production, test with TestPyPI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
twine upload -r testpypi dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
Then test installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -i https://test.pypi.org/simple/ elytra-pim-client==0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
### Version Format
|
||||||
|
|
||||||
|
Follow PEP 440 versioning:
|
||||||
|
|
||||||
|
```
|
||||||
|
Major.Minor.Patch (e.g., 0.1.0)
|
||||||
|
Major.Minor.Patch.preN (e.g., 0.1.0.pre1)
|
||||||
|
Major.Minor.Patch.postN (e.g., 0.1.0.post1)
|
||||||
|
Major.Minor.Patch.devN (e.g., 0.1.0.dev1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating Version
|
||||||
|
|
||||||
|
Edit `pyproject.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[project]
|
||||||
|
name = "elytra-pim-client"
|
||||||
|
version = "0.2.0" # Update version here
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic Build Validation
|
||||||
|
|
||||||
|
Before building, scripts automatically:
|
||||||
|
|
||||||
|
1. Remove old build artifacts
|
||||||
|
2. Clean `dist/`, `build/`, and `.egg-info` directories
|
||||||
|
3. Verify build dependencies
|
||||||
|
4. Validate Python version compatibility
|
||||||
|
5. Check that distributions were created
|
||||||
|
|
||||||
|
## Continuous Integration
|
||||||
|
|
||||||
|
### GitHub Actions Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Build Distribution
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.11'
|
||||||
|
- run: pip install -r build_requirements.txt
|
||||||
|
- run: python build_wheel.py
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
||||||
|
|
||||||
|
upload:
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: dist
|
||||||
|
path: dist/
|
||||||
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Build Fails with "No module named 'build'"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install build
|
||||||
|
python build_wheel.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### "setuptools not found"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install setuptools>=65.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Denied (Unix/Linux)
|
||||||
|
|
||||||
|
Make build script executable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x build_wheel.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### "twine: command not found"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install twine
|
||||||
|
python -m twine upload dist/*
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wheel not in dist/
|
||||||
|
|
||||||
|
Check that `pyproject.toml` exists and is valid:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m build --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
elytra_client/
|
||||||
|
├── build_wheel.py # Python build script (all platforms)
|
||||||
|
├── build_wheel.ps1 # PowerShell build script (Windows)
|
||||||
|
├── build_wheel.sh # Shell build script (Unix/Linux)
|
||||||
|
├── build_requirements.txt # Build dependencies
|
||||||
|
├── setup.py # Setup configuration (legacy compatibility)
|
||||||
|
├── pyproject.toml # Modern build configuration (PEP 517/518)
|
||||||
|
├── MANIFEST.in # (Optional) File inclusion rules
|
||||||
|
└── dist/ # Output directory for distributions
|
||||||
|
├── elytra_pim_client-0.1.0-py3-none-any.whl
|
||||||
|
└── elytra_pim_client-0.1.0.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Always test before releasing**
|
||||||
|
```bash
|
||||||
|
twine upload -r testpypi dist/*
|
||||||
|
pip install -i https://test.pypi.org/simple/ elytra-pim-client==0.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Increment version for each release**
|
||||||
|
- Patch: Bug fixes (0.1.1)
|
||||||
|
- Minor: New features (0.2.0)
|
||||||
|
- Major: Breaking changes (1.0.0)
|
||||||
|
|
||||||
|
3. **Clean before rebuilding**
|
||||||
|
```bash
|
||||||
|
python build_wheel.py # Automatically cleans
|
||||||
|
# Or manually
|
||||||
|
rm -rf dist/ build/ *.egg-info/
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Keep dependencies minimal**
|
||||||
|
- Only required packages in `dependencies`
|
||||||
|
- Development tools in `[project.optional-dependencies]`
|
||||||
|
|
||||||
|
5. **Document changes**
|
||||||
|
- Update CHANGELOG.md (if present)
|
||||||
|
- Update version in pyproject.toml
|
||||||
|
- Create git tag for release
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Python Packaging Guide](https://packaging.python.org/)
|
||||||
|
- [PEP 517 - Build System Interface](https://www.python.org/dev/peps/pep-0517/)
|
||||||
|
- [PEP 518 - pyproject.toml](https://www.python.org/dev/peps/pep-0518/)
|
||||||
|
- [PEP 440 - Version Identification](https://www.python.org/dev/peps/pep-0440/)
|
||||||
|
- [setuptools Documentation](https://setuptools.pypa.io/)
|
||||||
|
- [twine Documentation](https://twine.readthedocs.io/)
|
||||||
|
- [PyPI Help](https://pypi.org/help/)
|
||||||
15
build_requirements.txt
Normal file
15
build_requirements.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Build Requirements for Elytra PIM Client
|
||||||
|
|
||||||
|
# Core build tools
|
||||||
|
setuptools>=65.0
|
||||||
|
wheel>=0.38.0
|
||||||
|
|
||||||
|
# Modern build frontend (PEP 517)
|
||||||
|
build>=0.10.0
|
||||||
|
|
||||||
|
# Distribution upload
|
||||||
|
twine>=4.0.0
|
||||||
|
|
||||||
|
# Optional: for building documentation
|
||||||
|
# sphinx>=5.0.0
|
||||||
|
# sphinx-rtd-theme>=1.0.0
|
||||||
188
build_wheel.ps1
Normal file
188
build_wheel.ps1
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
# build_wheel.ps1
|
||||||
|
# Build wheel distribution for Elytra PIM Client (PowerShell)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# .\build_wheel.ps1
|
||||||
|
#
|
||||||
|
# Requires:
|
||||||
|
# - Python 3.9+
|
||||||
|
# - setuptools>=65.0
|
||||||
|
# - wheel
|
||||||
|
# - build (recommended)
|
||||||
|
|
||||||
|
param(
|
||||||
|
[switch]$Clean = $false,
|
||||||
|
[switch]$Upload = $false
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define symbols as variables to avoid encoding issues
|
||||||
|
$symSuccess = "[OK]"
|
||||||
|
$symError = "[!]"
|
||||||
|
$symBullet = "[*]"
|
||||||
|
|
||||||
|
# Color functions for output
|
||||||
|
function Write-Success {
|
||||||
|
Write-Host "$symSuccess $args" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Error-Custom {
|
||||||
|
Write-Host "$symError $args" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Header {
|
||||||
|
Write-Host ("=" * 70)
|
||||||
|
Write-Host $args
|
||||||
|
Write-Host ("=" * 70)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-SubHeader {
|
||||||
|
Write-Host ("-" * 70)
|
||||||
|
Write-Host $args
|
||||||
|
Write-Host ("-" * 70)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script
|
||||||
|
$projectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$distDir = Join-Path $projectRoot "dist"
|
||||||
|
$buildDir = Join-Path $projectRoot "build"
|
||||||
|
$eggInfoDir = Join-Path $projectRoot "elytra_pim_client.egg-info"
|
||||||
|
|
||||||
|
Write-Header "Elytra PIM Client - Wheel Builder (PowerShell)"
|
||||||
|
|
||||||
|
# Clean if requested
|
||||||
|
if ($Clean) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Cleaning previous builds..."
|
||||||
|
|
||||||
|
@($distDir, $buildDir, $eggInfoDir) | ForEach-Object {
|
||||||
|
if (Test-Path $_) {
|
||||||
|
Remove-Item $_ -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Write-Success "Removed $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if build directory exists from previous build
|
||||||
|
if (Test-Path $distDir) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Cleaning dist directory..."
|
||||||
|
Remove-Item $distDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
Write-Success "Removed old distributions"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install build requirements if needed
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Checking build dependencies..."
|
||||||
|
$buildCheck = python -m pip list 2>$null | Select-String "build"
|
||||||
|
if (-not $buildCheck) {
|
||||||
|
Write-Host "Installing build tools..."
|
||||||
|
python -m pip install -q build setuptools wheel
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Success "Build tools installed"
|
||||||
|
} else {
|
||||||
|
Write-Error-Custom "Failed to install build tools"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build
|
||||||
|
Write-SubHeader "Building distributions..."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Push-Location $projectRoot
|
||||||
|
try {
|
||||||
|
python -m build
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error-Custom "Build failed"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
|
|
||||||
|
# Verify output
|
||||||
|
Write-SubHeader "Build Results"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
if (!(Test-Path $distDir)) {
|
||||||
|
Write-Error-Custom "dist directory not created"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$wheels = @(Get-ChildItem -Path $distDir -Filter "*.whl" -ErrorAction SilentlyContinue)
|
||||||
|
$sdists = @(Get-ChildItem -Path $distDir -Filter "*.tar.gz" -ErrorAction SilentlyContinue)
|
||||||
|
|
||||||
|
if ($wheels.Count -eq 0 -and $sdists.Count -eq 0) {
|
||||||
|
Write-Error-Custom "No distributions created"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Success "Build successful!"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
if ($wheels.Count -gt 0) {
|
||||||
|
Write-Host "Wheels:"
|
||||||
|
$wheels | ForEach-Object {
|
||||||
|
$sizeMB = [Math]::Round($_.Length / 1MB, 2)
|
||||||
|
Write-Host " $symBullet $($_.Name) ($sizeMB MB)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sdists.Count -gt 0) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Source Distributions:"
|
||||||
|
$sdists | ForEach-Object {
|
||||||
|
$sizeMB = [Math]::Round($_.Length / 1MB, 2)
|
||||||
|
Write-Host " $symBullet $($_.Name) ($sizeMB MB)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Success "Distributions saved to: $distDir"
|
||||||
|
|
||||||
|
# Installation instructions
|
||||||
|
Write-SubHeader "Installation Instructions"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
if ($wheels.Count -gt 0) {
|
||||||
|
$wheel = $wheels[0]
|
||||||
|
Write-Host "Install the wheel locally:"
|
||||||
|
Write-Host " pip install `"$($wheel.FullName)`""
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
Write-Host "Or upload to PyPI:"
|
||||||
|
Write-Host " pip install twine"
|
||||||
|
Write-Host " twine upload dist/*"
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional upload
|
||||||
|
if ($Upload) {
|
||||||
|
Write-SubHeader "Uploading to PyPI..."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$twineCheck = python -m pip list 2>$null | Select-String "twine"
|
||||||
|
if (-not $twineCheck) {
|
||||||
|
Write-Host "Installing twine..."
|
||||||
|
python -m pip install -q twine
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Running twine upload..."
|
||||||
|
Push-Location $projectRoot
|
||||||
|
try {
|
||||||
|
python -m twine upload dist/*
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Success "Upload complete!"
|
||||||
|
} else {
|
||||||
|
Write-Error-Custom "Upload failed"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Done!"
|
||||||
|
Write-Host ""
|
||||||
|
exit 0
|
||||||
152
build_wheel.py
Normal file
152
build_wheel.py
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
"""Build wheel distribution for Elytra PIM Client.
|
||||||
|
|
||||||
|
This script builds wheel and source distributions for the Elytra PIM Client package.
|
||||||
|
It requires setuptools and wheel to be installed.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python build_wheel.py
|
||||||
|
|
||||||
|
Output:
|
||||||
|
- Wheels saved to dist/ directory
|
||||||
|
- Source distribution (sdist) also created for reference
|
||||||
|
"""
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
"""Build wheel distribution.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Exit code (0 for success, 1 for failure)
|
||||||
|
"""
|
||||||
|
project_root = Path(__file__).parent
|
||||||
|
dist_dir = project_root / "dist"
|
||||||
|
|
||||||
|
print("=" * 70)
|
||||||
|
print("Elytra PIM Client - Wheel Builder")
|
||||||
|
print("=" * 70)
|
||||||
|
|
||||||
|
# Clean previous builds
|
||||||
|
print("\nCleaning previous builds...")
|
||||||
|
if dist_dir.exists():
|
||||||
|
try:
|
||||||
|
shutil.rmtree(dist_dir)
|
||||||
|
print(f"✓ Removed {dist_dir}")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"✗ Failed to remove {dist_dir}: {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
build_dir = project_root / "build"
|
||||||
|
if build_dir.exists():
|
||||||
|
try:
|
||||||
|
shutil.rmtree(build_dir)
|
||||||
|
print(f"✓ Removed {build_dir}")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"✗ Failed to remove {build_dir}: {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
egg_info_dir = project_root / "elytra_pim_client.egg-info"
|
||||||
|
if egg_info_dir.exists():
|
||||||
|
try:
|
||||||
|
shutil.rmtree(egg_info_dir)
|
||||||
|
print(f"✓ Removed {egg_info_dir}")
|
||||||
|
except OSError as e:
|
||||||
|
print(f"✗ Failed to remove {egg_info_dir}: {e}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Build wheel and sdist
|
||||||
|
print("\n" + "-" * 70)
|
||||||
|
print("Building distributions...")
|
||||||
|
print("-" * 70 + "\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Use python -m build for modern approach
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, "-m", "build"],
|
||||||
|
cwd=project_root,
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("\n✗ Build failed")
|
||||||
|
print("\nTrying alternative build method...")
|
||||||
|
|
||||||
|
# Fallback to direct setuptools invocation
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, "setup.py", "sdist", "bdist_wheel"],
|
||||||
|
cwd=project_root,
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("\n✗ Build failed with fallback method")
|
||||||
|
return 1
|
||||||
|
except FileNotFoundError:
|
||||||
|
# If 'build' module not available, use setup.py
|
||||||
|
print("Using setuptools directly...\n")
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, "setup.py", "sdist", "bdist_wheel"],
|
||||||
|
cwd=project_root,
|
||||||
|
check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print("\n✗ Build failed")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Verify build output
|
||||||
|
print("\n" + "-" * 70)
|
||||||
|
print("Build Results")
|
||||||
|
print("-" * 70 + "\n")
|
||||||
|
|
||||||
|
if not dist_dir.exists():
|
||||||
|
print("✗ dist directory not created")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
wheels = list(dist_dir.glob("*.whl"))
|
||||||
|
sdists = list(dist_dir.glob("*.tar.gz"))
|
||||||
|
|
||||||
|
if not wheels and not sdists:
|
||||||
|
print("✗ No distributions created")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print("✓ Build successful!\n")
|
||||||
|
|
||||||
|
if wheels:
|
||||||
|
print("Wheels:")
|
||||||
|
for wheel in wheels:
|
||||||
|
size_mb = wheel.stat().st_size / (1024 * 1024)
|
||||||
|
print(f" • {wheel.name} ({size_mb:.2f} MB)")
|
||||||
|
|
||||||
|
if sdists:
|
||||||
|
print("\nSource Distributions:")
|
||||||
|
for sdist in sdists:
|
||||||
|
size_mb = sdist.stat().st_size / (1024 * 1024)
|
||||||
|
print(f" • {sdist.name} ({size_mb:.2f} MB)")
|
||||||
|
|
||||||
|
print(f"\n✓ Distributions saved to: {dist_dir}")
|
||||||
|
|
||||||
|
# Installation instructions
|
||||||
|
print("\n" + "-" * 70)
|
||||||
|
print("Installation Instructions")
|
||||||
|
print("-" * 70 + "\n")
|
||||||
|
|
||||||
|
if wheels:
|
||||||
|
wheel = wheels[0]
|
||||||
|
print(f"Install the wheel locally:\n")
|
||||||
|
print(f" pip install {dist_dir / wheel.name}\n")
|
||||||
|
|
||||||
|
print(f"Or upload to PyPI:\n")
|
||||||
|
print(f" pip install twine")
|
||||||
|
print(f" twine upload dist/*\n")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
197
build_wheel.sh
Normal file
197
build_wheel.sh
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# build_wheel.sh - Build wheel distribution for Elytra PIM Client
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./build_wheel.sh [--clean] [--upload]
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# --clean Clean previous builds before building
|
||||||
|
# --upload Upload to PyPI after building
|
||||||
|
#
|
||||||
|
# Requires:
|
||||||
|
# - Python 3.9+
|
||||||
|
# - setuptools>=65.0
|
||||||
|
# - wheel
|
||||||
|
# - build (recommended)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✓ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}✗ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo "========================================================================"
|
||||||
|
echo "$1"
|
||||||
|
echo "========================================================================"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_subheader() {
|
||||||
|
echo "------------------------------------------------------------------------"
|
||||||
|
echo "$1"
|
||||||
|
echo "------------------------------------------------------------------------"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
CLEAN=false
|
||||||
|
UPLOAD=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--clean)
|
||||||
|
CLEAN=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--upload)
|
||||||
|
UPLOAD=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
echo "Usage: $0 [--clean] [--upload]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Get project root
|
||||||
|
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
DIST_DIR="$PROJECT_ROOT/dist"
|
||||||
|
BUILD_DIR="$PROJECT_ROOT/build"
|
||||||
|
EGG_INFO_DIR="$PROJECT_ROOT/elytra_pim_client.egg-info"
|
||||||
|
|
||||||
|
print_header "Elytra PIM Client - Wheel Builder"
|
||||||
|
|
||||||
|
# Clean if requested
|
||||||
|
if [ "$CLEAN" = true ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Cleaning previous builds..."
|
||||||
|
for dir in "$DIST_DIR" "$BUILD_DIR" "$EGG_INFO_DIR"; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
rm -rf "$dir"
|
||||||
|
print_success "Removed $dir"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean dist directory for fresh build
|
||||||
|
if [ -d "$DIST_DIR" ]; then
|
||||||
|
rm -rf "$DIST_DIR"
|
||||||
|
print_success "Removed old distributions"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check build dependencies
|
||||||
|
echo ""
|
||||||
|
echo "Checking build dependencies..."
|
||||||
|
if ! python3 -m pip list 2>/dev/null | grep -q "^build "; then
|
||||||
|
echo "Installing build tools..."
|
||||||
|
python3 -m pip install -q build setuptools wheel
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
print_success "Build tools installed"
|
||||||
|
else
|
||||||
|
print_error "Failed to install build tools"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build
|
||||||
|
print_subheader "Building distributions..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
if ! python3 -m build; then
|
||||||
|
print_error "Build failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify output
|
||||||
|
print_subheader "Build Results"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ ! -d "$DIST_DIR" ]; then
|
||||||
|
print_error "dist directory not created"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count wheels and sdists
|
||||||
|
WHEEL_COUNT=$(find "$DIST_DIR" -maxdepth 1 -name "*.whl" 2>/dev/null | wc -l)
|
||||||
|
SDIST_COUNT=$(find "$DIST_DIR" -maxdepth 1 -name "*.tar.gz" 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
if [ $WHEEL_COUNT -eq 0 ] && [ $SDIST_COUNT -eq 0 ]; then
|
||||||
|
print_error "No distributions created"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Build successful!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ $WHEEL_COUNT -gt 0 ]; then
|
||||||
|
echo "Wheels:"
|
||||||
|
for wheel in "$DIST_DIR"/*.whl; do
|
||||||
|
SIZE=$(du -h "$wheel" | cut -f1)
|
||||||
|
echo " • $(basename "$wheel") ($SIZE)"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $SDIST_COUNT -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Source Distributions:"
|
||||||
|
for sdist in "$DIST_DIR"/*.tar.gz; do
|
||||||
|
SIZE=$(du -h "$sdist" | cut -f1)
|
||||||
|
echo " • $(basename "$sdist") ($SIZE)"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_success "Distributions saved to: $DIST_DIR"
|
||||||
|
|
||||||
|
# Installation instructions
|
||||||
|
print_subheader "Installation Instructions"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ $WHEEL_COUNT -gt 0 ]; then
|
||||||
|
WHEEL=$(ls "$DIST_DIR"/*.whl | head -1)
|
||||||
|
echo "Install the wheel locally:"
|
||||||
|
echo " pip install \"$WHEEL\""
|
||||||
|
echo ""
|
||||||
|
echo "Or upload to PyPI:"
|
||||||
|
echo " pip install twine"
|
||||||
|
echo " twine upload dist/*"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional upload
|
||||||
|
if [ "$UPLOAD" = true ]; then
|
||||||
|
print_subheader "Uploading to PyPI..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if ! python3 -m pip list 2>/dev/null | grep -q "^twine "; then
|
||||||
|
echo "Installing twine..."
|
||||||
|
python3 -m pip install -q twine
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running twine upload..."
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
if python3 -m twine upload dist/*; then
|
||||||
|
print_success "Upload complete!"
|
||||||
|
else
|
||||||
|
print_error "Upload failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done!"
|
||||||
|
echo ""
|
||||||
|
exit 0
|
||||||
|
|
@ -8,7 +8,7 @@ version = "0.1.0"
|
||||||
description = "A Pythonic client for the Elytra PIM API"
|
description = "A Pythonic client for the Elytra PIM API"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.9"
|
requires-python = ">=3.9"
|
||||||
license = {text = "MIT"}
|
license = "MIT"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Your Name", email = "your.email@example.com"}
|
{name = "Your Name", email = "your.email@example.com"}
|
||||||
]
|
]
|
||||||
|
|
@ -16,7 +16,6 @@ keywords = ["elytra", "pim", "api", "client"]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 3 - Alpha",
|
"Development Status :: 3 - Alpha",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
|
|
|
||||||
10
setup.py
Normal file
10
setup.py
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
"""Setup configuration for Elytra PIM Client.
|
||||||
|
|
||||||
|
This setup.py file provides compatibility with legacy build tools.
|
||||||
|
The main configuration is in pyproject.toml (PEP 517/518).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
setup()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue