restructure into "server" and "ui" subdirs

Besides being more clear about what belongs to which, this helps with
docker caching. The server and ui parts are only rebuilt when their
respective subdirectories change.

Extend this a bit further by making the webpack build not depend on
the target architecture. And adding cache dirs so parts of the server
and ui build process can be reused when layer-wide caching fails.
This commit is contained in:
Scott Lamb 2021-01-22 14:43:41 -08:00
parent adcfc5e5f0
commit dd66c7b0dd
100 changed files with 127 additions and 105 deletions

View File

@ -1,3 +1,4 @@
node_modules
target
ui-dist
/server/target
/ui/dist
/ui/node_modules
/ui/yarn-error.log

View File

@ -27,7 +27,7 @@ jobs:
path: |
~/.cargo/registry
~/.cargo/git
target
server/target
key: ${{ matrix.rust }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install libavcodec-dev libavformat-dev libavutil-dev libncurses-dev libsqlite3-dev pkgconf
@ -38,7 +38,7 @@ jobs:
toolchain: ${{ matrix.rust }}
override: true
- name: Test
run: cargo test ${{ matrix.extra_args }} --all
run: cd server && cargo test ${{ matrix.extra_args }} --all
js:
name: Build and lint Javascript frontend
runs-on: ubuntu-20.04
@ -57,6 +57,6 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install
- run: yarn build
- run: yarn lint
- run: cd ui && yarn install
- run: cd ui && yarn build
- run: cd ui && yarn lint

11
.gitignore vendored
View File

@ -1,9 +1,6 @@
.DS_Store
*.swp
*.sublime-workspace
node_modules
prep.config
db/schema.rs
target
ui-dist
yarn-error.log
/server/target
/ui/dist
/ui/node_modules
/ui/yarn-error.log

View File

@ -3,39 +3,51 @@
# See documentation here:
# https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md
# Moonfire NVR development environment, using the build platform.
FROM --platform=$BUILDPLATFORM ubuntu:20.04 AS dev
# "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 TARGETARCH
ARG BUILDARCH
ARG BUILD_UID=1000
ARG BUILD_GID=1000
LABEL maintainer="slamb@slamb.org"
ENV LC_ALL=C.UTF-8
COPY docker/dev-common.bash /
RUN /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
ARG BUILDARCH
ARG TARGETARCH
LABEL maintainer="slamb@slamb.org"
COPY docker/dev.bash /
RUN /dev.bash
USER moonfire-nvr:moonfire-nvr
WORKDIR /var/lib/moonfire-nvr
CMD [ "/bin/bash", "--login" ]
# Build the webpack with node_modules and ui-dist outside the src dir.
FROM dev AS build-webpack
# Build the UI with node_modules and ui-dist outside the src dir.
FROM --platform=$BUILDPLATFORM dev-common AS build-ui
LABEL maintainer="slamb@slamb.org"
RUN --mount=type=bind,target=/var/lib/moonfire-nvr/src,readonly \
ln -s src/package.json src/yarn.lock src/ui-src src/webpack . && \
yarn install && yarn build && rm -rf node_modules
WORKDIR /var/lib/moonfire-nvr/src/ui
COPY ui /var/lib/moonfire-nvr/src/ui
RUN --mount=type=cache,target=/var/lib/moonfire-nvr/src/ui/node_modules,sharing=locked,mode=1777 \
yarn install && yarn build
# Build the Rust components. Note that dev.sh set up an environment variable
# in .buildrc that similarly changes the target dir path.
FROM dev AS build-server
FROM --platform=$BUILDPLATFORM dev AS build-server
LABEL maintainer="slamb@slamb.org"
RUN --mount=type=bind,target=/var/lib/moonfire-nvr/src,readonly \
bash -c 'set -o xtrace && source ~/.buildrc && cd src && cargo test && cargo build --release'
RUN --mount=type=cache,id=target,target=/var/lib/moonfire-nvr/target,sharing=locked,mode=1777 \
--mount=type=bind,source=server,target=/var/lib/moonfire-nvr/src/server,readonly \
bash -c 'set -o xtrace && \
source ~/.buildrc && \
cd src/server && \
cargo test && \
cargo build --release && \
sudo install -m 755 ~/moonfire-nvr /usr/local/bin/moonfire-nvr'
# Deployment environment, now in the target platform.
FROM --platform=$TARGETPLATFORM ubuntu:20.04 AS deploy
ARG DEPLOY_UID=10000
ARG DEPLOY_GID=10000
LABEL maintainer="slamb@slamb.org"
ENV LC_ALL=C.UTF-8
RUN export DEBIAN_FRONTEND=noninteractive && \
@ -51,21 +63,12 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
vim-nox && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
groupadd \
--gid="${DEPLOY_GID}" \
moonfire-nvr && \
useradd \
--no-log-init \
--home-dir=/var/lib/moonfire-nvr \
--uid="${DEPLOY_UID}" \
--gid=moonfire-nvr \
--shell=/bin/bash \
--create-home \
moonfire-nvr && \
ln -s moonfire-nvr /usr/local/bin/nvr
COPY --from=build-server /var/lib/moonfire-nvr/moonfire-nvr /usr/local/bin/moonfire-nvr
COPY --from=build-webpack /var/lib/moonfire-nvr/ui-dist /usr/local/lib/moonfire-nvr/ui
COPY --from=build-server /usr/local/bin/moonfire-nvr /usr/local/bin/moonfire-nvr
COPY --from=build-ui /var/lib/moonfire-nvr/ui/dist /usr/local/lib/moonfire-nvr/ui
USER moonfire-nvr:moonfire-nvr
# 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" ]

68
docker/dev-common.bash Executable file
View File

@ -0,0 +1,68 @@
#!/bin/bash
# Build the "dev" target. See Dockerfile.
set -o errexit
set -o pipefail
set -o xtrace
export DEBIAN_FRONTEND=noninteractive
packages=()
apt-get update
# Add yarn repository.
apt-get --assume-yes --no-install-recommends install curl gnupg ca-certificates
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" \
>> /etc/apt/sources.list.d/yarn.list
# Install all packages necessary for building (and some for testing/debugging).
packages+=(
build-essential
pkgconf
locales
nodejs
sudo
sqlite3
tzdata
vim-nox
yarn
)
apt-get update
apt-get install --assume-yes --no-install-recommends "${packages[@]}"
apt-get clean
rm -rf /var/lib/apt/lists/*
# 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.
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

View File

@ -1,4 +1,5 @@
#!/bin/bash
# Build the "dev" target. See Dockerfile.
set -o errexit
set -o pipefail
@ -64,68 +65,20 @@ fi
apt-get update
# Add yarn repository.
apt-get --assume-yes --no-install-recommends install curl gnupg ca-certificates
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" \
>> /etc/apt/sources.list.d/yarn.list
# Install all packages necessary for building (and some for testing/debugging).
# Install the packages for the target architecture.
packages+=(
build-essential
pkgconf
ffmpeg"${apt_target_suffix}"
libavcodec-dev"${apt_target_suffix}"
libavformat-dev"${apt_target_suffix}"
libavutil-dev"${apt_target_suffix}"
libncurses-dev"${apt_target_suffix}"
libsqlite3-dev"${apt_target_suffix}"
locales
nodejs
sudo
sqlite3
tzdata
vim-nox
yarn
)
apt-get update
apt-get install --assume-yes --no-install-recommends "${packages[@]}"
apt-get clean
rm -rf /var/lib/apt/lists/*
# 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.
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
# Set environment variables for cross-compiling.
# Also set up a symlink that points to the release binary, because the
# release binary's location varies when cross-compiling, as described here:

View File

@ -84,10 +84,6 @@ caveats:
$ docker buildx build --load --platform=arm64/v8 ...
```
Major caveat: something appears to be making `docker buildx build` frequently
redo builds rather than reusing cached results. The author is very annoyed by
this and would welcome help in understanding this problem...
## Non-Docker setup
You may prefer building without Docker on the host. Moonfire NVR should run
@ -148,13 +144,15 @@ Once prerequisites are installed, you can build the server and find it in
`target/release/moonfire-nvr`:
```
$ cd server
$ cargo test
$ cargo build --release
```
You can build the UI via `yarn` and find it in the `ui-dist` directory:
You can build the UI via `yarn` and find it in the `ui/dist` directory:
```
$ cd ui
$ yarn
$ yarn build
```

View File

@ -20,6 +20,7 @@ this in the webpack documentation.
Checkout the branch you want to work on and type
$ cd ui
$ yarn start
This will pack and prepare a development setup. By default the development

View File

View File

@ -10,7 +10,7 @@
"scripts": {
"start": "webpack-dev-server --mode development --config webpack/dev.config.js --progress",
"build": "webpack --mode production --config webpack/prod.config.js",
"lint": "eslint ui-src"
"lint": "eslint src"
},
"dependencies": {
"jquery": "^3.2.1",
@ -45,3 +45,4 @@
"webpack-merge": "^4.2.2"
}
}

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -37,11 +37,11 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
nvr: './ui-src/index.js',
nvr: './src/index.js',
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve('./ui-dist/'),
path: path.resolve('./dist/'),
publicPath: '/',
},
module: {
@ -60,7 +60,7 @@ module.exports = {
],
},
exclude: /(node_modules|bower_components)/,
include: [path.resolve('./ui-src')],
include: [path.resolve('./src')],
},
{
test: /\.png$/,
@ -83,7 +83,7 @@ module.exports = {
plugins: [
new webpack.IgnorePlugin(/\.\/locale$/),
new HtmlWebpackPlugin({
template: './ui-src/index.html',
template: './src/index.html',
}),
new webpack.NormalModuleReplacementPlugin(
/node_modules\/moment\/moment\.js$/,
@ -94,7 +94,7 @@ module.exports = {
'./builds/moment-timezone-with-data-2012-2022.min.js'
),
new FaviconsWebpackPlugin({
logo: './ui-src/favicon.svg',
logo: './src/favicon.svg',
mode: 'webapp',
devMode: 'light',
prefix: 'favicons-[hash]/',