diff --git a/.gitignore b/.gitignore index 8a4c8936..d5252c32 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ __pycache__/ *$py.class /artifacts +scripts/artifacts # C extensions @@ -108,3 +109,4 @@ target/ *.dylib *.dll *.so +src/c2pa/libs/ diff --git a/Makefile b/Makefile index 2938e3d5..8d6399e4 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,14 @@ # Start from clean env: Delete `.venv`, then `python3 -m venv .venv` # Pre-requisite: Python virtual environment is active (source .venv/bin/activate) +clean: + rm -rf artifacts/ build/ dist/ + +clean-c2pa-env: + python3 -m pip uninstall -y c2pa + python3 -m pip cache purge + build-python: - python3 -m pip uninstall -y maturin python3 -m pip install -r requirements.txt python3 -m pip install -r requirements-dev.txt pip install -e . @@ -12,6 +18,20 @@ build-python: test: python3 ./tests/test_unit_tests.py +test-local-wheel-build: + # Clean any existing builds + rm -rf build/ dist/ + # Download artifacts and place them where they should go + python scripts/download_artifacts.py c2pa-v0.49.5 + # Install Python + python3 -m pip install -r requirements.txt + python3 -m pip install -r requirements-dev.txt + python setup.py bdist_wheel + # Install local build in venv + pip install $$(ls dist/*.whl) + # Verify installation in local venv + python -c "import c2pa; print('C2PA package installed at:', c2pa.__file__)" + publish: release python3 -m pip install twine python3 -m twine upload dist/* diff --git a/scripts/download_artifacts.py b/scripts/download_artifacts.py index a67fb11b..a62b1b88 100644 --- a/scripts/download_artifacts.py +++ b/scripts/download_artifacts.py @@ -5,12 +5,14 @@ from pathlib import Path import zipfile import io +import shutil # Constants REPO_OWNER = "contentauth" REPO_NAME = "c2pa-rs" GITHUB_API_BASE = "https://api.github.com" -ARTIFACTS_DIR = Path("artifacts") +SCRIPTS_ARTIFACTS_DIR = Path("scripts/artifacts") +ROOT_ARTIFACTS_DIR = Path("artifacts") def get_release_by_tag(tag): """Get release information for a specific tag from GitHub.""" @@ -22,7 +24,7 @@ def get_release_by_tag(tag): def download_and_extract_libs(url, platform_name): """Download a zip artifact and extract only the libs folder.""" print(f"Downloading artifact for {platform_name}...") - platform_dir = ARTIFACTS_DIR / platform_name + platform_dir = SCRIPTS_ARTIFACTS_DIR / platform_name platform_dir.mkdir(parents=True, exist_ok=True) response = requests.get(url) @@ -31,12 +33,28 @@ def download_and_extract_libs(url, platform_name): with zipfile.ZipFile(io.BytesIO(response.content)) as zip_ref: # Extract only files inside the libs/ directory for member in zip_ref.namelist(): + print(f" Processing zip member: {member}") if member.startswith("lib/") and not member.endswith("/"): + print(f" Processing lib file from downloadedzip: {member}") target_path = platform_dir / os.path.relpath(member, "lib") + print(f" Moving file to target path: {target_path}") target_path.parent.mkdir(parents=True, exist_ok=True) with zip_ref.open(member) as source, open(target_path, "wb") as target: target.write(source.read()) - print(f"Successfully downloaded and extracted libraries for {platform_name}") + + print(f"Done downloading and extracting libraries for {platform_name}") + +def copy_artifacts_to_root(): + """Copy the artifacts folder from scripts/artifacts to the root of the repository.""" + if not SCRIPTS_ARTIFACTS_DIR.exists(): + print("No artifacts found in scripts/artifacts") + return + + print("Copying artifacts from scripts/artifacts to root...") + if ROOT_ARTIFACTS_DIR.exists(): + shutil.rmtree(ROOT_ARTIFACTS_DIR) + shutil.copytree(SCRIPTS_ARTIFACTS_DIR, ROOT_ARTIFACTS_DIR) + print("Done copying artifacts") def main(): if len(sys.argv) < 2: @@ -46,11 +64,12 @@ def main(): release_tag = sys.argv[1] try: - ARTIFACTS_DIR.mkdir(exist_ok=True) + SCRIPTS_ARTIFACTS_DIR.mkdir(exist_ok=True) print(f"Fetching release information for tag {release_tag}...") release = get_release_by_tag(release_tag) print(f"Found release: {release['tag_name']}") + artifacts_downloaded = False for asset in release['assets']: if not asset['name'].endswith('.zip'): continue @@ -63,14 +82,17 @@ def main(): platform_name = '-'.join(parts[3:]).replace('.zip', '') download_and_extract_libs(asset['browser_download_url'], platform_name) + artifacts_downloaded = True - print("\nAll artifacts have been downloaded and extracted successfully!") + if artifacts_downloaded: + print("\nAll artifacts have been downloaded and extracted successfully!") + copy_artifacts_to_root() except requests.exceptions.RequestException as e: - print(f"Error downloading artifacts: {e}", file=sys.stderr) + print(f"Error: {e}") sys.exit(1) except Exception as e: - print(f"Unexpected error: {e}", file=sys.stderr) + print(f"Error: {e}") sys.exit(1) if __name__ == "__main__": diff --git a/setup.py b/setup.py index 18662687..bf70864c 100644 --- a/setup.py +++ b/setup.py @@ -36,29 +36,29 @@ def get_current_platform(): def copy_platform_libraries(platform_name, clean_first=False): """Copy libraries for a specific platform to the package libs directory. - + Args: platform_name: The platform to copy libraries for clean_first: If True, remove existing files in PACKAGE_LIBS_DIR first """ platform_dir = ARTIFACTS_DIR / platform_name - + # Ensure the platform directory exists and contains files if not platform_dir.exists(): raise ValueError(f"Platform directory not found: {platform_dir}") - + # Get list of all files in the platform directory platform_files = list(platform_dir.glob('*')) if not platform_files: raise ValueError(f"No files found in platform directory: {platform_dir}") - + # Clean and recreate the package libs directory if requested if clean_first and PACKAGE_LIBS_DIR.exists(): shutil.rmtree(PACKAGE_LIBS_DIR) - + # Ensure the package libs directory exists PACKAGE_LIBS_DIR.mkdir(parents=True, exist_ok=True) - + # Copy files from platform-specific directory to the package libs directory for file in platform_files: if file.is_file(): @@ -85,10 +85,10 @@ def find_available_platforms(): platform_dir = ARTIFACTS_DIR / platform_name if platform_dir.exists() and any(platform_dir.iterdir()): available_platforms.append(platform_name) - + if not available_platforms: raise ValueError("No platform-specific libraries found in artifacts directory") - + return available_platforms # For development installation @@ -100,13 +100,13 @@ def find_available_platforms(): if 'bdist_wheel' in sys.argv: available_platforms = find_available_platforms() print(f"Found libraries for platforms: {', '.join(available_platforms)}") - + for platform_name in available_platforms: print(f"\nBuilding wheel for {platform_name}...") try: # Copy libraries for this platform (cleaning first) copy_platform_libraries(platform_name, clean_first=True) - + # Build the wheel setup( name="c2pa", diff --git a/src/c2pa/build.py b/src/c2pa/build.py deleted file mode 100644 index 106dab9c..00000000 --- a/src/c2pa/build.py +++ /dev/null @@ -1,80 +0,0 @@ -import os -import sys -import json -import requests -from pathlib import Path -import zipfile -import io -from typing import Optional - -# Constants -REPO_OWNER = "contentauth" -REPO_NAME = "c2pa-rs" -GITHUB_API_BASE = "https://api.github.com" -ARTIFACTS_DIR = Path("artifacts") - -def get_latest_release() -> dict: - """Get the latest release information from GitHub.""" - url = f"{GITHUB_API_BASE}/repos/{REPO_OWNER}/{REPO_NAME}/releases/latest" - response = requests.get(url) - response.raise_for_status() - return response.json() - -def download_artifact(url: str, platform_name: str) -> None: - """Download and extract an artifact to the appropriate platform directory.""" - print(f"Downloading artifact for {platform_name}...") - - # Create platform directory - platform_dir = ARTIFACTS_DIR / platform_name - platform_dir.mkdir(parents=True, exist_ok=True) - - # Download the zip file - response = requests.get(url) - response.raise_for_status() - - # Extract the zip file - with zipfile.ZipFile(io.BytesIO(response.content)) as zip_ref: - # Extract all files to the platform directory - zip_ref.extractall(platform_dir) - - print(f"Successfully downloaded and extracted artifacts for {platform_name}") - -def download_artifacts() -> None: - """Main function to download artifacts. Can be called as a script or from hatch.""" - try: - # Create artifacts directory if it doesn't exist - ARTIFACTS_DIR.mkdir(exist_ok=True) - - # Get latest release - print("Fetching latest release information...") - release = get_latest_release() - print(f"Found release: {release['tag_name']}") - - # Download each asset - for asset in release['assets']: - # Skip non-zip files - if not asset['name'].endswith('.zip'): - continue - - # Determine platform from asset name - # Example: c2pa-rs-v1.0.0-macosx-arm64.zip - platform_name = asset['name'].split('-')[-1].replace('.zip', '') - - # Download and extract the artifact - download_artifact(asset['browser_download_url'], platform_name) - - print("\nAll artifacts have been downloaded successfully!") - - except requests.exceptions.RequestException as e: - print(f"Error downloading artifacts: {e}", file=sys.stderr) - sys.exit(1) - except Exception as e: - print(f"Unexpected error: {e}", file=sys.stderr) - sys.exit(1) - -def initialize_build() -> None: - """Initialize the build process by downloading artifacts.""" - download_artifacts() - -if __name__ == "__main__": - download_artifacts() \ No newline at end of file