Compare commits

..

No commits in common. "master" and "add-temp-2x-bundle" have entirely different histories.

7 changed files with 73 additions and 163 deletions

1
.gitignore vendored
View file

@ -7,4 +7,3 @@ dist
circuitpython_build_tools/data/ circuitpython_build_tools/data/
.eggs .eggs
version.py version.py
.env/*

View file

@ -1,50 +1,17 @@
dist: xenial sudo: false
dist: trusty
language: python language: python
python: python:
- '3.6' - '3.6'
script:
- python3 -m circuitpython_build_tools.scripts.build_mpy_cross circuitpython_build_tools/data/
stages:
- name: Tests
if: type = pull_request
- name: deploy
if: tag IS present
jobs:
include:
- stage: Tests
name: "Test CircuitPython Bundle"
python: "3.6"
script:
- echo "Building mpy-cross" && echo "travis_fold:start:mpy-cross"
- python3 -u -m circuitpython_build_tools.scripts.build_mpy_cross circuitpython_build_tools/data/
- echo "travis_fold:end:mpy-cross"
- pip install -e .
- echo "Cloning Adafruit_CircuitPython_Bundle" && echo "travis_fold:start:clone"
- git clone --recurse-submodules https://github.com/adafruit/Adafruit_CircuitPython_Bundle.git
- echo "travis_fold:end:clone"
- cd Adafruit_CircuitPython_Bundle
- circuitpython-build-bundles --filename_prefix test-bundle --library_location libraries --library_depth 2
- stage: Tests
name: "Test Single Library Bundle"
script:
- echo "Building mpy-cross" && echo "travis_fold:start:mpy-cross"
- python3 -u -m circuitpython_build_tools.scripts.build_mpy_cross circuitpython_build_tools/data/
- echo "travis_fold:end:mpy-cross"
- pip install -e .
- git clone https://github.com/adafruit/Adafruit_CircuitPython_FeatherWing.git
- cd Adafruit_CircuitPython_FeatherWing
- circuitpython-build-bundles --filename_prefix test-single --library_location .
- stage: deploy
script:
- python3 -u -m circuitpython_build_tools.scripts.build_mpy_cross circuitpython_build_tools/data/
deploy:
provider: pypi
user: "adafruit-travis"
password:
secure: tCjXwD8YeitG0HZLxW1D1QlVv4Xbj8mfRoqW0CM9ikPp3KY1PCz6Axj0PiOcyVwKdnxcUQ0EGRl16wEqwkObrmo9MboYrPuPqN00ULmyCQCRvJa2abIN6jDoLtBuf6bcze88t0XY2LdMOcj2Udv5Iijgf95zUgE+Z6BqT9Rgche78JEOeANJ7BlAJ6nRCA4whDdG7J9s7SmFtIjKWtMxig2J3X+Qy0bZ+Armtfp9/CRvjLJ8juDrcCBSysWLnAYLS4u8e/rbSTh8YwFeoeJ1pp9qSmME5NuwScY18QmfESNSqz8wVVXtAFKdoMOCoN+/CodTxp9aB0QsXX6yOYg74ahDIaci239wgnuUqxSaeLxeSwWkkVCXWdQVuP4vgq3GZwm2yNOQ1ZjfFbXF156yv0uSVw5nuaxv0YblQTinJtL4x9hwOdPDJio3b6UT3H1ue9l1qK0LT2OSkzDgn12WmTnTfRUH3BkU6onsYsdP33PK1YhepeQnfbT1P3ikrRHIwGYb7XqcjOtJh413kid6YezCXRqccl8kAxegnqX+cQG7K9ilpZtWaVYLu4RRBJ37H4vpuOb3SV686Y62sWPUXEbI3MR1OxU+RrRr/9DCH1EFXnlYT9LF986wXFJtWuSc+pbXuxY7qduai0hn5Pft6XH31exyiOwAHBIFeYebnVM=
skip_cleanup: true
on:
tags: true
deploy:
provider: pypi
user: "adafruit-travis"
password:
secure: tCjXwD8YeitG0HZLxW1D1QlVv4Xbj8mfRoqW0CM9ikPp3KY1PCz6Axj0PiOcyVwKdnxcUQ0EGRl16wEqwkObrmo9MboYrPuPqN00ULmyCQCRvJa2abIN6jDoLtBuf6bcze88t0XY2LdMOcj2Udv5Iijgf95zUgE+Z6BqT9Rgche78JEOeANJ7BlAJ6nRCA4whDdG7J9s7SmFtIjKWtMxig2J3X+Qy0bZ+Armtfp9/CRvjLJ8juDrcCBSysWLnAYLS4u8e/rbSTh8YwFeoeJ1pp9qSmME5NuwScY18QmfESNSqz8wVVXtAFKdoMOCoN+/CodTxp9aB0QsXX6yOYg74ahDIaci239wgnuUqxSaeLxeSwWkkVCXWdQVuP4vgq3GZwm2yNOQ1ZjfFbXF156yv0uSVw5nuaxv0YblQTinJtL4x9hwOdPDJio3b6UT3H1ue9l1qK0LT2OSkzDgn12WmTnTfRUH3BkU6onsYsdP33PK1YhepeQnfbT1P3ikrRHIwGYb7XqcjOtJh413kid6YezCXRqccl8kAxegnqX+cQG7K9ilpZtWaVYLu4RRBJ37H4vpuOb3SV686Y62sWPUXEbI3MR1OxU+RrRr/9DCH1EFXnlYT9LF986wXFJtWuSc+pbXuxY7qduai0hn5Pft6XH31exyiOwAHBIFeYebnVM=
skip_cleanup: true
on:
tags: true

View file

@ -1,6 +1,6 @@
# Adafruit CircuitPython Build Tools # Adafruit CircuitPython Build Tools
[![Discord](https://img.shields.io/discord/327254708534116352.svg)](https://adafru.it/discord) [![Discord](https://img.shields.io/discord/327254708534116352.svg)](https://discord.gg/nBQh6qu)
This repo contains build scripts used to build the This repo contains build scripts used to build the
[Adafruit CircuitPython bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle), [CircuitPython Community bundle](https://github.com/adafruit/CircuitPython_Community_Bundle) [Adafruit CircuitPython bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle), [CircuitPython Community bundle](https://github.com/adafruit/CircuitPython_Community_Bundle)
@ -56,20 +56,3 @@ source .env/bin/activate
pip install circuitpython-build-tools pip install circuitpython-build-tools
circuitpython-build-bundles --filename_prefix <output file prefix> --library_location . circuitpython-build-bundles --filename_prefix <output file prefix> --library_location .
``` ```
When making changes to `circuitpython-build-tools` itself, you can test your changes
locally like so:
```shell
cd circuitpython-build-tools # this will be specific to your storage location
python3 -m venv .env
source .env/bin/activate
pip install -e . # '-e' is pip's "development" install feature
circuitpython-build-bundles --filename_prefix <output file prefix> --library_location <library location>
```
## Contributing
Contributions are welcome! Please read our [Code of Conduct]
(https://github.com/adafruit/Adafruit_CircuitPython_adabot/blob/master/CODE_OF_CONDUCT.md)
before contributing to help this project stay welcoming.

View file

@ -3,7 +3,6 @@
# The MIT License (MIT) # The MIT License (MIT)
# #
# Copyright (c) 2016 Scott Shawcroft for Adafruit Industries # Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
# 2018, 2019 Michael Schroeder
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy # Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal # of this software and associated documentation files (the "Software"), to deal
@ -25,7 +24,6 @@
import os import os
import os.path import os.path
import pathlib
import semver import semver
import shutil import shutil
import sys import sys
@ -33,7 +31,6 @@ import subprocess
import tempfile import tempfile
IGNORE_PY = ["setup.py", "conf.py", "__init__.py"] IGNORE_PY = ["setup.py", "conf.py", "__init__.py"]
GLOB_PATTERNS = ["*.py", "font5x8.bin"]
def version_string(path=None, *, valid_semver=False): def version_string(path=None, *, valid_semver=False):
version = None version = None
@ -93,62 +90,39 @@ def mpy_cross(mpy_cross_filename, circuitpython_tag, quiet=False):
def _munge_to_temp(original_path, temp_file, library_version): def _munge_to_temp(original_path, temp_file, library_version):
with open(original_path, "rb") as original_file: with open(original_path, "rb") as original_file:
for line in original_file: for line in original_file:
if original_path.endswith(".bin"): line = line.decode("utf-8").strip("\n")
# this is solely for adafruit_framebuf/examples/font5x8.bin if line.startswith("__version__"):
temp_file.write(line) line = line.replace("0.0.0-auto.0", library_version)
else: temp_file.write(line.encode("utf-8") + b"\r\n")
line = line.decode("utf-8").strip("\n")
if line.startswith("__version__"):
line = line.replace("0.0.0-auto.0", library_version)
temp_file.write(line.encode("utf-8") + b"\r\n")
temp_file.flush() temp_file.flush()
def library(library_path, output_directory, package_folder_prefix, def library(library_path, output_directory, mpy_cross=None, example_bundle=False):
mpy_cross=None, example_bundle=False):
py_files = [] py_files = []
package_files = [] package_files = []
example_files = [] example_files = []
total_size = 512 total_size = 512
for filename in os.listdir(library_path):
lib_path = pathlib.Path(library_path) full_path = os.path.join(library_path, filename)
parent_idx = len(lib_path.parts) if os.path.isdir(full_path) and filename not in ["docs"]:
glob_search = [] files = os.listdir(full_path)
for pattern in GLOB_PATTERNS: files = filter(lambda x: x.endswith(".py"), files)
glob_search.extend(list(lib_path.rglob(pattern))) files = map(lambda x: os.path.join(filename, x), files)
if filename.startswith("examples"):
for file in glob_search: example_files.extend(files)
if file.parts[parent_idx] == "examples": else:
example_files.append(file) if not example_bundle:
else: package_files.extend(files)
if not example_bundle: if (filename.endswith(".py") and
is_package = False filename not in IGNORE_PY and
for prefix in package_folder_prefix: not example_bundle):
if file.parts[parent_idx].startswith(prefix): py_files.append(filename)
is_package = True
if is_package:
package_files.append(file)
else:
if file.name in IGNORE_PY:
#print("Ignoring:", file.resolve())
continue
if file.parent == lib_path:
py_files.append(file)
if len(py_files) > 1: if len(py_files) > 1:
raise ValueError("Multiple top level py files not allowed. Please put " raise ValueError("Multiple top level py files not allowed. Please put them in a package "
"them in a package or combine them into a single file.") "or combine them into a single file.")
for fn in example_files:
base_dir = os.path.join(output_directory.replace("/lib", "/"),
fn.relative_to(library_path).parent)
if not os.path.isdir(base_dir):
os.makedirs(base_dir)
total_size += 512
for fn in package_files: for fn in package_files:
base_dir = os.path.join(output_directory, base_dir = os.path.join(output_directory, os.path.dirname(fn))
fn.relative_to(library_path).parent)
if not os.path.isdir(base_dir): if not os.path.isdir(base_dir):
os.makedirs(base_dir) os.makedirs(base_dir)
total_size += 512 total_size += 512
@ -166,20 +140,16 @@ def library(library_path, output_directory, package_folder_prefix,
for filename in py_files: for filename in py_files:
full_path = os.path.join(library_path, filename) full_path = os.path.join(library_path, filename)
output_file = os.path.join( output_file = os.path.join(output_directory,
output_directory, filename.replace(".py", new_extension))
filename.relative_to(library_path).with_suffix(new_extension)
)
with tempfile.NamedTemporaryFile() as temp_file: with tempfile.NamedTemporaryFile() as temp_file:
_munge_to_temp(full_path, temp_file, library_version) _munge_to_temp(full_path, temp_file, library_version)
if mpy_cross: if mpy_cross:
mpy_success = subprocess.call([ mpy_success = subprocess.call([mpy_cross,
mpy_cross, "-o", output_file,
"-o", output_file, "-s", filename,
"-s", str(filename.relative_to(library_path)), temp_file.name])
temp_file.name
])
if mpy_success != 0: if mpy_success != 0:
raise RuntimeError("mpy-cross failed on", full_path) raise RuntimeError("mpy-cross failed on", full_path)
else: else:
@ -189,29 +159,24 @@ def library(library_path, output_directory, package_folder_prefix,
full_path = os.path.join(library_path, filename) full_path = os.path.join(library_path, filename)
with tempfile.NamedTemporaryFile() as temp_file: with tempfile.NamedTemporaryFile() as temp_file:
_munge_to_temp(full_path, temp_file, library_version) _munge_to_temp(full_path, temp_file, library_version)
if not mpy_cross or os.stat(full_path).st_size == 0: if (not mpy_cross or
output_file = os.path.join(output_directory, os.stat(full_path).st_size == 0 or
filename.relative_to(library_path)) filename.endswith("__init__.py")):
output_file = os.path.join(output_directory, filename)
shutil.copyfile(temp_file.name, output_file) shutil.copyfile(temp_file.name, output_file)
else: else:
output_file = os.path.join( output_file = os.path.join(output_directory,
output_directory, filename.replace(".py", new_extension))
filename.relative_to(library_path).with_suffix(new_extension) mpy_success = subprocess.call([mpy_cross,
) "-o", output_file,
"-s", filename,
mpy_success = subprocess.call([ temp_file.name])
mpy_cross,
"-o", output_file,
"-s", str(filename.relative_to(library_path)),
temp_file.name
])
if mpy_success != 0: if mpy_success != 0:
raise RuntimeError("mpy-cross failed on", full_path) raise RuntimeError("mpy-cross failed on", full_path)
for filename in example_files: for filename in example_files:
full_path = os.path.join(library_path, filename) full_path = os.path.join(library_path, filename)
output_file = os.path.join(output_directory.replace("/lib", "/"), output_file = os.path.join(output_directory.replace("/lib", "/"), filename)
filename.relative_to(library_path))
with tempfile.NamedTemporaryFile() as temp_file: with tempfile.NamedTemporaryFile() as temp_file:
_munge_to_temp(full_path, temp_file, library_version) _munge_to_temp(full_path, temp_file, library_version)
shutil.copyfile(temp_file.name, output_file) shutil.copyfile(temp_file.name, output_file)

View file

@ -48,12 +48,11 @@ def add_file(bundle, src_file, zip_name):
return file_sector_size return file_sector_size
def build_bundle(libs, bundle_version, output_filename, package_folder_prefix, def build_bundle(libs, bundle_version, output_filename,
build_tools_version="devel", mpy_cross=None, example_bundle=False): build_tools_version="devel", mpy_cross=None, example_bundle=False):
build_dir = "build-" + os.path.basename(output_filename) build_dir = "build-" + os.path.basename(output_filename)
top_folder = os.path.basename(output_filename).replace(".zip", "") build_lib_dir = os.path.join(build_dir, build_dir.replace(".zip", ""), "lib")
build_lib_dir = os.path.join(build_dir, top_folder, "lib") build_example_dir = os.path.join(build_dir, build_dir.replace(".zip", ""), "examples")
build_example_dir = os.path.join(build_dir, top_folder, "examples")
if os.path.isdir(build_dir): if os.path.isdir(build_dir):
print("Deleting existing build.") print("Deleting existing build.")
shutil.rmtree(build_dir) shutil.rmtree(build_dir)
@ -69,8 +68,8 @@ def build_bundle(libs, bundle_version, output_filename, package_folder_prefix,
success = True success = True
for library_path in libs: for library_path in libs:
try: try:
build.library(library_path, build_lib_dir, package_folder_prefix, build.library(library_path, build_lib_dir, mpy_cross=mpy_cross,
mpy_cross=mpy_cross, example_bundle=example_bundle) example_bundle=example_bundle)
except ValueError as e: except ValueError as e:
print("build.library failure:", library_path) print("build.library failure:", library_path)
print(e) print(e)
@ -79,9 +78,9 @@ def build_bundle(libs, bundle_version, output_filename, package_folder_prefix,
print() print()
print("Generating VERSIONS") print("Generating VERSIONS")
if multiple_libs: if multiple_libs:
with open(os.path.join(build_dir, top_folder, "VERSIONS.txt"), "w") as f: with open(os.path.join(build_dir, build_dir.replace(".zip", ""), "VERSIONS.txt"), "w") as f:
f.write(bundle_version + "\r\n") f.write(bundle_version + "\r\n")
versions = subprocess.run('git submodule --quiet foreach \"git remote get-url origin && git describe --tags\"', shell=True, stdout=subprocess.PIPE, cwd=os.path.commonpath(libs)) versions = subprocess.run('git submodule foreach \"git remote get-url origin && git describe --tags\"', shell=True, stdout=subprocess.PIPE, cwd=os.path.commonpath(libs))
if versions.returncode != 0: if versions.returncode != 0:
print("Failed to generate versions file. Its likely a library hasn't been " print("Failed to generate versions file. Its likely a library hasn't been "
"released yet.") "released yet.")
@ -89,11 +88,9 @@ def build_bundle(libs, bundle_version, output_filename, package_folder_prefix,
repo = None repo = None
for line in versions.stdout.split(b"\n"): for line in versions.stdout.split(b"\n"):
if not line: if line.startswith(b"Entering") or not line:
continue continue
if line.startswith(b"ssh://git@"): if line.startswith(b"git@"):
repo = b"https://" + line.split(b"@")[1][:-len(".git")]
elif line.startswith(b"git@"):
repo = b"https://github.com/" + line.split(b":")[1][:-len(".git")] repo = b"https://github.com/" + line.split(b":")[1][:-len(".git")]
elif line.startswith(b"https:"): elif line.startswith(b"https:"):
repo = line.strip()[:-len(".git")] repo = line.strip()[:-len(".git")]
@ -111,9 +108,10 @@ def build_bundle(libs, bundle_version, output_filename, package_folder_prefix,
build_metadata = {"build-tools-version": build_tools_version} build_metadata = {"build-tools-version": build_tools_version}
bundle.comment = json.dumps(build_metadata).encode("utf-8") bundle.comment = json.dumps(build_metadata).encode("utf-8")
if multiple_libs: if multiple_libs:
total_size += add_file(bundle, "README.txt", os.path.join(top_folder, "README.txt")) readme_zip_dir = build_dir.replace(".zip", "")
total_size += add_file(bundle, "README.txt", os.path.join(readme_zip_dir.replace("-", "_"), "README.txt"))
for root, dirs, files in os.walk(build_dir): for root, dirs, files in os.walk(build_dir):
ziproot = root[len(build_dir + "/"):] ziproot = root[len(build_dir + "/"):].replace("-", "_")
for filename in files: for filename in files:
total_size += add_file(bundle, os.path.join(root, filename), total_size += add_file(bundle, os.path.join(root, filename),
os.path.join(ziproot, filename.replace("-", "_"))) os.path.join(ziproot, filename.replace("-", "_")))
@ -137,12 +135,9 @@ def _find_libraries(current_path, depth):
@click.option('--output_directory', default="bundles", help="Output location for the zip files.") @click.option('--output_directory', default="bundles", help="Output location for the zip files.")
@click.option('--library_location', required=True, help="Location of libraries to bundle.") @click.option('--library_location', required=True, help="Location of libraries to bundle.")
@click.option('--library_depth', default=0, help="Depth of library folders. This is useful when multiple libraries are bundled together but are initially in separate subfolders.") @click.option('--library_depth', default=0, help="Depth of library folders. This is useful when multiple libraries are bundled together but are initially in separate subfolders.")
@click.option('--package_folder_prefix', default="adafruit_", help="Prefix string used to determine package folders to bundle.") def build_bundles(filename_prefix, output_directory, library_location, library_depth):
def build_bundles(filename_prefix, output_directory, library_location, library_depth, package_folder_prefix):
os.makedirs(output_directory, exist_ok=True) os.makedirs(output_directory, exist_ok=True)
package_folder_prefix = package_folder_prefix.split(", ")
bundle_version = build.version_string() bundle_version = build.version_string()
libs = _find_libraries(os.path.abspath(library_location), library_depth) libs = _find_libraries(os.path.abspath(library_location), library_depth)
@ -162,7 +157,7 @@ def build_bundles(filename_prefix, output_directory, library_location, library_d
zip_filename = os.path.join(output_directory, zip_filename = os.path.join(output_directory,
filename_prefix + '-py-{VERSION}.zip'.format( filename_prefix + '-py-{VERSION}.zip'.format(
VERSION=bundle_version)) VERSION=bundle_version))
build_bundle(libs, bundle_version, zip_filename, package_folder_prefix, build_bundle(libs, bundle_version, zip_filename,
build_tools_version=build_tools_version) build_tools_version=build_tools_version)
# Build .mpy bundle(s) # Build .mpy bundle(s)
@ -179,12 +174,12 @@ def build_bundles(filename_prefix, output_directory, library_location, library_d
filename_prefix + '-{TAG}-mpy-{VERSION}.zip'.format( filename_prefix + '-{TAG}-mpy-{VERSION}.zip'.format(
TAG=version["name"], TAG=version["name"],
VERSION=bundle_version)) VERSION=bundle_version))
build_bundle(libs, bundle_version, zip_filename, package_folder_prefix, build_bundle(libs, bundle_version, zip_filename, mpy_cross=mpy_cross,
mpy_cross=mpy_cross, build_tools_version=build_tools_version) build_tools_version=build_tools_version)
# Build example bundle # Build example bundle
zip_filename = os.path.join(output_directory, zip_filename = os.path.join(output_directory,
filename_prefix + '-examples-{VERSION}.zip'.format( filename_prefix + '-examples-{VERSION}.zip'.format(
VERSION=bundle_version)) VERSION=bundle_version))
build_bundle(libs, bundle_version, zip_filename, package_folder_prefix, build_bundle(libs, bundle_version, zip_filename,
build_tools_version=build_tools_version, example_bundle=True) build_tools_version=build_tools_version, example_bundle=True)

View file

@ -25,5 +25,7 @@
# The tag specifies which version of CircuitPython to use for mpy-cross. # The tag specifies which version of CircuitPython to use for mpy-cross.
# The name is used when constructing the zip file names. # The name is used when constructing the zip file names.
VERSIONS = [ VERSIONS = [
{"tag": "6.1.0", "name": "6.x"}, {"tag": "2.3.1", "name": "2.x"},
{"tag": "3.0.0", "name": "3.x"},
{"tag": "4.0.0-alpha.2", "name": "4.x"},
] ]

View file

@ -1,3 +1,2 @@
Click Click
semver semver
wheel