diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..1a3a1f69c7e5 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,37 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.205.1/containers/typescript-node +{ + "name": "Node.js & TypeScript", + "build": { + "dockerfile": "../docker-dev-env/Dockerfile", + // Update 'VARIANT' to pick a Node version: 16, 14, 12. + // Append -bullseye or -buster to pin to an OS version. + // Use -bullseye variants on local on arm64/Apple Silicon. + "args": { + "VARIANT": "16-bullseye", + } + }, + + // Set *default* container specific settings.json values on container create. + "settings": {}, + + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "dbaeumer.vscode-eslint" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + "initializeCommand": "cp ./shell.nix docker-dev-env/ && cp ./release.nix docker-dev-env/", + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "sudo bash -c 'nix-daemon &' && echo 'eval \"$(direnv hook bash)\"' > ~/.bashrc && echo \"use nix\" > .envrc && direnv allow", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "features": { + "git": "os-provided", + } +} diff --git a/.gitignore b/.gitignore index ef6ef70f6e09..600d044c6792 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,8 @@ utopia-db # Nix builds. server-build-result + +# Docker Dev Environment +docker-dev-env/*.nix +docker-dev-env/.cache +.pnpm-store diff --git a/docker-dev-env/.direnvrc b/docker-dev-env/.direnvrc new file mode 100644 index 000000000000..754c4fadd960 --- /dev/null +++ b/docker-dev-env/.direnvrc @@ -0,0 +1,62 @@ +use_nix() { + local path="$(nix-instantiate --find-file nixpkgs)" + + if [ -f "${path}/.version-suffix" ]; then + local version="$(< $path/.version-suffix)" + elif [ -f "${path}/.git" ]; then + local version="$(< $(< ${path}/.git/HEAD))" + fi + + local cache=".direnv/cache-${version:-unknown}" + + local update_drv=0 + if [[ ! -e "$cache" ]] || \ + [[ "$HOME/.direnvrc" -nt "$cache" ]] || \ + [[ .envrc -nt "$cache" ]] || \ + [[ default.nix -nt "$cache" ]] || \ + [[ shell.nix -nt "$cache" ]]; + then + [ -d .direnv ] || mkdir .direnv + sudo nix-shell --show-trace --pure "$@" --run "\"$direnv\" dump bash" > "$cache" + update_drv=1 + else + log_status using cached derivation + fi + local term_backup=$TERM path_backup=$PATH home_backup=$HOME + if [ -n ${TMPDIR+x} ]; then + local tmp_backup=$TMPDIR + fi + + eval "$(< $cache)" + export PATH=$PATH:$path_backup TERM=$term_backup TMPDIR=$tmp_backup HOME=$home_backup + if [ -n ${tmp_backup+x} ]; then + export TMPDIR=${tmp_backup} + else + unset TMPDIR + fi + + # `nix-shell --pure` sets invalid ssl certificate paths + if [ "${SSL_CERT_FILE:-}" = /no-cert-file.crt ]; then + unset SSL_CERT_FILE + fi + if [ "${NIX_SSL_CERT_FILE:-}" = /no-cert-file.crt ]; then + unset NIX_SSL_CERT_FILE + fi + + # This part is based on https://discourse.nixos.org/t/what-is-the-best-dev-workflow-around-nix-shell/418/4 + if [ "$out" ] && (( $update_drv )); then + local drv_link=".direnv/drv" + local drv="$(nix show-derivation $out | grep -E -o -m1 '/nix/store/.*.drv')" + local stripped_pwd=${PWD/\//} + local escaped_pwd=${stripped_pwd//-/--} + local escaped_pwd=${escaped_pwd//\//-} + ln -fs "$drv" "$drv_link" + ln -fs "$PWD/$drv_link" "/nix/var/nix/gcroots/per-user/$LOGNAME/$escaped_pwd" + log_status renewed cache and derivation link + fi + + if [[ $# = 0 ]]; then + watch_file default.nix + watch_file shell.nix + fi +} \ No newline at end of file diff --git a/docker-dev-env/.dockerignore b/docker-dev-env/.dockerignore new file mode 100644 index 000000000000..16d3c4dbbfec --- /dev/null +++ b/docker-dev-env/.dockerignore @@ -0,0 +1 @@ +.cache diff --git a/docker-dev-env/Dockerfile b/docker-dev-env/Dockerfile new file mode 100644 index 000000000000..9f4cef68f042 --- /dev/null +++ b/docker-dev-env/Dockerfile @@ -0,0 +1,44 @@ +FROM mcr.microsoft.com/vscode/devcontainers/base:hirsute + +# RUN set -ex && apk --no-cache add sudo chromium +RUN apt-get update +RUN apt-get install --no-install-recommends -y nix-bin + + +# I commented this out && sudo chown $DOCKER_USER /nix +RUN sudo mkdir -m 0755 /nix && sudo mkdir -p /etc/nix && sudo groupadd -r nixbld \ + && for n in $(seq 1 10); do sudo useradd -c "Nix build user $n" -d /var/empty -g nixbld -G nixbld -M -N -r -s "$(command -v nologin)" "nixbld$n"; done + +RUN echo 'filter-syscalls = false' >> /etc/nix/nix.conf +RUN nix-channel --add https://nixos.org/channels/nixos-21.05 nixpkgs +RUN nix-channel --update + +# Attempt to get the nix dependencies of the shell cached into a Docker layer. +RUN mkdir -p /root/.nix-tmp +WORKDIR /root/.nix-tmp +ADD shell.nix /root/.nix-tmp/shell.nix +ADD release.nix /root/.nix-tmp/release.nix +RUN nix-shell --run "exit" + +EXPOSE 8000 + +RUN chmod -R o+rwx /root/ + +RUN mkdir -p /root/.cabal/ +VOLUME /root/.cabal/ + +# This is for jest. +ENV CHROME_BIN=chromium-browser + +RUN apt-get install --no-install-recommends -y locales +ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' +RUN locale-gen en_US.UTF-8 +RUN dpkg-reconfigure locales +# RUN update-locale LANG='en_US.UTF-8' + +# install Direnv for the vscodeuser user +RUN apt-get install --no-install-recommends -y direnv +ADD .direnvrc /home/vscode/.direnvrc + +RUN echo 'export TMPDIR=/tmp' > ~/.bashrc +RUN echo 'export TMPDIR=/tmp' > /home/$DOCKER_USER/.bashrc diff --git a/run-docker-dev.sh b/run-docker-dev.sh new file mode 100755 index 000000000000..d553b71796ce --- /dev/null +++ b/run-docker-dev.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -e + +PROJECT_ROOT=`git rev-parse --show-toplevel` +DOCKER_DEV_ENV_DIR=$PROJECT_ROOT/docker-dev-env +DOCKER_CACHE_DIR=$DOCKER_DEV_ENV_DIR/.cache +CABAL_CACHE_DIR=$DOCKER_CACHE_DIR/.cabal +DOCKER_USER=`whoami` +DOCKER_UID=`id -u` + +# Create the cache directories that Docker can use between sessions. +mkdir -p $CABAL_CACHE_DIR + +# Copy the nix files into here so they can be used inside the Dockerfile. +cp $PROJECT_ROOT/shell.nix $DOCKER_DEV_ENV_DIR +cp $PROJECT_ROOT/release.nix $DOCKER_DEV_ENV_DIR + +echo $DOCKER_DEV_ENV_DIR +echo $DOCKER_USER + +# Build the Docker image. +docker build \ + --tag utopia-dev-env \ + --build-arg DOCKER_USER=$DOCKER_USER \ + --build-arg DOCKER_UID=$DOCKER_UID \ + $DOCKER_DEV_ENV_DIR + +# Run a shell within the Docker image produced. +docker run \ + --interactive \ + --tty \ + --publish 8000:8000 \ + --volume $PROJECT_ROOT:/home/utopia/utopia-src \ + --volume $CABAL_CACHE_DIR:/root/.cabal \ + utopia-dev-env \ + nix-shell --run "sudo --preserve-env --user $DOCKER_USER bash" diff --git a/shell.nix b/shell.nix index 2dd4eae353db..992b6f601670 100644 --- a/shell.nix +++ b/shell.nix @@ -442,7 +442,7 @@ let scripts = withCustomDevScripts; # ++ (if needsRelease then releaseScripts else []); - linuxOnlyPackages = lib.optionals stdenv.isLinux [ pkgs.xvfb_run pkgs.x11 pkgs.xorg.libxkbfile ]; + linuxOnlyPackages = lib.optionals stdenv.isLinux [ pkgs.xvfb_run pkgs.x11 pkgs.xorg.libX11 pkgs.xorg.libxkbfile ]; macOSOnlyPackages = lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ Cocoa CoreServices