no more Docker!

* use `termion` rather than `ncurses` to limit runtime deps
* cross-compile with `cross` instead of our own dockerfiles/scripts
* update instructions
* update release procedure and GitHub actions to match
* prep changelog for `v0.7.8`

Fixes #160
Closes #265
This commit is contained in:
Scott Lamb 2023-10-14 15:52:06 -07:00
parent faf0201b52
commit ee98bf5236
23 changed files with 364 additions and 890 deletions

View File

@ -24,8 +24,7 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Server (please complete the following information):** **Server (please complete the following information):**
- If using Docker: `docker ps` + `docker images` - `moonfire-nvr --version`
- If building from git: `moonfire-nvr --version`
- Attach a [log file](https://github.com/scottlamb/moonfire-nvr/blob/master/guide/troubleshooting.md#viewing-moonfire-nvrs-logs). Run with the `RUST_BACKTRACE=1` environment variable set if possible. - Attach a [log file](https://github.com/scottlamb/moonfire-nvr/blob/master/guide/troubleshooting.md#viewing-moonfire-nvrs-logs). Run with the `RUST_BACKTRACE=1` environment variable set if possible.
**Camera (please complete the following information):** **Camera (please complete the following information):**

View File

@ -1,6 +1,10 @@
name: CI name: CI
on: [push, pull_request] on: [push, pull_request]
defaults:
run:
shell: bash
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
MOONFIRE_COLOR: always MOONFIRE_COLOR: always
@ -37,11 +41,7 @@ jobs:
restore-keys: | restore-keys: |
cargo-${{ matrix.rust }}- cargo-${{ matrix.rust }}-
cargo- cargo-
- name: Install dependencies - uses: actions/setup-node@v3
# The retry here is to work around "Unable to connect to azure.archive.ubuntu.com" errors.
# https://github.com/actions/runner-images/issues/6894
run: sudo apt-get --option=APT::Acquire::Retries=3 update && sudo apt-get --option=APT::Acquire::Retries=3 install libncurses-dev libsqlite3-dev pkgconf
- uses: actions/setup-node@v2
with: with:
node-version: 18 node-version: 18
- name: Install Rust - name: Install Rust
@ -51,13 +51,10 @@ jobs:
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
override: true override: true
components: ${{ matrix.extra_components }} components: ${{ matrix.extra_components }}
- run: cd ui && npm ci
- run: cd ui && npm run build
- name: Test - name: Test
run: | run: |
cd server cd server
cargo test ${{ matrix.extra_args }} --all cargo test --features=rusqlite/bundled ${{ matrix.extra_args }} --all
cargo test --features=bundled-ui ${{ matrix.extra_args }} --all
continue-on-error: ${{ matrix.rust == 'nightly' }} continue-on-error: ${{ matrix.rust == 'nightly' }}
- name: Check formatting - name: Check formatting
if: matrix.rust == 'stable' if: matrix.rust == 'stable'
@ -70,7 +67,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v2 - uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node }} node-version: ${{ matrix.node }}
- run: cd ui && npm ci - run: cd ui && npm ci
@ -83,5 +80,5 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v4
- run: find . -type f -print0 | xargs -0 .github/workflows/check-license.py - run: find . -type f -print0 | xargs -0 .github/workflows/check-license.py

View File

@ -1,19 +1,109 @@
name: Release name: Release
defaults:
run:
shell: bash
on: on:
push: push:
tags: tags:
- v[0-9]+.* - v[0-9]+.*
jobs: jobs:
create-release: base:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - name: Checkout
- uses: taiki-e/create-gh-release-action@v1 uses: actions/checkout@v4
- uses: taiki-e/install-action@v2
with: with:
# (Optional) Path to changelog. tool: parse-changelog
changelog: CHANGELOG.md - name: Generate changelog
run: |
VERSION_MINUS_V=${GITHUB_REF_NAME/#v/}
parse-changelog CHANGELOG.md $VERSION_MINUS_V > CHANGELOG-$GITHUB_REF_NAME.md
- uses: actions/setup-node@v3
with:
node-version: 18
- run: cd ui && npm ci
- run: cd ui && npm run build
- run: cd ui && npm run test
# Upload the UI and changelog as *job* artifacts (not *release* artifacts), used below.
- uses: actions/upload-artifact@v3
with:
name: moonfire-nvr-ui-${{ github.ref_name }}
path: ui/build
if-no-files-found: error
- uses: actions/upload-artifact@v3
with:
name: CHANGELOG-${{ github.ref_name }}
path: CHANGELOG-${{ github.ref_name }}.md
if-no-files-found: error
cross:
needs: base # for bundled ui
strategy:
matrix:
include:
- target: x86_64-unknown-linux-musl
- target: aarch64-unknown-linux-musl
- target: armv7-unknown-linux-musleabihf
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download UI
uses: actions/download-artifact@v3
with:
name: moonfire-nvr-ui-${{ github.ref_name }}
path: ui/build
# actions-rust-cross doesn't actually use cross for x86_64.
# Install the needed musl-tools in the host.
- name: Install musl-tools
run: sudo apt-get --option=APT::Acquire::Retries=3 update && sudo apt-get --option=APT::Acquire::Retries=3 install musl-tools
if: matrix.target == 'x86_64-unknown-linux-musl'
- name: Build
uses: houseabsolute/actions-rust-cross@v0
env: env:
# (Required) GitHub token for creating GitHub Releases. UI_BUILD_DIR: ../ui/build
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# cross doesn't install `git` within its Docker container, so plumb
# the version through rather than try `git describe` from `build.rs`.
VERSION: ${{ github.ref_name }}
with:
working-directory: server
target: ${{ matrix.target }}
command: build
args: --release --features bundled
# Upload as a *job* artifact (not *release* artifact), used below.
- name: Upload
uses: actions/upload-artifact@v3
with:
name: moonfire-nvr-${{ github.ref_name }}-${{ matrix.target }}
path: server/target/${{ matrix.target }}/release/moonfire-nvr
if-no-files-found: error
release:
needs: [ base, cross ]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v3
with:
path: artifacts
- name: ls before rearranging
run: find . -ls
- name: Rearrange
run: |
(cd artifacts/moonfire-nvr-ui-${GITHUB_REF_NAME} && zip -r ../../moonfire-nvr-ui-${GITHUB_REF_NAME}.zip .)
(cd artifacts; for i in moonfire-nvr-*/moonfire-nvr; do mv $i "../$(dirname $i)"; done)
- name: ls after rearranging
run: find . -ls
- name: Create GitHub release
uses: softprops/action-gh-release@v1
with:
body_path: artifacts/CHANGELOG-${{ github.ref_name }}/CHANGELOG-${{ github.ref_name }}.md
files: |
moonfire-nvr-*

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.DS_Store .DS_Store
*.swp *.swp
/release-*
/server/target /server/target
.idea .idea

View File

@ -1,17 +1,22 @@
# Moonfire NVR change log # Moonfire NVR change log
Below are some highlights in each release. For a full description of all Below are some highlights in each release. For a full description of all
changes, see Git history. changes, see Git history. Each release is tagged in git.
Each release is tagged in Git and on the Docker repository
[`scottlamb/moonfire-nvr`](https://hub.docker.com/r/scottlamb/moonfire-nvr).
Backwards-incompatible database schema changes happen on on major version Backwards-incompatible database schema changes happen on on major version
upgrades, e.g. `0.6.x` -> `0.7.x`. The config file format and upgrades, e.g. `v0.6.x` -> `v0.7.x`. The config file format and
[API](ref/api.md) currently have no stability guarantees, so they may change [API](ref/api.md) currently have no stability guarantees, so they may change
even on minor releases, e.g. `0.7.5` -> `0.7.6`. even on minor releases, e.g. `v0.7.5` -> `v0.7.6`.
## 0.7.7 (2023-08-03) ## v0.7.8 (2023-10-18)
* release as self-contained Linux binaries (for `x86_64`, `aarch64`, and
`armv8` architectures) rather than Docker images. This minimizes hassle and
total download size. Along the way, we switched libc to from `glibc` to
`musl` in the process. Please report any problems with the build or
instructions!
## v0.7.7 (2023-08-03)
* fix [#289](https://github.com/scottlamb/moonfire-nvr/issues/289): crash on * fix [#289](https://github.com/scottlamb/moonfire-nvr/issues/289): crash on
pressing the `Add` button in the sample file directory dialog pressing the `Add` button in the sample file directory dialog
@ -19,7 +24,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* experimental (off by default) support for bundling UI files into the * experimental (off by default) support for bundling UI files into the
executable. executable.
## 0.7.6 (2023-07-08) ## v0.7.6 (2023-07-08)
* new log formats using `tracing`. This will allow richer context information. * new log formats using `tracing`. This will allow richer context information.
* bump minimum Rust version to 1.70. * bump minimum Rust version to 1.70.
@ -53,7 +58,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* improvements to `moonfire-nvr config`, * improvements to `moonfire-nvr config`,
thanks to [@sky1e](https://github.com/sky1e). thanks to [@sky1e](https://github.com/sky1e).
## 0.7.5 (2022-05-09) ## v0.7.5 (2022-05-09)
* [#219](https://github.com/scottlamb/moonfire-nvr/issues/219): fix * [#219](https://github.com/scottlamb/moonfire-nvr/issues/219): fix
live stream failing with `ws close: 1006` on URLs with port numbers. live stream failing with `ws close: 1006` on URLs with port numbers.
@ -63,7 +68,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
Retina 0.3.10, improving compatibility with OMNY M5S2A 2812 cameras that Retina 0.3.10, improving compatibility with OMNY M5S2A 2812 cameras that
send invalid `rtptime` values. send invalid `rtptime` values.
## 0.7.4 (2022-04-13) ## v0.7.4 (2022-04-13)
* upgrade to Retina 0.3.9, improving camera interop and diagnostics. * upgrade to Retina 0.3.9, improving camera interop and diagnostics.
Fixes [#213](https://github.com/scottlamb/moonfire-nvr/issues/213), Fixes [#213](https://github.com/scottlamb/moonfire-nvr/issues/213),
@ -74,13 +79,13 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* [#206](https://github.com/scottlamb/moonfire-nvr/issues/206#issuecomment-1086442543): * [#206](https://github.com/scottlamb/moonfire-nvr/issues/206#issuecomment-1086442543):
fix `teardown Sender shouldn't be dropped: RecvError(())` errors on shutdown. fix `teardown Sender shouldn't be dropped: RecvError(())` errors on shutdown.
## 0.7.3 (2022-03-22) ## v0.7.3 (2022-03-22)
* security fix: check the `Origin` header on live stream WebSocket requests * security fix: check the `Origin` header on live stream WebSocket requests
to avoid cross-site WebSocket hijacking (CSWSH). to avoid cross-site WebSocket hijacking (CSWSH).
* RTSP connections always use the Retina library rather than FFmpeg. * RTSP connections always use the Retina library rather than FFmpeg.
## 0.7.2 (2022-03-16) ## v0.7.2 (2022-03-16)
* introduce a configuration file `/etc/moonfire-nvr.toml`; you will need * introduce a configuration file `/etc/moonfire-nvr.toml`; you will need
to create one when upgrading. to create one when upgrading.
@ -97,13 +102,13 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* progress on [#70](https://github.com/scottlamb/moonfire-nvr/issues/184): * progress on [#70](https://github.com/scottlamb/moonfire-nvr/issues/184):
shrink the binary from 154 MiB to 70 MiB by reducing debugging information. shrink the binary from 154 MiB to 70 MiB by reducing debugging information.
## 0.7.1 (2021-10-27) ## v0.7.1 (2021-10-27)
* bugfix: editing a camera from `nvr config` would erroneously clear the * bugfix: editing a camera from `nvr config` would erroneously clear the
sample file directory associated with its streams. sample file directory associated with its streams.
* RTSP transport (TCP or UDP) can be set per-stream from `nvr config`. * RTSP transport (TCP or UDP) can be set per-stream from `nvr config`.
## 0.7.0 (2021-10-27) ## v0.7.0 (2021-10-27)
* [schema version 7](guide/schema.md#version-7) * [schema version 7](guide/schema.md#version-7)
* Changes to the [API](guide/api.md): * Changes to the [API](guide/api.md):
@ -130,7 +135,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
currently may be either absent or the string `record`. currently may be either absent or the string `record`.
* Added `POST /api/users/<id>` for altering a user's UI preferences. * Added `POST /api/users/<id>` for altering a user's UI preferences.
## 0.6.7 (2021-10-20) ## v0.6.7 (2021-10-20)
* trim whitespace when detecting time zone by reading `/etc/timezone`. * trim whitespace when detecting time zone by reading `/etc/timezone`.
* (Retina 0.3.2) better `TEARDOWN` handling with the default * (Retina 0.3.2) better `TEARDOWN` handling with the default
@ -142,7 +147,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
`--rtsp-library=retina` (see `--rtsp-library=retina` (see
[scottlamb/retina#25](https://github.com/scottlamb/retina/25)). [scottlamb/retina#25](https://github.com/scottlamb/retina/25)).
## 0.6.6 (2021-09-23) ## v0.6.6 (2021-09-23)
* fix [#146](https://github.com/scottlamb/moonfire-nvr/issues/146): "init * fix [#146](https://github.com/scottlamb/moonfire-nvr/issues/146): "init
segment fetch error" when browsers have cached data from `v0.6.4` and segment fetch error" when browsers have cached data from `v0.6.4` and
@ -167,7 +172,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
impatient to get fast results with ctrl-C when running interactively, rather impatient to get fast results with ctrl-C when running interactively, rather
than having to use `SIGKILL` from another terminal. than having to use `SIGKILL` from another terminal.
## 0.6.5 (2021-08-13) ## v0.6.5 (2021-08-13)
* UI: improve video aspect ratio handling. Live streams formerly worked * UI: improve video aspect ratio handling. Live streams formerly worked
around a Firefox pixel aspect ratio bug by forcing all videos to 16:9, which around a Firefox pixel aspect ratio bug by forcing all videos to 16:9, which
@ -181,7 +186,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
`GET_PARAMETERS` as a RTSP keepalive. GW Security cameras would ignored `GET_PARAMETERS` as a RTSP keepalive. GW Security cameras would ignored
the latter, causing Moonfire NVR to drop the connection every minute. the latter, causing Moonfire NVR to drop the connection every minute.
## 0.6.4 (2021-06-28) ## v0.6.4 (2021-06-28)
* Default to a new pure-Rust RTSP library, `retina`. If you hit problems, you * Default to a new pure-Rust RTSP library, `retina`. If you hit problems, you
can switch back via `--rtsp-library=ffmpeg`. Please report a bug if this can switch back via `--rtsp-library=ffmpeg`. Please report a bug if this
@ -189,7 +194,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* Correct the pixel aspect ratio of 9:16 sub streams (eg a standard 16x9 * Correct the pixel aspect ratio of 9:16 sub streams (eg a standard 16x9
camera rotated 90 degrees) in the same way as 16:9 sub streams. camera rotated 90 degrees) in the same way as 16:9 sub streams.
## 0.6.3 (2021-03-31) ## v0.6.3 (2021-03-31)
* New user interface! Besides a more modern appearance, it has better * New user interface! Besides a more modern appearance, it has better
error handling and an experimental live view UI. error handling and an experimental live view UI.
@ -199,7 +204,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
not calculated properly there might be unexpected gaps or overlaps in not calculated properly there might be unexpected gaps or overlaps in
playback. playback.
## 0.6.2 (2021-03-12) ## v0.6.2 (2021-03-12)
* Fix panics when a stream's PTS has extreme jumps * Fix panics when a stream's PTS has extreme jumps
([#113](https://github.com/scottlamb/moonfire-nvr/issues/113)) ([#113](https://github.com/scottlamb/moonfire-nvr/issues/113))
@ -209,7 +214,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
`moonfire-nvr check --delete-orphan-rows` command from actually deleting `moonfire-nvr check --delete-orphan-rows` command from actually deleting
rows. rows.
## 0.6.1 (2021-02-16) ## v0.6.1 (2021-02-16)
* Improve the server's error messages on the console and in logs. * Improve the server's error messages on the console and in logs.
* Switch the UI build from the `yarn` package manager to `npm`. * Switch the UI build from the `yarn` package manager to `npm`.
@ -221,7 +226,7 @@ even on minor releases, e.g. `0.7.5` -> `0.7.6`.
* Fix mangled favicons * Fix mangled favicons
([#105](https://github.com/scottlamb/moonfire-nvr/issues/105)) ([#105](https://github.com/scottlamb/moonfire-nvr/issues/105))
## 0.6.0 (2021-01-22) ## v0.6.0 (2021-01-22)
This is the first tagged version and first Docker image release. I chose the This is the first tagged version and first Docker image release. I chose the
version number 0.6.0 to match the current schema version 6. version number 0.6.0 to match the current schema version 6.

View File

@ -1,75 +0,0 @@
# syntax=docker/dockerfile:1.2.1
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# See documentation here:
# https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md
# "dev-common" is the portion of "dev" (see below) which isn't specific to the
# target arch. It's sufficient for building the non-arch-specific webpack.
FROM --platform=$BUILDPLATFORM ubuntu:20.04 AS dev-common
LABEL maintainer="slamb@slamb.org"
ARG BUILD_UID=1000
ARG BUILD_GID=1000
ARG INVALIDATE_CACHE_DEV_COMMON=
ENV LC_ALL=C.UTF-8
COPY docker/dev-common.bash /
RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \
/dev-common.bash
CMD [ "/bin/bash", "--login" ]
# "dev" is a full development environment, suitable for shelling into or
# using with the VS Code container plugin.
FROM --platform=$BUILDPLATFORM dev-common AS dev
LABEL maintainer="slamb@slamb.org"
ARG BUILDARCH
ARG TARGETARCH
ARG INVALIDATE_CACHE_DEV=
COPY docker/dev.bash /
RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \
/dev.bash
USER moonfire-nvr:moonfire-nvr
WORKDIR /var/lib/moonfire-nvr
# Build the UI with node_modules and ui-dist outside the src dir.
FROM --platform=$BUILDPLATFORM dev-common AS build-ui
ARG INVALIDATE_CACHE_BUILD_UI=
LABEL maintainer="slamb@slamb.org"
WORKDIR /var/lib/moonfire-nvr/src/ui
COPY docker/build-ui.bash /
COPY ui /var/lib/moonfire-nvr/src/ui
RUN --mount=type=tmpfs,target=/var/lib/moonfire-nvr/src/ui/node_modules \
/build-ui.bash
# Build the Rust components. Note that dev.sh set up an environment variable
# in .buildrc that similarly changes the target dir path.
FROM --platform=$BUILDPLATFORM dev AS build-server
LABEL maintainer="slamb@slamb.org"
ARG INVALIDATE_CACHE_BUILD_SERVER=
COPY docker/build-server.bash /
COPY --from=build-ui /var/lib/moonfire-nvr/src/ui/build /var/lib/moonfire-nvr/src/ui/build
RUN --mount=type=cache,id=target,target=/var/lib/moonfire-nvr/target,sharing=locked,mode=777 \
--mount=type=cache,id=cargo,target=/cargo-cache,sharing=locked,mode=777 \
--mount=type=bind,source=server,target=/var/lib/moonfire-nvr/src/server,readonly \
/build-server.bash
# Deployment environment, now in the target platform.
FROM --platform=$TARGETPLATFORM ubuntu:20.04 AS deploy
LABEL maintainer="slamb@slamb.org"
ARG INVALIDATE_CACHE_BUILD_DEPLOY=
ENV LC_ALL=C.UTF-8
COPY docker/deploy.bash /
RUN --mount=type=cache,id=var-cache-apt,target=/var/cache/apt,sharing=locked \
/deploy.bash
COPY --from=dev-common /docker-build-debug/dev-common/ /docker-build-debug/dev-common/
COPY --from=dev /docker-build-debug/dev/ /docker-build-debug/dev/
COPY --from=build-server /docker-build-debug/build-server/ /docker-build-debug/build-server/
COPY --from=build-server /usr/local/bin/moonfire-nvr /usr/local/bin/moonfire-nvr
COPY --from=build-ui /docker-build-debug/build-ui /docker-build-debug/build-ui
# The install instructions say to use --user in the docker run commandline.
# Specify a non-root user just in case someone forgets.
USER 10000:10000
WORKDIR /var/lib/moonfire-nvr
ENTRYPOINT [ "/usr/local/bin/moonfire-nvr" ]

View File

@ -1,37 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# Build the "build-server" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
mkdir /docker-build-debug/build-server
exec > >(tee -i /docker-build-debug/build-server/output) 2>&1
date
uname -a
find /cargo-cache -ls > /docker-build-debug/build-server/cargo-cache-before
find ~/target -ls > /docker-build-debug/build-server/target-before
source ~/.buildrc
# The "mode" argument to cache mounts doesn't seem to work reliably
# (as of Docker version 20.10.5, build 55c4c88, using a docker-container
# builder), thus the chmod command.
sudo chmod 777 /cargo-cache /var/lib/moonfire-nvr/target
mkdir -p /cargo-cache/{git,registry}
ln -s /cargo-cache/{git,registry} ~/.cargo
build_profile=release-lto
cd src/server
time cargo test --features=bundled-ui
time cargo build --features=bundled-ui --profile=$build_profile
find /cargo-cache -ls > /docker-build-debug/build-server/cargo-cache-after
find ~/target -ls > /docker-build-debug/build-server/target-after
sudo install -m 755 \
~/platform-target/$build_profile/moonfire-nvr \
/usr/local/bin/moonfire-nvr
date

View File

@ -1,24 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# Build the "build-ui" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
mkdir /docker-build-debug/build-ui
exec > >(tee -i /docker-build-debug/build-ui/output) 2>&1
date
uname -a
node --version
npm --version
time npm ci
time npm run build
find /var/lib/moonfire-nvr/src/ui/node_modules -ls \
> /docker-build-debug/build-ui/node_modules-after
date

View File

@ -1,32 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# Build the "deploy" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
mkdir -p /docker-build-debug/deploy
exec > >(tee -i /docker-build-debug/deploy/output) 2>&1
find /var/cache/apt -ls > /docker-build-debug/deploy/var-cache-apt-before
date
uname -a
export DEBIAN_FRONTEND=noninteractive
time apt-get update
time apt-get install --assume-yes --no-install-recommends \
libncurses6 \
libncursesw6 \
locales \
sudo \
sqlite3 \
tzdata \
vim-nox
rm -rf /var/lib/apt/lists/*
ln -s moonfire-nvr /usr/local/bin/nvr
find /var/cache/apt -ls > /docker-build-debug/deploy/var-cache-apt-after
date

View File

@ -1,82 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# Build the "dev" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
mkdir --mode=1777 /docker-build-debug
mkdir /docker-build-debug/dev-common
exec > >(tee -i /docker-build-debug/dev-common/output) 2>&1
date
uname -a
find /var/cache/apt -ls > /docker-build-debug/dev-common/var-cache-apt-before
export DEBIAN_FRONTEND=noninteractive
# This file cleans apt caches after every invocation. Instead, we use a
# buildkit cachemount to avoid putting them in the image while still allowing
# some reuse.
rm /etc/apt/apt.conf.d/docker-clean
packages=()
# Install all packages necessary for building (and some for testing/debugging).
packages+=(
build-essential
curl
pkgconf
locales
sudo
sqlite3
tzdata
vim-nox
)
time apt-get update
time apt-get install --assume-yes --no-install-recommends "${packages[@]}"
# Install a more recent nodejs/npm than in the universe repository.
time curl -sL https://deb.nodesource.com/setup_14.x | bash -
time apt-get install nodejs
# Create the user. On the dev environment, allow sudo.
groupadd \
--gid="${BUILD_GID}" \
moonfire-nvr
useradd \
--no-log-init \
--home-dir=/var/lib/moonfire-nvr \
--uid="${BUILD_UID}" \
--gid=moonfire-nvr \
--shell=/bin/bash \
--create-home \
moonfire-nvr
echo 'moonfire-nvr ALL=(ALL) NOPASSWD: ALL' >>/etc/sudoers
# Install Rust. Note curl was already installed for yarn above.
time su moonfire-nvr -lc "
curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs |
sh -s - -y"
# Put configuration for the Rust build into a new ".buildrc" which is used
# both (1) interactively from ~/.bashrc when logging into the dev container
# and (2) from a build-server RUN command. In particular, the latter can't
# use ~/.bashrc because that script immediately exits when run from a
# non-interactive shell.
echo 'source $HOME/.buildrc' >> /var/lib/moonfire-nvr/.bashrc
cat >> /var/lib/moonfire-nvr/.buildrc <<EOF
source \$HOME/.cargo/env
# Set the target directory to be outside the src bind mount.
# https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir
export CARGO_BUILD_TARGET_DIR=/var/lib/moonfire-nvr/target
EOF
chown moonfire-nvr:moonfire-nvr /var/lib/moonfire-nvr/.buildrc
find /var/cache/apt -ls > /docker-build-debug/dev-common/var-cache-apt-after
date

View File

@ -1,122 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception.
# Build the "dev" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
mkdir /docker-build-debug/dev
exec > >(tee -i /docker-build-debug/dev/output) 2>&1
date
uname -a
find /var/cache/apt -ls > /docker-build-debug/dev/var-cache-apt-before
export DEBIAN_FRONTEND=noninteractive
packages=()
if [[ "${BUILDARCH}" != "${TARGETARCH}" ]]; then
# Set up cross compilation.
case "${TARGETARCH}" in
arm64)
dpkg_arch=arm64
gcc_target=aarch64-linux-gnu
rust_target=aarch64-unknown-linux-gnu
target_is_port=1
;;
arm)
dpkg_arch=armhf
gcc_target=arm-linux-gnueabihf
rust_target=arm-unknown-linux-gnueabihf
target_is_port=1
;;
amd64)
dpkg_arch=amd64
gcc_target=x86_64-linux-gnu
rust_target=x86_64-unknown-linux-gnu
target_is_port=0
;;
*)
echo "Unsupported cross-compile target ${TARGETARCH}." >&2
exit 1
esac
apt_target_suffix=":${dpkg_arch}"
case "${BUILDARCH}" in
amd64|386) host_is_port=0 ;;
*) host_is_port=1 ;;
esac
time dpkg --add-architecture "${dpkg_arch}"
if [[ $target_is_port -ne $host_is_port ]]; then
# Ubuntu stores non-x86 architectures at a different URL, so futz the
# sources file to allow installing both host and target.
# See https://github.com/rust-embedded/cross/blob/master/docker/common.sh
perl -pi.bak -e '
s{^deb (http://.*.ubuntu.com/ubuntu/) (.*)}
{deb [arch=amd64,i386] \1 \2\ndeb [arch-=amd64,i386] http://ports.ubuntu.com/ubuntu-ports \2};
s{^deb (http://ports.ubuntu.com/ubuntu-ports/) (.*)}
{deb [arch=amd64,i386] http://archive.ubuntu.com/ubuntu \2\ndeb [arch-=amd64,i386] \1 \2}' \
/etc/apt/sources.list
cat /etc/apt/sources.list
fi
packages+=(
g++-${gcc_target/_/-}
libc6-dev-${dpkg_arch}-cross
qemu-user
)
fi
time apt-get update
# Install the packages for the target architecture.
packages+=(
libncurses-dev"${apt_target_suffix}"
libsqlite3-dev"${apt_target_suffix}"
)
time apt-get update
time apt-get install --assume-yes --no-install-recommends "${packages[@]}"
# Set environment variables for cross-compiling.
# Also set up a symlink that points to the output platform's target dir, because
# the target directory layout varies when cross-compiling, as described here:
# https://doc.rust-lang.org/cargo/guide/build-cache.html
if [[ -n "${rust_target}" ]]; then
su moonfire-nvr -lc "rustup target install ${rust_target} &&
ln -s target/${rust_target} platform-target"
underscore_rust_target="${rust_target//-/_}"
uppercase_underscore_rust_target="${underscore_rust_target^^}"
cat >> /var/lib/moonfire-nvr/.buildrc <<EOF
# https://doc.rust-lang.org/cargo/reference/config.html
export CARGO_BUILD_TARGET=${rust_target}
export CARGO_TARGET_${uppercase_underscore_rust_target}_LINKER=${gcc_target}-gcc
# Use a pkg-config wrapper for the target architecture. This wrapper was
# automatically created on "dpkg --add-architecture"; see
# /etc/dpkg/dpkg.cfg.d/pkgconf-hook-config.
#
# https://github.com/rust-lang/pkg-config-rs uses the "PKG_CONFIG"
# variable to to select the pkg-config binary to use. As of pkg-config 0.3.19,
# it unfortunately doesn't understand the <target>_ prefix that the README.md
# describes for other vars. Fortunately Moonfire NVR doesn't have any host tools
# that need pkg-config.
export PKG_CONFIG=${gcc_target}-pkg-config
# https://github.com/alexcrichton/cc-rs uses these variables to decide what
# compiler to invoke.
export CC_${underscore_rust_target}=${gcc_target}-gcc
export CXX_${underscore_rust_target}=${gcc_target}-g++
EOF
else
su moonfire-nvr -lc "ln -s target platform-target"
fi
find /var/cache/apt -ls > /docker-build-debug/dev/var-cache-apt-after
date

View File

@ -2,7 +2,7 @@
This document has notes for software developers on building Moonfire NVR from This document has notes for software developers on building Moonfire NVR from
source code for development. If you just want to install precompiled source code for development. If you just want to install precompiled
binaries, see the [Docker installation instructions](install.md) instead. binaries, see the [installation instructions](install.md) instead.
This document doesn't spell out as many details as the installation This document doesn't spell out as many details as the installation
instructions. Please ask on Moonfire NVR's [issue instructions. Please ask on Moonfire NVR's [issue
@ -11,11 +11,9 @@ tracker](https://github.com/scottlamb/moonfire-nvr/issues) or
stuck. Please also send pull requests to improve this doc. stuck. Please also send pull requests to improve this doc.
* [Downloading](#downloading) * [Downloading](#downloading)
* [Docker builds](#docker-builds) * [Building](#building)
* [Release procedure](#release-procedure)
* [Non-Docker setup](#non-docker-setup)
* [Running interactively straight from the working copy](#running-interactively-straight-from-the-working-copy) * [Running interactively straight from the working copy](#running-interactively-straight-from-the-working-copy)
* [Running as a `systemd` service](#running-as-a-systemd-service) * [Release procedure](#release-procedure)
## Downloading ## Downloading
@ -28,152 +26,16 @@ $ git clone https://github.com/scottlamb/moonfire-nvr.git
$ cd moonfire-nvr $ cd moonfire-nvr
``` ```
## Docker builds ## Building
This command should prepare a deployment image for your local machine: Moonfire NVR should run natively on any Unix-like system. It's been tested on
Linux, macOS, and FreeBSD. (In theory [Windows Subsystem for
```console
$ sudo docker buildx build --load --tag=moonfire-nvr -f docker/Dockerfile .
```
<details>
<summary>Common errors</summary>
* `docker: 'buildx' is not a docker command.`: You shouldn't see this with
Docker 20.10. With Docker version 19.03 you'll need to prepend
`DOCKER_CLI_EXPERIMENTAL=enabled` to `docker buildx build` commands. If
your Docker version is older than 19.03, you'll need to upgrade.
* `At least one invalid signature was encountered.`: this is likely
due to an error in `libseccomp`, as described [in this askubuntu.com answer](https://askubuntu.com/a/1264921/1365248).
Try running in a privileged builder. As described in [`docker buildx build` documentation](https://docs.docker.com/engine/reference/commandline/buildx_build/#allow),
run this command once:
```console
$ sudo docker buildx create --use --name insecure-builder --buildkitd-flags '--allow-insecure-entitlement security.insecure'
```
then add `--allow security.insecure` to your `docker buildx build` commandlines.
</details>
If you want to iterate on code changes, doing a full Docker build from
scratch every time will be painfully slow. You will likely find it more
helpful to use the `dev` target. This is a self-contained developer environment
which you can use from its shell via `docker run` or via something like
Visual Studio Code's Docker plugin.
```console
$ sudo docker buildx build \
--load --tag=moonfire-dev --target=dev -f docker/Dockerfile .
...
$ sudo docker run \
--rm --interactive=true --tty \
--mount=type=bind,source=$(pwd),destination=/var/lib/moonfire-nvr/src \
moonfire-dev
```
The development image overrides cargo's output directory to
`/var/lib/moonfire-nvr/target`. (See `~moonfire-nvr/.buildrc`.) This avoids
using a bind filesystem for build products, which can be slow on macOS. It
also means that if you sometimes compile directly on the host and sometimes
within Docker, they don't trip over each other's target directories.
You can also cross-compile to a different architecture. Adding a
`--platform=linux/arm64/v8,linux/arm/v7,linux/amd64` argument will compile
Moonfire NVR for all supported platforms. (Note: this has been used
successfully for building on x86-64 and compiling to arm but not the
reverse.) For the `dev` target, this prepares a build which executes on your
local architecture and is capable of building a binary for your desired target
architecture.
On the author's macOS machine with Docker desktop 3.0.4, building for
multiple platforms at once will initially fail with the following error:
```console
$ sudo docker buildx build ... --platform=linux/arm64/v8,linux/arm/v7,linux/amd64
[+] Building 0.0s (0/0)
error: multiple platforms feature is currently not supported for docker driver. Please switch to a different driver (eg. "docker buildx create --use")
```
Running `docker buildx create --use` once solves this problem, with a couple
caveats:
* you'll need to specify an additional `--load` argument to make builds
available to run locally.
* the `--load` argument only works for one platform at a time. With multiple
platforms, it gives an error like the following:
```
error: failed to solve: rpc error: code = Unknown desc = docker exporter does not currently support exporting manifest lists
```
[A comment on docker/buildx issue
#59](https://github.com/docker/buildx/issues/59#issuecomment-667548900)
suggests a workaround of building all three then using caching to quickly
load the one of immediate interest:
```
$ sudo docker buildx build --platform=linux/arm64/v8,linux/arm/v7,linux/amd64 ...
$ sudo docker buildx build --load --platform=arm64/v8 ...
```
On Linux hosts (as opposed to when using Docker Desktop on macOS/Windows),
you'll likely see errors like the ones below. The solution is to [install
emulators](https://github.com/tonistiigi/binfmt#installing-emulators).
You may need to reinstall emulators on each boot of the host.
```
Exec format error
Error while loading /usr/sbin/dpkg-split: No such file or directory
Error while loading /usr/sbin/dpkg-deb: No such file or directory
```
Moonfire NVR's `Dockerfile` has some built-in debugging tools:
* Each stage saves some debug info to `/docker-build-debug/<stage>`, and
the `deploy` stage preserves the output from previous stages. The debug
info includes:
* output (stdout + stderr) from the build script, running long operations
through the `time` command.
* `find -ls` output on cache mounts before and after.
* Each stage accepts a `INVALIDATE_CACHE_<stage>` argument. You can use eg
`--build-arg=INVALIDATE_CACHE_BUILD_SERVER=$(date +%s)` to force the
`build-server` stage to be rebuilt rather than use cached Docker layers.
### Release procedure
Releases are currently a bit manual. From a completely clean git work tree,
1. manually verify the current commit is pushed to github's master branch and
has a green checkmark indicating CI passed.
2. update version in `CHANGELOG.md`.
3. run commands:
```bash
VERSION=x.y.z
git commit -am "prepare version ${VERSION}"
git tag -a "v${VERSION}" -m "version ${VERSION}"
./release.bash
git push
git push origin "v${VERSION}"
```
The `release.bash` script needs [`jq`](https://stedolan.github.io/jq/)
installed to work.
## Non-Docker setup
You may prefer building without Docker on the host. Moonfire NVR should run
natively on any Unix-like system. It's been tested on Linux and macOS.
(In theory [Windows Subsystem for
Linux](https://docs.microsoft.com/en-us/windows/wsl/about) should also work. Linux](https://docs.microsoft.com/en-us/windows/wsl/about) should also work.
Please speak up if you try it.) Please speak up if you try it.)
On macOS systems native builds may be noticeably faster than using Docker's To build the server, you will need [SQLite3](https://www.sqlite.org/). You
Linux VM and filesystem overlay. can skip this if compiling with `--features=rusqlite/bundled` and don't
mind the `moonfire-nvr sql` command not working.
To build the server, you will need the following C libraries installed:
* [SQLite3](https://www.sqlite.org/), at least version 3.8.2.
(You can skip this if you compile with `--features=bundled` and
don't mind the `moonfire-nvr sql` command not working.)
* [`ncursesw`](https://www.gnu.org/software/ncurses/), the UTF-8 version of
the `ncurses` library.
To build the UI, you'll need a [nodejs](https://nodejs.org/en/download/) release To build the UI, you'll need a [nodejs](https://nodejs.org/en/download/) release
in "Maintenance" or "LTS" status: currently v14, v16, or v18. in "Maintenance" or "LTS" status: currently v14, v16, or v18.
@ -184,7 +46,6 @@ most non-Rust dependencies:
```console ```console
$ sudo apt-get install \ $ sudo apt-get install \
build-essential \ build-essential \
libncurses-dev \
libsqlite3-dev \ libsqlite3-dev \
pkgconf \ pkgconf \
sqlite3 \ sqlite3 \
@ -253,72 +114,24 @@ $ nvr run
with `cargo build` rather than `cargo build --release`, for a faster build with `cargo build` rather than `cargo build --release`, for a faster build
cycle and slower performance.) cycle and slower performance.)
Note this `nvr` is a little different than the `nvr` shell script you create ## Release procedure
when following the [install instructions](install.md). With that shell wrapper,
`nvr run` will create and run a detached Docker container with some extra
arguments specified in the script. This `nvr run` will directly run from the
terminal, with no extra arguments, until you abort with Ctrl-C. Likewise,
some of the shell script's subcommands that wrap Docker (`start`, `stop`, and
`logs`) have no parallel with this `nvr`.
### Running as a `systemd` service Releases are currently a bit manual. From a completely clean git work tree,
If you want to deploy a non-Docker build on Linux, you may want to use 1. manually verify the current commit is pushed to github's master branch and
`systemd`. Create `/etc/systemd/system/moonfire-nvr.service`: has a green checkmark indicating CI passed.
2. update versions:
* update `server/Cargo.toml` version by hand; run `cargo test --workspace`
to update `Cargo.lock`.
* ensure `README.md` and `CHANGELOG.md` refer to the new version.
3. run commands:
```bash
VERSION=x.y.z
git commit -am "prepare version ${VERSION}"
git tag -a "v${VERSION}" -m "version ${VERSION}"
git push origin "v${VERSION}"
```
```ini The rest should happen automatically—the tag push will fire off a GitHub
[Unit] Actions workflow which creates a release, cross-compiles statically compiled
Description=Moonfire NVR binaries for three different platforms, and uploads them to the release.
After=network-online.target
[Service]
ExecStart=/usr/local/bin/moonfire-nvr run
Environment=TZ=:/etc/localtime
Environment=MOONFIRE_FORMAT=google-systemd
Environment=MOONFIRE_LOG=info
Environment=RUST_BACKTRACE=1
Type=simple
User=moonfire-nvr
Restart=on-failure
CPUAccounting=true
MemoryAccounting=true
BlockIOAccounting=true
[Install]
WantedBy=multi-user.target
```
You'll also need a `/etc/moonfire-nvr.toml`:
```toml
[[binds]]
ipv4 = "0.0.0.0:8080"
allowUnauthenticatedPermissions = { viewVideo = true }
[[binds]]
unix = "/var/lib/moonfire-nvr/sock"
ownUidIsPrivileged = true
```
Note this configuration is insecure. You can change that via replacing the
`allowUnauthenticatedPermissions` here as described in [Securing Moonfire NVR
and exposing it to the Internet](secure.md).
See [ref/config.md](../ref/config.md) for more about `/etc/moonfire-nvr.toml`.
Some handy commands:
```console
$ sudo systemctl daemon-reload # reload configuration files
$ sudo systemctl start moonfire-nvr # start the service now
$ sudo systemctl stop moonfire-nvr # stop the service now (but don't wait for it finish stopping)
$ sudo systemctl status moonfire-nvr # show if the service is running and the last few log lines
$ sudo systemctl enable moonfire-nvr # start the service on boot
$ sudo systemctl disable moonfire-nvr # don't start the service on boot
$ sudo journalctl --unit=moonfire-nvr --since='-5 min' --follow # look at recent logs and await more
```
See the [systemd](http://www.freedesktop.org/wiki/Software/systemd/)
documentation for more information. The [manual
pages](http://www.freedesktop.org/software/systemd/man/) for `systemd.service`
and `systemctl` may be of particular interest.

View File

@ -1,14 +1,14 @@
# Installing Moonfire NVR <!-- omit in toc --> # Installing Moonfire NVR <!-- omit in toc -->
* [Downloading, installing, and configuring Moonfire NVR with Docker](#downloading-installing-and-configuring-moonfire-nvr-with-docker) * [Downloading, installing, and configuring Moonfire NVR](#downloading-installing-and-configuring-moonfire-nvr)
* [Dedicated hard drive setup](#dedicated-hard-drive-setup) * [Dedicated hard drive setup](#dedicated-hard-drive-setup)
* [Completing configuration through the UI](#completing-configuration-through-the-ui) * [Completing configuration through the UI](#completing-configuration-through-the-ui)
* [Starting it up](#starting-it-up) * [Starting it up](#starting-it-up)
## Downloading, installing, and configuring Moonfire NVR with Docker ## Downloading, installing, and configuring Moonfire NVR
This document describes how to download, install, and configure Moonfire NVR This document describes how to download, install, and configure Moonfire NVR
via the prebuilt Docker images available for x86-64, arm64, and arm. If you via the prebuilt Linux binaries available for x86-64, arm64, and arm. If you
instead want to build Moonfire NVR yourself, see the [Build instead want to build Moonfire NVR yourself, see the [Build
instructions](build.md). instructions](build.md).
@ -18,17 +18,16 @@ left, and pick the [latest tagged version](https://github.com/scottlamb/moonfire
![Selecting a version of install instructions](install-version.png) ![Selecting a version of install instructions](install-version.png)
Next, install [Docker](https://www.docker.com/) if you haven't already, Download the binary for your platform from the matching GitHub release.
and verify `sudo docker run --rm hello-world` works. Install it as `/usr/local/bin/moonfire-nvr` and ensure it is executable, e.g.
for version `v0.7.8` on Intel machines:
<details> ```console
<summary><tt>sudo</tt> or not?</summary> $ VERSION=v0.7.8
$ ARCH=x86_64-unknown-linux-musl
If you prefer to save typing by not prefixing all `docker` and `nvr` commands $ curl -OL "https://github.com/scottlamb/moonfire-nvr/releases/download/$VERSION/moonfire-nvr-$VERSION-$ARCH"
with `sudo`, see [Docker docs: Manage Docker as a non-root $ sudo install -m 755 "moonfire-nvr-$VERSION-$ARCH" /usr/local/bin/moonfire-nvr
user](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user). ```
Note `docker` access is equivalent to root access security-wise.
</details>
Next, you'll need to set up your filesystem and the Moonfire NVR user. Next, you'll need to set up your filesystem and the Moonfire NVR user.
@ -49,22 +48,12 @@ On most Linux systems, you can create the user as follows:
$ sudo useradd --user-group --create-home --home /var/lib/moonfire-nvr moonfire-nvr $ sudo useradd --user-group --create-home --home /var/lib/moonfire-nvr moonfire-nvr
``` ```
and create a script called `nvr` to run Moonfire NVR as the intended host user. Use your favorite editor to create `/etc/moonfire-nvr.toml`,
This script supports running Moonfire NVR's various administrative commands interactively starting from the configurations below:
and managing a long-lived Docker container for its web interface.
As you set up this script, adjust the `tz` variable as appropriate for your
time zone.
Use your favorite editor to create `/etc/moonfire-nvr.toml` and
`/usr/local/bin/nvr`, starting from the configurations below:
```console ```console
$ sudo nano /etc/moonfire-nvr.toml $ sudo nano /etc/moonfire-nvr.toml
(see below for contents) (see below for contents)
$ sudo nano /usr/local/bin/nvr
(see below for contents)
$ sudo chmod a+rx /usr/local/bin/nvr
``` ```
`/etc/moonfire-nvr.toml` (see [ref/config.md](../ref/config.md) for more explanation): `/etc/moonfire-nvr.toml` (see [ref/config.md](../ref/config.md) for more explanation):
@ -78,79 +67,10 @@ unix = "/var/lib/moonfire-nvr/sock"
ownUidIsPrivileged = true ownUidIsPrivileged = true
``` ```
`/usr/local/bin/nvr`: Then initialize the database:
```bash
#!/bin/bash -e
# Set your timezone here.
tz="America/Los_Angeles"
image_name="scottlamb/moonfire-nvr:v0.7.7"
container_name="moonfire-nvr"
common_docker_run_args=(
--mount=type=bind,source=/var/lib/moonfire-nvr,destination=/var/lib/moonfire-nvr
--mount=type=bind,source=/etc/moonfire-nvr.toml,destination=/etc/moonfire-nvr.toml
# Add additional mount lines here for each sample file directory
# outside of /var/lib/moonfire-nvr, e.g.:
# --mount=type=bind,source=/media/nvr/sample,destination=/media/nvr/sample
--user="$(id -u moonfire-nvr):$(id -g moonfire-nvr)"
# This avoids errors with broken seccomp on older 32-bit hosts.
# https://github.com/moby/moby/issues/40734
--security-opt=seccomp:unconfined
# This is the simplest way of configuring networking, although
# you can use e.g. --publish=8080:8080 in the run) case below if you
# prefer.
--network=host
# docker's default log driver won't rotate logs properly, and will throw
# away logs when you destroy and recreate the container. Using journald
# solves these problems.
# https://docs.docker.com/config/containers/logging/configure/
--log-driver=journald
--log-opt="tag=moonfire-nvr"
--env=RUST_BACKTRACE=1
--env=TZ=":${tz}"
)
case "$1" in
run)
shift
exec docker run \
--detach=true \
--restart=unless-stopped \
"${common_docker_run_args[@]}" \
--name="${container_name}" \
"${image_name}" \
run \
"$@"
;;
start|stop|logs|rm)
exec docker "$@" "${container_name}"
;;
pull)
exec docker pull "${image_name}"
;;
*)
exec docker run \
--interactive=true \
--tty \
--rm \
"${common_docker_run_args[@]}" \
"${image_name}" \
"$@"
;;
esac
```
then try it out by initializing the database:
```console ```console
$ sudo nvr init $ sudo -u moonfire-nvr moonfire-nvr init
``` ```
This will create a directory `/var/lib/moonfire-nvr/db` with a SQLite3 database This will create a directory `/var/lib/moonfire-nvr/db` with a SQLite3 database
@ -189,10 +109,6 @@ system will boot successfully even when the hard drive is unavailable (such as
when your external USB storage is unmounted). This can be helpful when when your external USB storage is unmounted). This can be helpful when
recovering from problems. recovering from problems.
Add a new `--mount` line to your Docker wrapper script `/usr/local/bin/nvr`
to expose the new sample directory `/media/nvr/sample` to the Docker container,
right where a comment mentions "Additional mount lines".
### Completing configuration through the UI ### Completing configuration through the UI
Once your system is set up, it's time to initialize an empty database Once your system is set up, it's time to initialize an empty database
@ -200,16 +116,17 @@ and add the cameras and sample directories. You can do this
by using the `moonfire-nvr` binary's text-based configuration tool. by using the `moonfire-nvr` binary's text-based configuration tool.
```console ```console
$ sudo nvr config 2>debug-log $ sudo -u moonfire-nvr moonfire-nvr config 2>debug-log
``` ```
<details> <details>
<summary>Did it return without doing anything?</summary> <summary>Did it return without doing anything?</summary>
If `nvr config` returns you to the console prompt right away, look in the If `moonfire-nvr config` returns you to the console prompt right away, look in
`debug-log` file for why. One common reason is that you have Moonfire NVR the `debug-log` file for why. One common reason is that you have Moonfire NVR
running; you'll need to shut it down first. Try `nvr stop` before `nvr config` running; you'll need to shut it down first. If you are running a systemd
and `nvr start` afterward. service as described below, try `sudo systemctl stop moonfire-nvr` before
editing the config and `sudo systemctl start moonfire-nvr` after.
</details> </details>
In the user interface, In the user interface,
@ -277,15 +194,58 @@ starting it in this configuration to try it out, particularly if the machine
it's running on is behind a home router's firewall. You might not; in that case it's running on is behind a home router's firewall. You might not; in that case
read through [secure the system](secure.md) first. read through [secure the system](secure.md) first.
This command will start a detached Docker container for the web interface. Assuming you want to proceed, you can launch Moonfire NVR through `systemd`.
It will automatically restart when your system does. Create `/etc/systemd/system/moonfire-nvr.service`:
```console ```ini
$ sudo nvr run [Unit]
Description=Moonfire NVR
After=network-online.target
# If you use an external hard drive, uncomment this with a reference to the
# mount point as written in `/etc/fstab`.
# RequiresMountsFor=/media/nvr
[Service]
ExecStart=/usr/local/bin/moonfire-nvr run
Environment=TZ=:/etc/localtime
Environment=MOONFIRE_FORMAT=systemd
Environment=MOONFIRE_LOG=info
Environment=RUST_BACKTRACE=1
Type=simple
User=moonfire-nvr
Restart=on-failure
CPUAccounting=true
MemoryAccounting=true
BlockIOAccounting=true
[Install]
WantedBy=multi-user.target
``` ```
You can temporarily disable the service via `nvr stop` and restart it later via Then start it up as follows:
`nvr start`. You'll need to do this before and after using `nvr config`.
```console
$ sudo systemctl daemon-reload # read in the new config file
$ sudo systemctl enable --now moonfire-nvr # start the service now and on boot
```
Some handy commands:
```console
$ sudo systemctl daemon-reload # reload configuration files
$ sudo systemctl start moonfire-nvr # start the service now without enabling on boot
$ sudo systemctl stop moonfire-nvr # stop the service now (but don't wait for it finish stopping)
$ sudo systemctl status moonfire-nvr # show if the service is running and the last few log lines
$ sudo systemctl enable moonfire-nvr # start the service on boot
$ sudo systemctl disable moonfire-nvr # don't start the service on boot
$ sudo journalctl --unit=moonfire-nvr --since='-5 min' --follow # look at recent logs and await more
```
See the [systemd](http://www.freedesktop.org/wiki/Software/systemd/)
documentation for more information. The [manual
pages](http://www.freedesktop.org/software/systemd/man/) for `systemd.service`
and `systemctl` may be of particular interest.
The HTTP interface is accessible on port 8080; if your web browser is running The HTTP interface is accessible on port 8080; if your web browser is running
on the same machine, you can access it at on the same machine, you can access it at

View File

@ -62,11 +62,11 @@ SQLite database:
no longer in the dangerous mode. no longer in the dangerous mode.
Next ensure Moonfire NVR is not running and does not automatically restart if Next ensure Moonfire NVR is not running and does not automatically restart if
the system is rebooted during the upgrade. If you followed the Docker the system is rebooted during the upgrade. If you followed the standard
instructions, you can do this as follows: instructions, you can do this as follows:
```console ```console
$ sudo nvr stop $ sudo systemctl disable --now moonfire-nvr
``` ```
Then back up your SQLite database. If you are using the default path, you can Then back up your SQLite database. If you are using the default path, you can
@ -92,34 +92,27 @@ manual for write-ahead logging](https://www.sqlite.org/wal.html):
Run the upgrade procedure using the new software binary. Run the upgrade procedure using the new software binary.
```console
$ sudo nvr pull # updates the docker image to the latest binary
$ sudo nvr upgrade # runs the upgrade
```
As a rule of thumb, on a Raspberry Pi 4 with a 1 GiB database, an upgrade might As a rule of thumb, on a Raspberry Pi 4 with a 1 GiB database, an upgrade might
take about four minutes for each schema version and for the final vacuum. take about four minutes for each schema version and for the final vacuum.
Next, you can run the system in read-only mode, although you'll find this only Next, you can run the system in read-only mode, although you'll find this only
works in the "insecure" setup. (Authorization requires writing the database.) works in the "insecure" setup. (Authorization requires writing the database.)
To just run directly within the console until you hit ctrl-C, use the following
command:
```console ```console
$ sudo nvr rm $ sudo -u moonfire-nvr moonfire-nvr run --read-only
$ sudo nvr run --read-only
``` ```
Go to the web interface and ensure the system is operating correctly. If Go to the web interface and ensure the system is operating correctly. If
you detect a problem now, you can copy the old database back over the new one you detect a problem now, you can copy the old database back over the new one
and edit your `nvr` script to use the corresponding older Docker image. If and go back to the prior release. If you detect a problem after enabling
you detect a problem after enabling read-write operation, a restore will be read-write operation, a restore will be more complicated.
more complicated.
Once you're satisfied, restart the system in read-write mode: Once you're satisfied, ctrl-C and start the system in read-write mode:
```console ```console
$ sudo nvr stop $ sudo systemctl enable --now moonfire-nvr
$ sudo nvr rm
$ sudo nvr run
``` ```
Hopefully your system is functioning correctly. If not, there are two options Hopefully your system is functioning correctly. If not, there are two options
@ -137,7 +130,8 @@ for restore; neither are easy:
* undo the changes by hand. There's no documentation on this; you'll need * undo the changes by hand. There's no documentation on this; you'll need
to read the code and come up with a reverse transformation. to read the code and come up with a reverse transformation.
The `nvr check` command will show you what problems exist on your system. The `sudo -u moonfire-nvr moonfire-nvr check` command will show you what
problems exist on your system.
### Unversioned to version 0 ### Unversioned to version 0

View File

@ -161,8 +161,8 @@ your browser. See [How to secure Nginx with Let's Encrypt on Ubuntu
## 6. Reconfigure Moonfire NVR ## 6. Reconfigure Moonfire NVR
If you follow the recommended Docker setup, your `/etc/moonfire-nvr.toml` If you follow the recommended setup, your `/etc/moonfire-nvr.toml` will contain
will contain this line: this line:
```toml ```toml
allowUnauthenticatedPermissions = { viewVideo = true } allowUnauthenticatedPermissions = { viewVideo = true }
@ -185,18 +185,16 @@ This change has two effects:
See also [ref/config.md](../ref/config.md) for more about the configuration file. See also [ref/config.md](../ref/config.md) for more about the configuration file.
If the webserver is running on the same machine as Moonfire NVR, you might If the webserver is running on the same machine as Moonfire NVR, you might
also change `--publish=8080:8080` to `--publish=127.0.0.1:8080:8080` in your also change the `ipv4 = "0.0.0.0:8080"` line in `/etc/moonfire-nvr/toml` to
`/usr/local/bin/nvr` script, preventing other machines on the network from `ipv4 = "127.0.0.1:8080"`, so that only the local host can directly connect to
impersonating the proxy, effectively allowing them to lie about the client's IP Moonfire NVR. If other machines can connect directly, they can impersonate
and protocol. the proxy, which would effectively allow them to lie about the client's IP and
protocol.
To make this take effect, you'll need to stop the running Docker container, To make this take effect, you'll need to restart Moonfire NVR:
delete it, and create/run a new one:
```console ```console
$ sudo nvr stop $ sudo systemctl restart moonfire-nvr
$ sudo nvr rm
$ sudo nvr run
``` ```
## 7. Configure the webserver ## 7. Configure the webserver

View File

@ -11,7 +11,6 @@ need more help.
* [Camera stream errors](#camera-stream-errors) * [Camera stream errors](#camera-stream-errors)
* [Problems](#problems) * [Problems](#problems)
* [Server errors](#server-errors) * [Server errors](#server-errors)
* [`clock_gettime failed: EPERM: Operation not permitted`](#clock_gettime-failed-eperm-operation-not-permitted)
* [`Error: pts not monotonically increasing; got 26615520 then 26539470`](#error-pts-not-monotonically-increasing-got-26615520-then-26539470) * [`Error: pts not monotonically increasing; got 26615520 then 26539470`](#error-pts-not-monotonically-increasing-got-26615520-then-26539470)
* [Out of disk space](#out-of-disk-space) * [Out of disk space](#out-of-disk-space)
* [Database or filesystem corruption errors](#database-or-filesystem-corruption-errors) * [Database or filesystem corruption errors](#database-or-filesystem-corruption-errors)
@ -29,9 +28,8 @@ While Moonfire NVR is running, logs will be written to stderr.
* When running the configuration UI, you typically should redirect stderr * When running the configuration UI, you typically should redirect stderr
to a text file to avoid poor interaction between the interactive stdout to a text file to avoid poor interaction between the interactive stdout
output and the logging. If you use the recommended output and the logging. If you use the recommended
`nvr config 2>debug-log` command, output will be in the `debug-log` file. `moonfire-nvr config 2>debug-log` command, output will be in the
* When running detached through Docker, Docker saves the logs for you. `debug-log` file.
Try `nvr logs` or `docker logs moonfire-nvr`.
* When running through systemd, stderr will be redirected to the journal. * When running through systemd, stderr will be redirected to the journal.
Try `sudo journalctl --unit moonfire-nvr` to view the logs. You also Try `sudo journalctl --unit moonfire-nvr` to view the logs. You also
likely want to set `MOONFIRE_FORMAT=systemd` to format logs as likely want to set `MOONFIRE_FORMAT=systemd` to format logs as
@ -56,8 +54,6 @@ Logging options are controlled by environment variables:
consumption. consumption.
* Errors include a backtrace if `RUST_BACKTRACE=1` is set. * Errors include a backtrace if `RUST_BACKTRACE=1` is set.
If you use Docker, set these via Docker's `--env` argument.
With `MOONFIRE_FORMAT` left unset, log events look as follows: With `MOONFIRE_FORMAT` left unset, log events look as follows:
```text ```text
@ -191,23 +187,6 @@ quickly enough. In the latter case, you'll likely see a
### Server errors ### Server errors
#### `clock_gettime failed: EPERM: Operation not permitted`
If commands fail with an error like the following, you're likely running
Docker with an overly restrictive `seccomp` setup. [This stackoverflow
answer](https://askubuntu.com/questions/1263284/apt-update-throws-signature-error-in-ubuntu-20-04-container-on-arm/1264921#1264921) describes the
problem in more detail. The simplest solution is to add
`--security-opt=seccomp:unconfined` to your Docker commandline.
If you are using the recommended `/usr/local/bin/nvr` wrapper script,
add this option to the `common_docker_run_args` section.
```console
$ sudo docker run --rm -it moonfire-nvr:latest
clock_gettime failed: EPERM: Operation not permitted
This indicates a broken environment. See the troubleshooting guide.
```
#### `Error: pts not monotonically increasing; got 26615520 then 26539470` #### `Error: pts not monotonically increasing; got 26615520 then 26539470`
If your streams cut out and you see error messages like this one in Moonfire If your streams cut out and you see error messages like this one in Moonfire
@ -322,8 +301,7 @@ mechanism to fix old timestamps after the fact. Ideas and help welcome; see
#### `moonfire-nvr config` displays garbage #### `moonfire-nvr config` displays garbage
This happens if you're not using the premade Docker containers and have This may happen if your machine is configured to a non-UTF-8 locale, due to
configured your machine is configured to a non-UTF-8 locale, due to
gyscos/Cursive#13. As a workaround, try setting the environment variable gyscos/Cursive#13. As a workaround, try setting the environment variable
`LC_ALL=C.UTF-8`. `LC_ALL=C.UTF-8`.

View File

@ -1,51 +0,0 @@
#!/bin/bash
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
# SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
# Pushes a release to Docker. See guides/build.md#release-procedure.
set -o errexit
set -o pipefail
set -o xtrace
set_latest() {
# Our images are manifest lists (for multiple architectures).
# "docker tag" won't copy those. The technique below is adopted from here:
# https://github.com/docker/buildx/issues/459#issuecomment-750011371
local image="$1"
local hashes=($(docker manifest inspect "${image}:${version}" |
jq --raw-output '.manifests[].digest'))
time docker manifest rm "${image}:latest" || true
time docker manifest create \
"${image}:latest" \
"${hashes[@]/#/${image}@}"
time docker manifest push "${image}:latest"
}
build_and_push() {
local image="$1"
local target="$2"
time docker buildx build \
--push \
--tag="${image}:${version}" \
--target="${target}" \
--platform=linux/amd64,linux/arm64/v8,linux/arm/v7 \
-f docker/Dockerfile .
}
version="$(git describe --dirty)"
if [[ ! "${version}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Expected a vX.Y.Z version tag, got ${version}." >&2
exit 1
fi
if [[ -n "$(git status --porcelain)" ]]; then
echo "git status says there's extra stuff in this directory." >&2
exit 1
fi
build_and_push scottlamb/moonfire-nvr deploy
build_and_push scottlamb/moonfire-dev dev
set_latest scottlamb/moonfire-nvr
set_latest scottlamb/moonfire-dev

46
server/Cargo.lock generated
View File

@ -303,10 +303,8 @@ dependencies = [
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"maplit",
"ncurses",
"signal-hook", "signal-hook",
"term_size", "termion",
"unicode-segmentation", "unicode-segmentation",
"unicode-width", "unicode-width",
] ]
@ -982,12 +980,6 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -1198,17 +1190,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918" checksum = "96a1fe2275b68991faded2c80aa4a33dba398b77d276038b8f50701a22e55918"
[[package]]
name = "ncurses"
version = "5.101.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e2c5d34d72657dc4b638a1c25d40aae81e4f1c699062f72f467237920752032"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.26.1" version = "0.26.1"
@ -1338,6 +1319,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]] [[package]]
name = "odds" name = "odds"
version = "0.4.0" version = "0.4.0"
@ -1581,6 +1568,15 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
[[package]]
name = "redox_termios"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
dependencies = [
"redox_syscall",
]
[[package]] [[package]]
name = "reffers" name = "reffers"
version = "0.7.0" version = "0.7.0"
@ -1994,13 +1990,15 @@ dependencies = [
] ]
[[package]] [[package]]
name = "term_size" name = "termion"
version = "0.3.2" version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "numtoa",
"redox_syscall",
"redox_termios",
] ]
[[package]] [[package]]

View File

@ -35,7 +35,7 @@ bpaf = { version = "0.9.1", features = ["autocomplete", "bright-color", "derive"
bytes = "1" bytes = "1"
byteorder = "1.0" byteorder = "1.0"
chrono = "0.4.23" chrono = "0.4.23"
cursive = "0.20.0" cursive = { version = "0.20.0", default-features = false, features = ["termion-backend"] }
db = { package = "moonfire-db", path = "db" } db = { package = "moonfire-db", path = "db" }
futures = "0.3" futures = "0.3"
fnv = "1.0" fnv = "1.0"

14
server/Cross.toml Normal file
View File

@ -0,0 +1,14 @@
[build.env]
volumes = [
# For the (optional) `bundled-ui` feature.
"UI_BUILD_DIR",
# For tests which use the `America/Los_Angeles` zone.
"ZONEINFO=/usr/share/zoneinfo",
]
passthrough = [
# Cross's default docker image doesn't install `git`, so `git_version!` doesn't work.
# Allow passing through the version via this environment variable.
"VERSION",
]

View File

@ -6,13 +6,17 @@
use std::fmt::Write; use std::fmt::Write;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::ExitCode; use std::process::Command;
const UI_DIR: &str = "../ui/build"; const UI_BUILD_DIR_ENV_VAR: &str = "UI_BUILD_DIR";
const DEFAULT_UI_BUILD_DIR: &str = "../ui/build";
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
fn ensure_link(original: &Path, link: &Path) { fn ensure_link(original: &Path, link: &Path) {
match std::fs::read_link(link) { match std::fs::read_link(link) {
Ok(dst) if dst == original => return, Ok(dst) if dst == original => return,
Ok(_) => std::fs::remove_file(link).expect("removing stale symlink should succeed"),
Err(e) if e.kind() != std::io::ErrorKind::NotFound => { Err(e) if e.kind() != std::io::ErrorKind::NotFound => {
panic!("couldn't create link {link:?} to original path {original:?}: {e}") panic!("couldn't create link {link:?} to original path {original:?}: {e}")
} }
@ -67,37 +71,30 @@ fn stringify_files(files: &FileMap) -> Result<String, std::fmt::Error> {
Ok(buf) Ok(buf)
} }
fn main() -> ExitCode { fn handle_bundled_ui() -> Result<(), BoxError> {
// Explicitly declare dependencies, so this doesn't re-run if other source files change.
println!("cargo:rerun-if-changed=build.rs");
// Nothing to do if the feature is off. cargo will re-run if features change. // Nothing to do if the feature is off. cargo will re-run if features change.
if !cfg!(feature = "bundled-ui") { if !cfg!(feature = "bundled-ui") {
return ExitCode::SUCCESS; return Ok(());
} }
let ui_dir =
std::env::var(UI_BUILD_DIR_ENV_VAR).unwrap_or_else(|_| DEFAULT_UI_BUILD_DIR.to_owned());
// If the feature is on, also re-run if the actual UI files change. // If the feature is on, also re-run if the actual UI files change.
println!("cargo:rerun-if-changed={UI_DIR}"); println!("cargo:rerun-if-env-changed={UI_BUILD_DIR_ENV_VAR}");
println!("cargo:rerun-if-changed={ui_dir}");
let out_dir: PathBuf = std::env::var_os("OUT_DIR") let out_dir: PathBuf = std::env::var_os("OUT_DIR")
.expect("cargo should set OUT_DIR") .expect("cargo should set OUT_DIR")
.into(); .into();
let abs_ui_dir = std::fs::canonicalize(UI_DIR) let abs_ui_dir = std::fs::canonicalize(&ui_dir).map_err(|e| format!("ui dir {ui_dir:?} should be accessible. Did you run `npm run build` first?\n\ncaused by:\n{e}"))?;
.expect("ui dir should be accessible. Did you run `npm run build` first?");
let mut files = FileMap::default(); let mut files = FileMap::default();
for entry in walkdir::WalkDir::new(&abs_ui_dir) { for entry in walkdir::WalkDir::new(&abs_ui_dir) {
let entry = match entry { let entry = entry.map_err(|e| {
Ok(e) => e, format!("walkdir failed. Did you run `npm run build` first?\n\ncaused by:\n{e}")
Err(e) => { })?;
eprintln!(
"walkdir failed. Did you run `npm run build` first?\n\n\
caused by:\n{e}"
);
return ExitCode::FAILURE;
}
};
if !entry.file_type().is_file() { if !entry.file_type().is_file() {
continue; continue;
} }
@ -135,6 +132,13 @@ fn main() -> ExitCode {
); );
} }
if !files.contains_key("index.html") {
return Err(format!(
"No `index.html` within {ui_dir:?}. Did you run `npm run build` first?"
)
.into());
}
let files = stringify_files(&files).expect("write to String should succeed"); let files = stringify_files(&files).expect("write to String should succeed");
let mut out_rs_path = std::path::PathBuf::new(); let mut out_rs_path = std::path::PathBuf::new();
out_rs_path.push(&out_dir); out_rs_path.push(&out_dir);
@ -145,5 +149,49 @@ fn main() -> ExitCode {
out_link_path.push(&out_dir); out_link_path.push(&out_dir);
out_link_path.push("ui_files"); out_link_path.push("ui_files");
ensure_link(&abs_ui_dir, &out_link_path); ensure_link(&abs_ui_dir, &out_link_path);
return ExitCode::SUCCESS; Ok(())
}
fn handle_version() -> Result<(), BoxError> {
println!("cargo:rerun-if-env-changed=VERSION");
if std::env::var("VERSION").is_ok() {
return Ok(());
}
// Get version from `git describe`. Inspired by the `git-version` crate.
// We don't use that directly because `cross`'s default docker image doesn't install `git`,
// and thus we need the environment variable pass-through above.
// Avoid reruns when the output doesn't meaningfully change. I don't think this is quite right:
// it won't recognize toggling between `-dirty` and not. But it'll do.
let dir = Command::new("git")
.arg("rev-parse")
.arg("--git-dir")
.output()?
.stdout;
let dir = String::from_utf8(dir).unwrap();
let dir = dir.strip_suffix('\n').unwrap();
println!("cargo:rerun-if-changed={dir}/logs/HEAD");
println!("cargo:rerun-if-changed={dir}/index");
// Plumb the version through.
let version = Command::new("git")
.arg("describe")
.arg("--always")
.arg("--dirty")
.output()?
.stdout;
let version = String::from_utf8(version).unwrap();
let version = version.strip_suffix('\n').unwrap();
println!("cargo:rustc-env=VERSION={version}");
Ok(())
}
fn main() -> Result<(), BoxError> {
// Explicitly declare dependencies, so this doesn't re-run if other source files change.
println!("cargo:rerun-if-changed=build.rs");
handle_bundled_ui()?;
handle_version()?;
Ok(())
} }

View File

@ -22,6 +22,7 @@ struct BuildFile {
encoding: FileEncoding, encoding: FileEncoding,
} }
#[allow(unused)] // it's valid for a UI to have all uncompressed files or vice versa.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum FileEncoding { enum FileEncoding {
Uncompressed, Uncompressed,

View File

@ -25,7 +25,8 @@ mod bundled_ui;
const DEFAULT_DB_DIR: &str = "/var/lib/moonfire-nvr/db"; const DEFAULT_DB_DIR: &str = "/var/lib/moonfire-nvr/db";
const VERSION: &str = git_version::git_version!(args = ["--always", "--dirty"]); // This is either in the environment when `cargo` is invoked or set from within `build.rs`.
const VERSION: &str = env!("VERSION");
/// Moonfire NVR: security camera network video recorder. /// Moonfire NVR: security camera network video recorder.
#[derive(Bpaf, Debug)] #[derive(Bpaf, Debug)]