diff --git a/Dockerfile b/Dockerfile index 911c066..56e8c9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM kivy/buildozer:latest # See https://github.com/kivy/buildozer/blob/master/Dockerfile -# Buildozer will be installed in entrypoint.sh +# Buildozer will be installed in entrypoint.py # This is needed to install version specified by user RUN pip3 uninstall -y buildozer @@ -10,7 +10,5 @@ RUN pip3 uninstall -y buildozer # See https://github.com/sudo-project/sudo/issues/42 RUN echo "Set disable_coredump false" | sudo tee -a /etc/sudo.conf > /dev/null -COPY entrypoint.sh /action/entrypoint.sh -COPY patches.py /action/patches.py - -ENTRYPOINT ["/action/entrypoint.sh"] +COPY entrypoint.py /action/entrypoint.py +ENTRYPOINT ["/action/entrypoint.py"] diff --git a/README.md b/README.md index 77d8789..2a056dc 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,14 @@ but adds some features and patches to use in GitHub Actions. **Required** Command to start Buildozer. - _Default:_ `buildozer android debug` _(iOS and OSX is not supported because Docker cannot run on MacOS)_. -- For more commands use `;` as delimiter: `python3 setup.py build_ext --inplace; buildozer android debug`. +- For more commands use `;` as delimiter: `python3 pre_buildozer.py; buildozer android debug`. + +### `repository_root` + +**Required** Path to cloned repository. + +- _Default:_ `.` (GitHub workspace). +- Set to directory name if you specified path for `actions/checkout` action. ### `workdir` diff --git a/action.yml b/action.yml index 03bf92a..f494e47 100644 --- a/action.yml +++ b/action.yml @@ -10,6 +10,10 @@ inputs: description: Command to start Buildozer. Set to `buildozer ios debug` for iOS required: true default: buildozer android debug + repository_root: + description: Path to cloned repository. Set if you specified path for `actions/checkout` action. + required: true + default: . workdir: description: Working directory where buildozer.spec is located. Set to `src` if buildozer.spec is in `src` directory required: true diff --git a/entrypoint.py b/entrypoint.py new file mode 100644 index 0000000..7b83d25 --- /dev/null +++ b/entrypoint.py @@ -0,0 +1,142 @@ +#!/bin/python3 +""" +Buildozer action +================ + +It sets some environment variables, installs Buildozer, runs Buildozer and finds +output file. + +You can read this file top down because functions are ordered by their execution +order. +""" + +import os +from os import environ as env +import subprocess + + +def main(): + repository_root = os.path.abspath(env["INPUT_REPOSITORY_ROOT"]) + change_owner(env["USER"], repository_root) + fix_home() + install_buildozer(env["INPUT_BUILDOZER_VERSION"]) + apply_buildozer_settings() + change_directory(env["INPUT_REPOSITORY_ROOT"], env["INPUT_WORKDIR"]) + apply_patches() + run_command(env["INPUT_COMMAND"]) + set_output(env["INPUT_REPOSITORY_ROOT"], env["INPUT_WORKDIR"]) + change_owner("root", repository_root) + + +def change_owner(user, repository_root): + # GitHub sets root as owner of repository directory. Change it to user + # And return to root after all commands + subprocess.check_call(["sudo", "chown", "-R", user, repository_root]) + + +def fix_home(): + # GitHub sets HOME to /github/home, but Buildozer is installed to /home/user. Change HOME to user's home + env["HOME"] = env["HOME_DIR"] + + +def install_buildozer(buildozer_version): + # Install required Buildozer version + print("::group::Installing Buildozer") + pip_install = "pip3 install --user --upgrade".split() + if buildozer_version == "stable": + # Install stable buildozer from PyPI + subprocess.check_call([*pip_install, "buildozer"]) + elif os.path.exists(buildozer_version): + # Install from local directory + subprocess.check_call([*pip_install, buildozer_version]) + elif buildozer_version.startswith("git+"): + # Install from specified git+ link + subprocess.check_call([*pip_install, buildozer_version]) + elif buildozer_version == "": + # Just do nothing + print( + "::warning::Buildozer is not installed because " + "specified buildozer_version is nothing." + ) + else: + # Install specified ref from repository + subprocess.check_call( + [ + *pip_install, + f"git+https://github.com/kivy/buildozer.git@{buildozer_version}", + ] + ) + print("::endgroup::") + + +def apply_buildozer_settings(): + # Buildozer settings to disable interactions + env["BUILDOZER_WARN_ON_ROOT"] = "0" + env["APP_ANDROID_ACCEPT_SDK_LICENSE"] = "1" + # Do not allow to change directories + env["BUILDOZER_BUILD_DIR"] = "./.buildozer" + env["BUILDOZER_BIN"] = "./bin" + + +def change_directory(repository_root, workdir): + directory = os.path.join(repository_root, workdir) + # Change directory to workir + if not os.path.exists(directory): + print("::error::Specified workdir is not exists.") + exit(1) + os.chdir(directory) + + +def apply_patches(): + # Apply patches + print("::group::Applying patches to Buildozer") + try: + import buildozer + except ImportError: + print( + "::error::Cannot apply patches to buildozer (ImportError). " + "Update buildozer-action to new version or create a Bug Request" + ) + return + + print("Changing global_buildozer_dir") + source = open(buildozer.__file__, "r", encoding="utf-8").read() + new_source = source.replace( + """ + @property + def global_buildozer_dir(self): + return join(expanduser('~'), '.buildozer') + """, + f""" + @property + def global_buildozer_dir(self): + return '{os.environ["GITHUB_WORKSPACE"]}/.buildozer_global' + """, + ) + if new_source == source: + print( + "::warning::Cannot change global buildozer directory. " + "Update buildozer-action to new version or create a Bug Request" + ) + open(buildozer.__file__, "w", encoding="utf-8").write(new_source) + print("::endgroup::") + + +def run_command(command): + # Run command + retcode = subprocess.check_call(command.split()) + if retcode: + print(f'::error::Error while executing command "{command}"') + exit(1) + + +def set_output(repository_root, workdir): + if not os.path.exists("bin"): + print("::error::Output directory does not exist. See Buildozer log for error") + exit(1) + filename = [file for file in os.listdir("bin") if os.path.isfile(os.path.join("bin", file))][0] + print(f"::set-output name=filename::{os.path.join(repository_root, workdir, 'bin', filename)}") + + +if __name__ == "__main__": + main() diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100755 index 23d611f..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# GitHub sets root as owner of repository directory. Change it to user -sudo chown -R "$USER" "$GITHUB_WORKSPACE" -# GitHub sets HOME to /github/home, but Buildozer is installed to /home/user. Change HOME to user's home -export HOME=$HOME_DIR - -# Install required Buildozer version -echo ::group::Installing Buildozer -PIP_INSTALL="pip3 install --user --upgrade" -if [[ "$INPUT_BUILDOZER_VERSION" == "stable" ]]; then - $PIP_INSTALL buildozer # Install stable buildozer from PyPI -elif [[ -d "$INPUT_BUILDOZER_VERSION" ]]; then - $PIP_INSTALL "$INPUT_BUILDOZER_VERSION" # Install from local directory -elif [[ "$INPUT_BUILDOZER_VERSION" == "git+"* ]]; then - $PIP_INSTALL "$INPUT_BUILDOZER_VERSION" # Install from specified git+ link -elif [[ "$INPUT_BUILDOZER_VERSION" == "" ]]; then - echo ::warning::Buildozer is not installed because specified buildozer_version is nothing. # Just do nothing -else - $PIP_INSTALL "git+https://github.com/kivy/buildozer.git@$INPUT_BUILDOZER_VERSION" # Install specified ref from repository -fi -echo ::endgroup:: - -# Buildozer settings to disable interactions -export BUILDOZER_WARN_ON_ROOT=0 -export APP_ANDROID_ACCEPT_SDK_LICENSE=1 -# Do not allow to change directories -export BUILDOZER_BUILD_DIR=./.buildozer -export BUILDOZER_BIN=./bin - -# Change directory to workir -if ! cd "$INPUT_WORKDIR"; then - echo ::error::Specified workdir is not exists. - exit 1 -fi - -# Apply patches -echo ::group::Applying patches to Buildozer -if ! python3 /action/patches.py; then - echo ::error::Error while running patches.py - # exit 1 # Allow to fail -fi -echo ::endgroup:: - -# Run command -if ! sh -c "$INPUT_COMMAND"; then - echo ::error::Error while executing command \""$INPUT_COMMAND"\" - exit 1 -fi - -# Give access to root -sudo chown -R root "$GITHUB_WORKSPACE" - -# Set output -if [ ! -d bin ]; then - echo ::error::Output directory does not exist. See Buildozer log for error - exit 1 -fi -filename=$(ls bin | head -n1) -echo ::set-output name=filename::"$INPUT_WORKDIR/bin/$filename" diff --git a/patches.py b/patches.py deleted file mode 100644 index 5a1c3b4..0000000 --- a/patches.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -import buildozer - -print("Changing global_buildozer_dir") -source = open(buildozer.__file__, "r", encoding="utf-8").read() -new_source = source.replace( - """ - @property - def global_buildozer_dir(self): - return join(expanduser('~'), '.buildozer') -""", - f""" - @property - def global_buildozer_dir(self): - return '{os.environ["GITHUB_WORKSPACE"]}/.buildozer_global' -""", -) -if new_source == source: - print("::warning::Cannot change global buildozer directory. Update buildozer-action to new version or create a Bug Request") -open(buildozer.__file__, "w", encoding="utf-8").write(new_source)