From 122ce642964057bd0b6562e372fef1e6a5f2bdfd Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Sun, 26 May 2024 14:04:43 +0200 Subject: [PATCH 1/4] Replace ad hoc build system This is modelled after the corresponding changes in `acap-rs` and the motivation is largely the same; in summary it makes it easier to share improvements since we don't need to patch `Makefile`s that may have diverged, and allows more sophisticated integration with Cargo such as getting the name of test binaries build or using build scripts to prepare additional files dynamically. Enumerate workflows in readme This gives potential users a preview of what is available without downloading or installing anything. --- .github/workflows/CI.yml | 2 +- Cross.toml | 27 ----------- Dockerfile | 60 ++++++++++++++++++++++++ Makefile | 99 ++++++++++++++++------------------------ README.md | 31 ++++++++++++- docker/install_rust.sh | 15 ++++++ src/main.rs | 14 ++++++ 7 files changed, 159 insertions(+), 89 deletions(-) delete mode 100644 Cross.toml create mode 100644 Dockerfile create mode 100755 docker/install_rust.sh diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 827bf2e..80c089a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -12,7 +12,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies - run: cargo install cross + run: cargo install --path crates/cargo-acap-sdk - name: Run checks run: | make --always-make check_all diff --git a/Cross.toml b/Cross.toml deleted file mode 100644 index c54eff1..0000000 --- a/Cross.toml +++ /dev/null @@ -1,27 +0,0 @@ -[build] -pre-build = ["apt-get update && apt-get install -y clang && rm -rf /var/lib/apt/lists/*"] - - -[target.aarch64-unknown-linux-gnu] -image = "axisecp/acap-native-sdk:1.12-aarch64-ubuntu22.04" - -[target.aarch64-unknown-linux-gnu.env] -passthrough = [ - "PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu=/opt/axis/acapsdk/sysroots/aarch64", - "PKG_CONFIG_PATH_aarch64_unknown_linux_gnu=/opt/axis/acapsdk/sysroots/aarch64/usr/lib/pkgconfig:/opt/axis/acapsdk/sysroots/aarch64/usr/share/pkgconfig", - "PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu=/opt/axis/acapsdk/sysroots/aarch64/usr/lib/pkgconfig:/opt/axis/acapsdk/sysroots/aarch64/usr/share/pkgconfig", - "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc", - "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS=-C link-args=--sysroot=/opt/axis/acapsdk/sysroots/aarch64", -] - -[target.thumbv7neon-unknown-linux-gnueabihf] -image = "axisecp/acap-native-sdk:1.12-armv7hf-ubuntu22.04" - -[target.thumbv7neon-unknown-linux-gnueabihf.env] -passthrough = [ - "PKG_CONFIG_SYSROOT_DIR_thumbv7neon_unknown_linux_gnueabihf=/opt/axis/acapsdk/sysroots/armv7hf", - "PKG_CONFIG_PATH_thumbv7neon_unknown_linux_gnueabihf=/opt/axis/acapsdk/sysroots/armv7hf/usr/lib/pkgconfig:/opt/axis/acapsdk/sysroots/armv7hf/usr/share/pkgconfig", - "PKG_CONFIG_LIBDIR_thumbv7neon_unknown_linux_gnueabihf=/opt/axis/acapsdk/sysroots/armv7hf/usr/lib/pkgconfig:/opt/axis/acapsdk/sysroots/armv7hf/usr/share/pkgconfig", - "CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc", - "CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS=-C link-args=--sysroot=/opt/axis/acapsdk/sysroots/armv7hf", -] \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2a3071d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,60 @@ +ARG REPO=axisecp +ARG SDK=acap-native-sdk +ARG UBUNTU_VERSION=22.04 +ARG VERSION=1.14 +ARG BASE_IMAGE=debian:bookworm-20240423-slim + +FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 +FROM ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf +FROM ${BASE_IMAGE} + +COPY --from=sdk-aarch64 /opt/axis/acapsdk/axis-acap-manifest-tools /opt/axis/acapsdk/axis-acap-manifest-tools +COPY --from=sdk-aarch64 /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux +COPY --from=sdk-armv7hf /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi +COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/aarch64 /opt/axis/acapsdk/sysroots/aarch64 +COPY --from=sdk-armv7hf /opt/axis/acapsdk/sysroots/armv7hf /opt/axis/acapsdk/sysroots/armv7hf +COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux + +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + clang \ + curl \ + g++-aarch64-linux-gnu \ + g++-arm-linux-gnueabihf \ + inetutils-ping \ + pkg-config \ + python3-jsonschema \ + wget \ + && rm -rf /var/lib/apt/lists/* + +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:$PATH + +COPY docker/install_rust.sh rust-toolchain.toml ./ +RUN ./install_rust.sh \ + && rustup target add \ + aarch64-unknown-linux-gnu \ + thumbv7neon-unknown-linux-gnueabihf \ + && rm install_rust.sh rust-toolchain.toml + +ENV \ + SYSROOT_AARCH64=/opt/axis/acapsdk/sysroots/aarch64 \ + SYSROOT_ARMV7HF=/opt/axis/acapsdk/sysroots/armv7hf +# The above makes the below easier to read +ENV \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="aarch64-linux-gnu-gcc" \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_AARCH64}" \ + CC_aarch64_axis_linux_gnu="aarch64-linux-gnu-gcc" \ + CXX_aarch64_axis_linux_gnu="aarch64-linux-gnu-g++" \ + PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ + PKG_CONFIG_PATH_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ + PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}" \ + CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER="arm-linux-gnueabihf-gcc" \ + CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_ARMV7HF}" \ + CC_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-gcc" \ + CXX_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-g++" \ + PKG_CONFIG_LIBDIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ + PKG_CONFIG_PATH_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ + PKG_CONFIG_SYSROOT_DIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}" diff --git a/Makefile b/Makefile index 63b6c30..3765b1e 100644 --- a/Makefile +++ b/Makefile @@ -34,60 +34,70 @@ PASS ?= pass # Prevent pesky default rules from creating unexpected dependency graphs. .SUFFIXES: ; -# Rebuild targets when marking them as phony directly is not enough. -FORCE:; -.PHONY: FORCE - -DOCKER_RUN = docker run \ ---volume ${CURDIR}/target/$(ARCH)/$(PACKAGE)/:/opt/app \ ---user $(shell id -u):$(shell id -g) \ -axisecp/acap-native-sdk:1.12-$(ARCH)-ubuntu22.04 +EAP_INSTALL = cd ${CURDIR}/target/$(ARCH)/$(PACKAGE)/ \ +&& cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile -- \ +sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) $@" ## Verbs ## ===== ## Build app for all architectures -build: target/aarch64/$(PACKAGE)/_envoy target/armv7hf/$(PACKAGE)/_envoy - mkdir -p target/acap - cp $(patsubst %/_envoy,%/*.eap,$^) target/acap +build: + cargo-acap-sdk build ## Install app on using password and assuming architecture install: - @ $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) install" \ + cargo-acap-sdk install --docker-file ${CURDIR}/Dockerfile --address $(DEVICE_IP) --password $(PASS) --target $(ARCH) \ | grep -v '^to start your application type$$' \ | grep -v '^ eap-install.sh start$$' ## Remove app from using password and assuming architecture remove: - @ $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) remove" + @ $(EAP_INSTALL) ## Start app on using password and assuming architecture start: - @ $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) start" \ - | grep -v '^to stop your application type$$' \ - | grep -v '^ eap-install.sh stop$$' + @ # Don't match the line endings because docker replace LF with CR + LF when given `--tty` + @ $(EAP_INSTALL) \ + | grep -v '^to stop your application type' \ + | grep -v '^ eap-install.sh stop' ## Stop app on using password and assuming architecture stop: - @ $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) stop" + @ $(EAP_INSTALL) ## Build and run app directly on assuming architecture ## -## Forwards the following environment variables to the remote process: +## Prerequisites: ## -## * `RUST_LOG` -## * `RUST_LOG_STYLE` +## * The app is installed on the device. +## * The app is stopped. +## * The device has SSH enabled the ssh user root configured. +## * The device is added to `knownhosts`. +run: + cargo-acap-sdk run \ + --docker-file $(CURDIR)/Dockerfile \ + --password $(PASS) \ + --target $(ARCH) \ + --address $(DEVICE_IP) \ + --package $(PACKAGE) + +## Build and execute unit tests on assuming architecture ## ## Prerequisites: ## ## * The app is installed on the device. ## * The app is stopped. ## * The device has SSH enabled the ssh user root configured. -run: target/$(ARCH)/$(PACKAGE)/$(PACKAGE) - scp $< root@$(DEVICE_IP):/usr/local/packages/$(PACKAGE)/$(PACKAGE) - ssh root@$(DEVICE_IP) \ - "cd /usr/local/packages/$(PACKAGE) && su - acap-$(PACKAGE) -s /bin/sh --preserve-environment -c '$(if $(RUST_LOG_STYLE),RUST_LOG_STYLE=$(RUST_LOG_STYLE) )$(if $(RUST_LOG),RUST_LOG=$(RUST_LOG) )./$(PACKAGE)'" +## * The device is added to `knownhosts`. +test: + cargo-acap-sdk test \ + --docker-file $(CURDIR)/Dockerfile \ + --password $(PASS) \ + --target $(ARCH) \ + --address $(DEVICE_IP) \ + --package $(PACKAGE) ## Checks ## ------ @@ -97,12 +107,14 @@ check_all: check_build check_docs check_format check_lint .PHONY: check_all ## Check that all crates can be built -check_build: target/aarch64/$(PACKAGE)/_envoy target/armv7hf/$(PACKAGE)/_envoy +check_build: + cargo-acap-sdk build + .PHONY: check_build ## Check that docs can be built check_docs: - RUSTDOCFLAGS="-Dwarnings" cross doc \ + cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile --docker-env RUSTFLAGS="-Dwarnings" -- cargo doc \ --document-private-items \ --no-deps \ --target aarch64-unknown-linux-gnu @@ -115,7 +127,7 @@ check_format: ## Check that the code is free of lints check_lint: - RUSTFLAGS="-Dwarnings" cross clippy \ + cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile --docker-env RUSTFLAGS="-Dwarnings" -- cargo clippy \ --all-targets \ --no-deps \ --target aarch64-unknown-linux-gnu @@ -137,36 +149,3 @@ fix_lint: ## Nouns ## ===== - -# Stage the files that will be packaged outside the source tree to avoid -# * cluttering the source tree and `.gitignore` with build artifacts, and -# * having the same file be built for different targets at different times. -# Use the `_envoy` file as a target because -# * `.DELETE_ON_ERROR` does not work for directories, and -# * the name of the `.eap` file is annoying to predict. -target/%/$(PACKAGE)/_envoy: ARCH=$* -target/%/$(PACKAGE)/_envoy: target/%/$(PACKAGE)/$(PACKAGE) target/%/$(PACKAGE)/manifest.json target/%/$(PACKAGE)/LICENSE - $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && acap-build --build no-build ." - touch $@ - -target/%/$(PACKAGE)/manifest.json: manifest.json - mkdir -p $(dir $@) - cp $< $@ - -target/%/$(PACKAGE)/LICENSE: LICENSE - mkdir -p $(dir $@) - cp $< $@ - -# The target triple and the name of the docker image do not match, so -# at some point we need to map one to the other. It might as well be here. -target/aarch64/$(PACKAGE)/$(PACKAGE): target/aarch64-unknown-linux-gnu/release/$(PACKAGE) - mkdir -p $(dir $@) - cp $< $@ - -target/armv7hf/$(PACKAGE)/$(PACKAGE): target/thumbv7neon-unknown-linux-gnueabihf/release/$(PACKAGE) - mkdir -p $(dir $@) - cp $< $@ - -# Always rebuild the executable because configuring accurate cache invalidation is annoying. -target/%/release/$(PACKAGE): FORCE - cross -v build --release --target $* --package $(PACKAGE) diff --git a/README.md b/README.md index 48284e9..ea24de9 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Ensure global prerequisites are installed: * Docker * Rust e.g. [using rustup](https://www.rust-lang.org/tools/install) -* Cross e.g. like `cargo install cross` +* `cargo-acap-sdk` like `cargo install --git https://github.com/AxisCommunications/acap-rs.git --rev 452583a5898e233ec3e2a391923b8971fe7f342b cargo-acap-sdk` Build the app and create `.eap` files in the `target/acap/` directory like: @@ -34,6 +34,7 @@ Verbs: start: Start app on using password and assuming architecture stop: Stop app on using password and assuming architecture run: Build and run app directly on assuming architecture + test: Build and execute unit tests on assuming architecture Checks: check_all: Run all other checks @@ -47,6 +48,34 @@ Fixes: fix_lint: Attempt to fix lints automatically ``` +Yet more useful workflows can be listed like + +```console +$ cargo-acap-sdk help +ACAP analog to `cargo` for building and deploying apps + +Usage: cargo-acap-sdk + +Commands: + build Build app(s) + run Build executable for app(s) and run on the device, impersonating a user or the app + test Build test(s) and run on the device, impersonating a user or the app + install Build app(s) and install on the device + start TODO: Implement; Start app(s) on the device + stop TODO: Implement; Stop app(s) on the device + uninstall TODO: Implement; Uninstall app(s) on the device + containerize Run the provided program in a container + completions Print shell completion script for this program + help Print this message or the help of the given subcommand(s) + +Options: + -h, --help Print help + -V, --version Print version +``` + +Note that the shell completions may not work when using the program as a cargo plugin like +`cargo acap-sdk` (note the difference between ` ` and `-`). + ## License [MIT](LICENSE) diff --git a/docker/install_rust.sh b/docker/install_rust.sh new file mode 100755 index 0000000..811be19 --- /dev/null +++ b/docker/install_rust.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh +set -eux +wget "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" +echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c - +chmod +x rustup-init + +./rustup-init \ + --default-host x86_64-unknown-linux-gnu \ + --default-toolchain $(grep "channel" rust-toolchain.toml | cut -d '"' -f 2) \ + --no-modify-path \ + --profile minimal \ + -y + +rm rustup-init +chmod -R a+w $RUSTUP_HOME $CARGO_HOME diff --git a/src/main.rs b/src/main.rs index 4011eec..19bb736 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,3 +10,17 @@ fn main() { app_logging::init_logger(); info!("Hello World!"); } + +#[cfg(test)] +mod tests { + #[test] + fn tautology() { + assert!(true) + } + + #[test] + #[ignore] + fn contradiction() { + assert!(true) + } +} From ac239159adf5d4e468871c773df4b1621b48b890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Nystr=C3=B6m?= Date: Wed, 19 Jun 2024 17:18:05 +0200 Subject: [PATCH 2/4] Add devcontainer configuration (#15) * Remove wget dependency Since curl is already installed, wget is unnecessary. * Use regular (non-slim) debian as base, to include man pages, etc. * Install cargo-acap-sdk in Dockerfile * Use --no-docker with cargo-acap-sdk * Merge install_rust.sh into Dockerfile, skip adding unnecessary write permissions * Add devcontainer.json, move Dockerfile into .devcontainer * Install rust-analyzer extension in vscode devcontainers * Add devcontainers configuration to dependabot.yml * Add GitHub CLI as a devcontainer feature --- Dockerfile => .devcontainer/Dockerfile | 21 ++++++++---- .devcontainer/devcontainer.json | 46 ++++++++++++++++++++++++++ .devcontainer/gh/.gitignore | 2 ++ .github/dependabot.yml | 7 ++++ Makefile | 15 ++++----- docker/install_rust.sh | 15 --------- 6 files changed, 77 insertions(+), 29 deletions(-) rename Dockerfile => .devcontainer/Dockerfile (79%) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/gh/.gitignore delete mode 100755 docker/install_rust.sh diff --git a/Dockerfile b/.devcontainer/Dockerfile similarity index 79% rename from Dockerfile rename to .devcontainer/Dockerfile index 2a3071d..c31c039 100644 --- a/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,7 +2,7 @@ ARG REPO=axisecp ARG SDK=acap-native-sdk ARG UBUNTU_VERSION=22.04 ARG VERSION=1.14 -ARG BASE_IMAGE=debian:bookworm-20240423-slim +ARG BASE_IMAGE=debian:bookworm-20240423 FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 FROM ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf @@ -25,19 +25,28 @@ RUN apt-get update \ inetutils-ping \ pkg-config \ python3-jsonschema \ - wget \ && rm -rf /var/lib/apt/lists/* ENV RUSTUP_HOME=/usr/local/rustup \ CARGO_HOME=/usr/local/cargo \ PATH=/usr/local/cargo/bin:$PATH -COPY docker/install_rust.sh rust-toolchain.toml ./ -RUN ./install_rust.sh \ - && rustup target add \ +COPY rust-toolchain.toml ./ +RUN curl -O "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" \ + && echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c - \ + && chmod +x rustup-init \ + && ./rustup-init \ + --default-host x86_64-unknown-linux-gnu \ + --default-toolchain $(grep "channel" rust-toolchain.toml | cut -d '"' -f 2) \ + --no-modify-path \ + --profile minimal \ + -y \ + && rm rustup-init \ + && rustup target add \ aarch64-unknown-linux-gnu \ thumbv7neon-unknown-linux-gnueabihf \ - && rm install_rust.sh rust-toolchain.toml + && rm rust-toolchain.toml \ + && cargo install --git https://github.com/AxisCommunications/acap-rs.git --rev 452583a5898e233ec3e2a391923b8971fe7f342b cargo-acap-sdk ENV \ SYSROOT_AARCH64=/opt/axis/acapsdk/sysroots/aarch64 \ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..3f4b2aa --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,46 @@ +// For format details, see https://aka.ms/devcontainer.json. +{ + "name": "rust-acap-sdk", + + // More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "./Dockerfile", + "context": "..", + "args": { + "http_proxy": "${localEnv:http_proxy}", + "https_proxy": "${localEnv:https_proxy}", + "no_proxy": "${localEnv:no_proxy}" + } + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + "features": { + "ghcr.io/devcontainers/features/common-utils:2": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + + // More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "${localEnv:USER}", + + // More info: https://containers.dev/implementors/spec/#environment-variables + "containerEnv": { + "http_proxy": "${localEnv:http_proxy}", + "https_proxy": "${localEnv:https_proxy}", + "no_proxy": "${localEnv:no_proxy}" + }, + + // Configure tool-specific properties. + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": ["rust-lang.rust-analyzer"] + } + }, + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": { + "symlinkGhCli": "ln -s ${containerWorkspaceFolder}/.devcontainer/gh $HOME/.config/gh", + "fixCargoPermissions": "sudo chown -R $(id -u):$(id -g) \"$CARGO_HOME\"" + } +} diff --git a/.devcontainer/gh/.gitignore b/.devcontainer/gh/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/.devcontainer/gh/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c107b74..f706774 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,7 @@ updates: directory: "/" schedule: interval: "weekly" + - package-ecosystem: "cargo" directory: "/" schedule: @@ -18,3 +19,9 @@ updates: - "minor" - "patch" versioning-strategy: lockfile-only + + # Update dependencies under the "features" key in devcontainer.json. + - package-ecosystem: "devcontainers" + directory: "/" + schedule: + interval: "weekly" diff --git a/Makefile b/Makefile index 3765b1e..8bf0d28 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,7 @@ PASS ?= pass .SUFFIXES: ; EAP_INSTALL = cd ${CURDIR}/target/$(ARCH)/$(PACKAGE)/ \ -&& cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile -- \ -sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) $@" +&& sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) $@" ## Verbs @@ -44,11 +43,11 @@ sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $( ## Build app for all architectures build: - cargo-acap-sdk build + cargo-acap-sdk build --no-docker ## Install app on using password and assuming architecture install: - cargo-acap-sdk install --docker-file ${CURDIR}/Dockerfile --address $(DEVICE_IP) --password $(PASS) --target $(ARCH) \ + cargo-acap-sdk install --no-docker --address $(DEVICE_IP) --password $(PASS) --target $(ARCH) \ | grep -v '^to start your application type$$' \ | grep -v '^ eap-install.sh start$$' @@ -77,7 +76,7 @@ stop: ## * The device is added to `knownhosts`. run: cargo-acap-sdk run \ - --docker-file $(CURDIR)/Dockerfile \ + --no-docker \ --password $(PASS) \ --target $(ARCH) \ --address $(DEVICE_IP) \ @@ -93,7 +92,7 @@ run: ## * The device is added to `knownhosts`. test: cargo-acap-sdk test \ - --docker-file $(CURDIR)/Dockerfile \ + --no-docker \ --password $(PASS) \ --target $(ARCH) \ --address $(DEVICE_IP) \ @@ -114,7 +113,7 @@ check_build: ## Check that docs can be built check_docs: - cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile --docker-env RUSTFLAGS="-Dwarnings" -- cargo doc \ + RUSTFLAGS="-Dwarnings" cargo doc \ --document-private-items \ --no-deps \ --target aarch64-unknown-linux-gnu @@ -127,7 +126,7 @@ check_format: ## Check that the code is free of lints check_lint: - cargo-acap-sdk containerize --docker-file $(CURDIR)/Dockerfile --docker-env RUSTFLAGS="-Dwarnings" -- cargo clippy \ + RUSTFLAGS="-Dwarnings" cargo clippy \ --all-targets \ --no-deps \ --target aarch64-unknown-linux-gnu diff --git a/docker/install_rust.sh b/docker/install_rust.sh deleted file mode 100755 index 811be19..0000000 --- a/docker/install_rust.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env sh -set -eux -wget "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" -echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c - -chmod +x rustup-init - -./rustup-init \ - --default-host x86_64-unknown-linux-gnu \ - --default-toolchain $(grep "channel" rust-toolchain.toml | cut -d '"' -f 2) \ - --no-modify-path \ - --profile minimal \ - -y - -rm rustup-init -chmod -R a+w $RUSTUP_HOME $CARGO_HOME From 848eb1b1614c34e612fec8f091fe14409e733cb9 Mon Sep 17 00:00:00 2001 From: Anders-Petter Ljungquist Date: Wed, 14 Aug 2024 11:12:10 +0200 Subject: [PATCH 3/4] s: mirror recent changes in acap-rs --- .devcontainer/Dockerfile | 74 +++++++++++------- .devcontainer/devcontainer-lock.json | 6 +- .devcontainer/devcontainer.json | 9 +-- .devcontainer/gh/.gitignore | 2 - .github/dependabot.yml | 3 - .github/workflows/CI.yml | 11 +-- Dockerfile | 58 -------------- Makefile | 95 +++++++++++++---------- README.md | 108 ++++++++++++++++----------- rust-toolchain.toml | 6 +- src/main.rs | 24 +++--- 11 files changed, 195 insertions(+), 201 deletions(-) delete mode 100644 .devcontainer/gh/.gitignore delete mode 100644 Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c31c039..2a36fc7 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,12 +1,12 @@ ARG REPO=axisecp ARG SDK=acap-native-sdk ARG UBUNTU_VERSION=22.04 -ARG VERSION=1.14 +ARG VERSION=1.15 ARG BASE_IMAGE=debian:bookworm-20240423 -FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 -FROM ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf -FROM ${BASE_IMAGE} +FROM --platform=linux/amd64 ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 +FROM --platform=linux/amd64 ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf +FROM --platform=linux/amd64 ${BASE_IMAGE} COPY --from=sdk-aarch64 /opt/axis/acapsdk/axis-acap-manifest-tools /opt/axis/acapsdk/axis-acap-manifest-tools COPY --from=sdk-aarch64 /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux @@ -16,37 +16,49 @@ COPY --from=sdk-armv7hf /opt/axis/acapsdk/sysroots/armv7hf /opt/axis/acapsdk/sys COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux RUN apt-get update \ - && apt-get install -y \ + && apt-get install \ + --assume-yes \ + --no-install-recommends \ build-essential \ + ca-certificates \ clang \ curl \ g++-aarch64-linux-gnu \ g++-arm-linux-gnueabihf \ - inetutils-ping \ + git \ + iputils-ping \ + libglib2.0-dev \ + libssl-dev \ pkg-config \ python3-jsonschema \ - && rm -rf /var/lib/apt/lists/* + sshpass -ENV RUSTUP_HOME=/usr/local/rustup \ +ENV PATH=/usr/local/cargo/bin:$PATH \ CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH + RUSTUP_HOME=/usr/local/rustup COPY rust-toolchain.toml ./ -RUN curl -O "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" \ - && echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c - \ - && chmod +x rustup-init \ - && ./rustup-init \ - --default-host x86_64-unknown-linux-gnu \ - --default-toolchain $(grep "channel" rust-toolchain.toml | cut -d '"' -f 2) \ - --no-modify-path \ - --profile minimal \ - -y \ - && rm rustup-init \ - && rustup target add \ - aarch64-unknown-linux-gnu \ - thumbv7neon-unknown-linux-gnueabihf \ - && rm rust-toolchain.toml \ - && cargo install --git https://github.com/AxisCommunications/acap-rs.git --rev 452583a5898e233ec3e2a391923b8971fe7f342b cargo-acap-sdk +RUN curl \ + --output /tmp/rustup-init \ + "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" \ + && echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db /tmp/rustup-init" \ + | sha256sum -c - \ + && chmod +x /tmp/rustup-init \ + && ./tmp/rustup-init \ + --no-modify-path \ + --no-update-default-toolchain \ + -y \ + && rm /tmp/rustup-init \ + && rustup show \ + && cargo install \ + --locked \ + --git https://github.com/AxisCommunications/acap-rs.git \ + --rev 5148b09e77e321a215a18f2f4ab75ec64839265c \ + acap-ssh-utils \ + cargo-acap-build \ + cargo-acap-sdk \ + device-manager \ + && rm rust-toolchain.toml ENV \ SYSROOT_AARCH64=/opt/axis/acapsdk/sysroots/aarch64 \ @@ -55,8 +67,8 @@ ENV \ ENV \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="aarch64-linux-gnu-gcc" \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_AARCH64}" \ - CC_aarch64_axis_linux_gnu="aarch64-linux-gnu-gcc" \ - CXX_aarch64_axis_linux_gnu="aarch64-linux-gnu-g++" \ + CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc" \ + CXX_aarch64_unknown_linux_gnu="aarch64-linux-gnu-g++" \ PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ PKG_CONFIG_PATH_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}" \ @@ -67,3 +79,13 @@ ENV \ PKG_CONFIG_LIBDIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ PKG_CONFIG_PATH_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ PKG_CONFIG_SYSROOT_DIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}" + +# If neither `CARGO_HOME` nor `HOME` is set when launching a container, then cargo will try to +# download crates to this directory. If launched with the `--user` option then this will fail. +# TODO: Replace the example in the README with something that does not mount any volumes. +RUN mkdir /.cargo \ + && chmod a+w /.cargo/ + +# TODO: Consider removing the content of `CARGO_HOME` instead of `chmod`ing it; +RUN find $CARGO_HOME $RUSTUP_HOME -type d -exec chmod a+rwx {} + +RUN find $CARGO_HOME $RUSTUP_HOME -type f -exec chmod a+rw {} + diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json index a4f8dd0..c6f1c23 100644 --- a/.devcontainer/devcontainer-lock.json +++ b/.devcontainer/devcontainer-lock.json @@ -1,9 +1,9 @@ { "features": { "ghcr.io/devcontainers/features/common-utils:2": { - "version": "2.4.4", - "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:85c6505e809cc7c400b21997d7ae6f50811720d591813243f14d98cf2c577041", - "integrity": "sha256:85c6505e809cc7c400b21997d7ae6f50811720d591813243f14d98cf2c577041" + "version": "2.4.5", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:e232c240319c4e019467c1099536c5eefebd762cf017d6d50353ed50fbf66ba3", + "integrity": "sha256:e232c240319c4e019467c1099536c5eefebd762cf017d6d50353ed50fbf66ba3" } } } \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c010780..e9be9e6 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,14 +1,11 @@ { "name": "acap-rs-app-template", "build": { - "dockerfile": "../Dockerfile", + "dockerfile": "Dockerfile", "context": ".." }, "features": { - "ghcr.io/devcontainers/features/common-utils:2": {}, + "ghcr.io/devcontainers/features/common-utils:2": {} }, - "remoteUser": "${localEnv:USER}", - "containerEnv": { - "CARGO_HOME": "/home/${localEnv:USER}/.cargo" - } + "remoteUser": "${localEnv:USER}" } diff --git a/.devcontainer/gh/.gitignore b/.devcontainer/gh/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/.devcontainer/gh/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f706774..d26b2ab 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,7 +7,6 @@ updates: directory: "/" schedule: interval: "weekly" - - package-ecosystem: "cargo" directory: "/" schedule: @@ -19,8 +18,6 @@ updates: - "minor" - "patch" versioning-strategy: lockfile-only - - # Update dependencies under the "features" key in devcontainer.json. - package-ecosystem: "devcontainers" directory: "/" schedule: diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7b3c140..d3ffc3b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -11,9 +11,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Install dependencies - run: cargo install --locked cross@0.2.5 - - name: Run checks + - name: Install dev container dependencies + run: npm install -g @devcontainers/cli@0.65.0 + - name: Run checks in dev container run: | - make --always-make check_all - make build + devcontainer up --workspace-folder . + devcontainer exec --workspace-folder . make --always-make check_all + devcontainer exec --workspace-folder . make build diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d92b326..0000000 --- a/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -ARG REPO=axisecp -ARG SDK=acap-native-sdk -ARG UBUNTU_VERSION=22.04 -ARG VERSION=1.14 -ARG BASE_IMAGE=debian:bookworm-20240423 - -FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 -FROM ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf -FROM ${BASE_IMAGE} - -COPY --from=sdk-aarch64 /opt/axis/acapsdk/axis-acap-manifest-tools /opt/axis/acapsdk/axis-acap-manifest-tools -COPY --from=sdk-aarch64 /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux -COPY --from=sdk-armv7hf /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi -COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/aarch64 /opt/axis/acapsdk/sysroots/aarch64 -COPY --from=sdk-armv7hf /opt/axis/acapsdk/sysroots/armv7hf /opt/axis/acapsdk/sysroots/armv7hf -COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux - -RUN apt-get update \ - && apt-get install -y \ - build-essential \ - clang \ - g++-aarch64-linux-gnu \ - g++-arm-linux-gnueabihf \ - pkg-config \ - python3-jsonschema \ - wget \ - && rm -rf /var/lib/apt/lists/* - -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH - -COPY docker/install_rust.sh rust-toolchain.toml ./ -RUN ./install_rust.sh \ - && rustup target add \ - aarch64-unknown-linux-gnu \ - thumbv7neon-unknown-linux-gnueabihf \ - && rm install_rust.sh rust-toolchain.toml - -ENV \ - SYSROOT_AARCH64=/opt/axis/acapsdk/sysroots/aarch64 \ - SYSROOT_ARMV7HF=/opt/axis/acapsdk/sysroots/armv7hf -# The above makes the below easier to read -ENV \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="aarch64-linux-gnu-gcc" \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_AARCH64}" \ - CC_aarch64_axis_linux_gnu="aarch64-linux-gnu-gcc" \ - CXX_aarch64_axis_linux_gnu="aarch64-linux-gnu-g++" \ - PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ - PKG_CONFIG_PATH_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ - PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}" \ - CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER="arm-linux-gnueabihf-gcc" \ - CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_ARMV7HF}" \ - CC_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-gcc" \ - CXX_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-g++" \ - PKG_CONFIG_LIBDIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ - PKG_CONFIG_PATH_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ - PKG_CONFIG_SYSROOT_DIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}" diff --git a/Makefile b/Makefile index 8bf0d28..a59c28c 100644 --- a/Makefile +++ b/Makefile @@ -10,22 +10,25 @@ # Keep in sync with both # - `acapPackageConf.setup.appName` in `manifest.json` # - `package.name` in `Cargo.toml` -PACKAGE ?= hello_world +export AXIS_PACKAGE ?= hello_world # The architecture that will be assumed when interacting with the device. -ARCH ?= aarch64 +export AXIS_DEVICE_ARCH ?= aarch64 # The IP address of the device to interact with. -DEVICE_IP ?= 192.168.0.90 +export AXIS_DEVICE_IP ?= 192.168.0.90 + +# The username to use when interacting with the device. +export AXIS_DEVICE_USER ?= root # The password to use when interacting with the device. -PASS ?= pass +export AXIS_DEVICE_PASS ?= pass # Other # ----- # Have zero effect by default to prevent accidental changes. -.DEFAULT_GOAL := help +.DEFAULT_GOAL := none # Delete targets that fail to prevent subsequent attempts incorrectly assuming # the target is up to date. @@ -34,69 +37,79 @@ PASS ?= pass # Prevent pesky default rules from creating unexpected dependency graphs. .SUFFIXES: ; -EAP_INSTALL = cd ${CURDIR}/target/$(ARCH)/$(PACKAGE)/ \ -&& sh -c ". /opt/axis/acapsdk/environment-setup-* && eap-install.sh $(DEVICE_IP) $(PASS) $@" +# It doesn't matter which SDK is sourced for installing, but using a wildcard would fail since there are multiple in the container. +EAP_INSTALL = cd $(CURDIR)/target/$(AXIS_DEVICE_ARCH)/$(AXIS_PACKAGE)/ \ +&& . /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux && eap-install.sh $(AXIS_DEVICE_IP) $(AXIS_DEVICE_PASS) $@ ## Verbs ## ===== -## Build app for all architectures +none:; + +## Reset using password to a clean state suitable for development and testing. +reinit: + RUST_LOG=info device-manager reinit + +## Build app for build: - cargo-acap-sdk build --no-docker + cargo-acap-build --target $(AXIS_DEVICE_ARCH) -- -p $(AXIS_PACKAGE) -## Install app on using password and assuming architecture +## Install app on using password and assuming architecture install: - cargo-acap-sdk install --no-docker --address $(DEVICE_IP) --password $(PASS) --target $(ARCH) \ + @ $(EAP_INSTALL) \ | grep -v '^to start your application type$$' \ | grep -v '^ eap-install.sh start$$' -## Remove app from using password and assuming architecture +## Remove app from using password and assuming architecture remove: @ $(EAP_INSTALL) -## Start app on using password and assuming architecture +## Start app on using password and assuming architecture start: - @ # Don't match the line endings because docker replace LF with CR + LF when given `--tty` @ $(EAP_INSTALL) \ - | grep -v '^to stop your application type' \ - | grep -v '^ eap-install.sh stop' + | grep -v '^to stop your application type$$' \ + | grep -v '^ eap-install.sh stop$$' -## Stop app on using password and assuming architecture +## Stop app on using password and assuming architecture stop: @ $(EAP_INSTALL) -## Build and run app directly on assuming architecture +## Build and run app directly on assuming architecture ## ## Prerequisites: ## +## * app is recognized by `cargo-acap-build` as an ACAP app. ## * The app is installed on the device. ## * The app is stopped. ## * The device has SSH enabled the ssh user root configured. -## * The device is added to `knownhosts`. run: - cargo-acap-sdk run \ - --no-docker \ - --password $(PASS) \ - --target $(ARCH) \ - --address $(DEVICE_IP) \ - --package $(PACKAGE) - -## Build and execute unit tests on assuming architecture + cargo-acap-build --target $(AXIS_DEVICE_ARCH) -- -p $(AXIS_PACKAGE) + acap-ssh-utils patch target/$(AXIS_DEVICE_ARCH)/$(AXIS_PACKAGE)/*.eap + acap-ssh-utils run-app \ + --environment RUST_LOG=debug \ + --environment RUST_LOG_STYLE=always \ + $(AXIS_PACKAGE) + +## Build and execute unit tests for app on assuming architecture ## ## Prerequisites: ## +## * app is recognized by `cargo-acap-build` as an ACAP app. ## * The app is installed on the device. ## * The app is stopped. ## * The device has SSH enabled the ssh user root configured. -## * The device is added to `knownhosts`. test: - cargo-acap-sdk test \ - --no-docker \ - --password $(PASS) \ - --target $(ARCH) \ - --address $(DEVICE_IP) \ - --package $(PACKAGE) + # The `scp` command below needs the wildcard to match exactly one file. + rm -r target/$(AXIS_DEVICE_ARCH)/$(AXIS_PACKAGE)-*/$(AXIS_PACKAGE) ||: + cargo-acap-build --target $(AXIS_DEVICE_ARCH) -- -p $(AXIS_PACKAGE) --tests + acap-ssh-utils patch target/$(AXIS_DEVICE_ARCH)/$(AXIS_PACKAGE)-*/*.eap + acap-ssh-utils run-app \ + --environment RUST_LOG=debug \ + --environment RUST_LOG_STYLE=always \ + $(AXIS_PACKAGE) \ + -- \ + --test-threads=1 ## Checks ## ------ @@ -107,16 +120,16 @@ check_all: check_build check_docs check_format check_lint ## Check that all crates can be built check_build: - cargo-acap-sdk build - + cargo-acap-build --target aarch64 .PHONY: check_build ## Check that docs can be built check_docs: - RUSTFLAGS="-Dwarnings" cargo doc \ + RUSTDOCFLAGS="-Dwarnings" cargo doc \ --document-private-items \ --no-deps \ - --target aarch64-unknown-linux-gnu + --target aarch64-unknown-linux-gnu \ + --workspace .PHONY: check_docs ## Check that the code is formatted correctly @@ -126,10 +139,12 @@ check_format: ## Check that the code is free of lints check_lint: - RUSTFLAGS="-Dwarnings" cargo clippy \ + cargo clippy \ --all-targets \ --no-deps \ - --target aarch64-unknown-linux-gnu + --target aarch64-unknown-linux-gnu \ + -- \ + -Dwarnings .PHONY: check_lint ## Fixes diff --git a/README.md b/README.md index 9ffb35b..12f89bb 100644 --- a/README.md +++ b/README.md @@ -19,42 +19,20 @@ hello_world_1_0_0_aarch64.eap hello_world_1_0_0_armv7hf.eap ``` -If you prefer to not use dev containers, or the implementation in your favorite IDE is buggy, the app can be built using only `docker`: - -```sh -docker build --tag acap-rs-app-template . -docker run \ - --interactive \ - --rm \ - --tty \ - --user $(id -u):$(id -g) \ - --volume $(pwd):$(pwd) \ - --workdir $(pwd) \ - acap-rs-app-template \ - make build -``` - -## Advanced setup - -Ensure global prerequisites are installed: - -* Docker -* Rust e.g. [using rustup](https://www.rust-lang.org/tools/install) -* Cross e.g. like `cargo install --locked cross@0.2.5` - Useful workflows are documented under the "Verbs" section of the [Makefile](./Makefile). If Python package `mkhelp==0.2.1` is installed, they can be summarized like: ```console $ mkhelp print-docs Makefile help Verbs: - build: Build app for all architectures - install: Install app on using password and assuming architecture - remove: Remove app from using password and assuming architecture - start: Start app on using password and assuming architecture - stop: Stop app on using password and assuming architecture - run: Build and run app directly on assuming architecture - test: Build and execute unit tests on assuming architecture + reinit: Reset using password to a clean state suitable for development and testing. + build: Build app for + install: Install app on using password and assuming architecture + remove: Remove app from using password and assuming architecture + start: Start app on using password and assuming architecture + stop: Stop app on using password and assuming architecture + run: Build and run app directly on assuming architecture + test: Build and execute unit tests for app on assuming architecture Checks: check_all: Run all other checks @@ -68,29 +46,69 @@ Fixes: fix_lint: Attempt to fix lints automatically ``` -Yet more useful workflows can be listed like +The commands used by the workflows can be listed in the individual programs: + +```console +$ acap-ssh-utils +Utilities for interacting with Axis devices over SSH. + +Usage: acap-ssh-utils --host --user --pass + +Commands: + patch Patch app on device + run-app Run app on device, sending output to the terminal + run-other Run any executable on device, sending output to the terminal + help Print this message or the help of the given subcommand(s) + +Options: + --host Hostname or IP address of the device [env: AXIS_DEVICE_IP=] + -u, --user The username to use for the ssh connection [env: AXIS_DEVICE_USER=] + -p, --pass The password to use for the ssh connection [env: AXIS_DEVICE_PASS=] +``` ```console -$ cargo-acap-sdk help -ACAP analog to `cargo` for building and deploying apps +$ cargo-acap-sdk +Tools for developing ACAP apps using Rust Usage: cargo-acap-sdk Commands: - build Build app(s) - run Build executable for app(s) and run on the device, impersonating a user or the app - test Build test(s) and run on the device, impersonating a user or the app - install Build app(s) and install on the device - start TODO: Implement; Start app(s) on the device - stop TODO: Implement; Stop app(s) on the device - uninstall TODO: Implement; Uninstall app(s) on the device - containerize Run the provided program in a container - completions Print shell completion script for this program - help Print this message or the help of the given subcommand(s) + build Build app(s) with release profile + run Build app(s) and run on the device + test Build app(s) in test mode and run on the device + install Build app(s) with release profile and install on the device + completions Print shell completion script for this program + help Print this message or the help of the given subcommand(s) +``` + +```console +$ cargo-acap-build -h +ACAP analog to `cargo build` + +Usage: cargo-acap-build [OPTIONS] [ARGS]... + +Arguments: + [ARGS]... Pass additional arguments to `cargo build` + +Options: + --target If given, build only for the given architecture(s) [possible values: aarch64, armv7hf] +``` + +```console +$ device-manager +Utilities for managing individual devices. + +Usage: device-manager --host --user --pass + +Commands: + restore Restore device to a clean state + reinit Restore and initialize device to a known, useful state + help Print this message or the help of the given subcommand(s) Options: - -h, --help Print help - -V, --version Print version + --host Hostname or IP address of the device [env: AXIS_DEVICE_IP=] + -u, --user The username to use for the ssh connection [env: AXIS_DEVICE_USER=] + -p, --pass The password to use for the ssh connection [env: AXIS_DEVICE_PASS=] ``` Note that the shell completions may not work when using the program as a cargo plugin like diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 16895c7..812c49a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,7 @@ [toolchain] -channel = "1.75.0" +channel = "1.77.0" components = ["cargo", "clippy", "rustfmt"] +targets = [ + "aarch64-unknown-linux-gnu", + "thumbv7neon-unknown-linux-gnueabihf", +] diff --git a/src/main.rs b/src/main.rs index e42263d..a3df1aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,26 +1,26 @@ //! A simple hello world application //! -//! Uses some common app-logging crates to demonstrate -//! 1. how to use them in an application, and -//! 2. how to build and bundle them as an application. +//! This app demonstrates: +//! - The effect of printing to stdout and stderr. +//! - How to configure logging and the effect of logging at various levels. -use log::info; +use log::{debug, error, info, trace, warn}; fn main() { + eprintln!("Hello stderr!"); + println!("Hello stdout!"); acap_logging::init_logger(); - info!("Hello World!"); + trace!("Hello trace!"); + debug!("Hello debug!"); + info!("Hello info!"); + warn!("Hello warn!"); + error!("Hello error!"); } #[cfg(test)] mod tests { #[test] fn tautology() { - assert!(true) - } - - #[test] - #[ignore] - fn contradiction() { - assert!(true) + println!("This will always pass") } } From ffe349cef28da833dc0ca35bc559aa6d23b5409e Mon Sep 17 00:00:00 2001 From: Anders-Petter Ljungquist Date: Wed, 14 Aug 2024 14:28:03 +0200 Subject: [PATCH 4/4] s: Document decisions In general files have been copied or updated from acap-rs commit 5148b09e77e321a215a18f2f4ab75ec64839265c; if a decision is not explained here it may be explained in the history of acap-rs. `.devcontainer/Dockerfile`: - Inline shell scripts because when copied from a windows host they sometimes fail depending on how git is configured to handle line endings. - Install development tools from acap-rs earlier because we can and when `rust-toolchain.toml` has been removed cargo complains that no version is selected. `.github/workflows/CI.yml`: - Run tests using devcontainer to make sure that the recommended workflow is working. `Makefile`: - Replace default goal since the `help` goal does not exist and as long as `mkhelp` is a python package I don't intend to add it back. - Skip the bulk operations because this template is set up for developing a single app/package. `README.md`: - Remove documentation of development environments other than the dev container because the template is meant to get started quickly and committed or experienced users should be able to set up their own project with this template and acap-rs as inspiration. These environment setups are documented in acap-rs anyway. At some point running `cargo-acap-sdk` on host may become supported, but not before containerized builds a `cargo-acap` and `cross` is added to it. - Add help outputs from various tools to give users a preview of what to expect if they do use the template and to spread awareness of these tools. - Remove the troubleshooting section since this problem should not happen now that shell scripts have been inlined in the `Dockerfile`. `src/main.rs`: - Add a simple test so that `make test` does something interesting out of the box.