├── .github ├── CODEOWNERS └── workflows │ ├── build-docker.yml │ ├── pipeline-docker-build.yml │ └── publish-docker.yml ├── Dockerfile ├── Dockerfile.devcontainer ├── Dockerfile.tests.arm ├── README.md └── tools ├── azure_cli_deb_install.sh ├── bashrc-setup.sh ├── install-deps.sh ├── vnc-setup.sh └── xvfb-init.sh /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @electron/wg-releases @electron/wg-upgrades 2 | -------------------------------------------------------------------------------- /.github/workflows/build-docker.yml: -------------------------------------------------------------------------------- 1 | name: Build Docker images 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - main 7 | 8 | jobs: 9 | build-x64: 10 | permissions: 11 | contents: read 12 | packages: write 13 | attestations: write 14 | id-token: write 15 | uses: ./.github/workflows/pipeline-docker-build.yml 16 | with: 17 | docker-name: build 18 | dockerfile: Dockerfile 19 | publish: false 20 | secrets: inherit 21 | build-arm64v8-test: 22 | permissions: 23 | contents: read 24 | packages: write 25 | attestations: write 26 | id-token: write 27 | uses: ./.github/workflows/pipeline-docker-build.yml 28 | with: 29 | docker-name: test 30 | dockerfile: Dockerfile.tests.arm 31 | tag-prefix: arm64v8- 32 | platform: linux/arm64 33 | publish: false 34 | secrets: inherit 35 | build-arm32v7-test: 36 | permissions: 37 | contents: read 38 | packages: write 39 | attestations: write 40 | id-token: write 41 | uses: ./.github/workflows/pipeline-docker-build.yml 42 | with: 43 | docker-name: test 44 | dockerfile: Dockerfile.tests.arm 45 | tag-prefix: arm32v7- 46 | platform: linux/arm 47 | publish: false 48 | secrets: inherit 49 | build-devcontainer: 50 | permissions: 51 | contents: read 52 | packages: write 53 | attestations: write 54 | id-token: write 55 | uses: ./.github/workflows/pipeline-docker-build.yml 56 | with: 57 | docker-name: devcontainer 58 | dockerfile: Dockerfile.devcontainer 59 | publish: false 60 | secrets: inherit 61 | -------------------------------------------------------------------------------- /.github/workflows/pipeline-docker-build.yml: -------------------------------------------------------------------------------- 1 | name: Build and optionally Publish Docker Images 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | docker-name: 7 | description: 'Name of folder in the "docker" directory in this repository' 8 | required: true 9 | type: string 10 | dockerfile: 11 | description: 'Name of the docker file to use' 12 | required: true 13 | type: string 14 | tag-prefix: 15 | type: string 16 | default: '' 17 | platform: 18 | description: 'Docker build platform' 19 | type: string 20 | default: linux/amd64 21 | publish: 22 | description: 'Whether to publish the image as well' 23 | required: true 24 | type: boolean 25 | runs-on: 26 | description: 'Host OS' 27 | default: ubuntu-latest 28 | type: string 29 | 30 | concurrency: 31 | group: build-docker-${{ inputs.docker-name }}-${{ inputs.tag-prefix }} 32 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 33 | 34 | permissions: 35 | contents: read 36 | packages: write 37 | attestations: write 38 | id-token: write 39 | 40 | jobs: 41 | build-image: 42 | runs-on: ${{ inputs.runs-on }} 43 | permissions: 44 | contents: read 45 | packages: write 46 | attestations: write 47 | id-token: write 48 | steps: 49 | - name: Set up QEMU 50 | uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 51 | - name: Checkout repository 52 | uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 53 | - name: Build and push Docker image 54 | id: push 55 | uses: mr-smithers-excellent/docker-build-push@59523c638baec979a74fea99caa9e29d97e5963c # v6.4 56 | with: 57 | dockerfile: ${{ inputs.dockerfile }} 58 | image: ${{ inputs.docker-name }} 59 | tags: ${{ inputs.tag-prefix }}latest, ${{ inputs.tag-prefix }}${{ github.sha }} 60 | platform: ${{ inputs.platform }} 61 | registry: ghcr.io 62 | pushImage: ${{ inputs.publish }} 63 | username: ${{ github.actor }} 64 | password: ${{ secrets.GITHUB_TOKEN }} 65 | -------------------------------------------------------------------------------- /.github/workflows/publish-docker.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish Docker images 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | 10 | publish-x64: 11 | permissions: 12 | contents: read 13 | packages: write 14 | attestations: write 15 | id-token: write 16 | uses: ./.github/workflows/pipeline-docker-build.yml 17 | with: 18 | docker-name: build 19 | dockerfile: Dockerfile 20 | publish: true 21 | secrets: inherit 22 | publish-arm64v8-test: 23 | permissions: 24 | contents: read 25 | packages: write 26 | attestations: write 27 | id-token: write 28 | uses: ./.github/workflows/pipeline-docker-build.yml 29 | with: 30 | docker-name: test 31 | dockerfile: Dockerfile.tests.arm 32 | tag-prefix: arm64v8- 33 | platform: linux/arm64 34 | publish: true 35 | secrets: inherit 36 | publish-arm32v7-test: 37 | permissions: 38 | contents: read 39 | packages: write 40 | attestations: write 41 | id-token: write 42 | uses: ./.github/workflows/pipeline-docker-build.yml 43 | with: 44 | docker-name: test 45 | dockerfile: Dockerfile.tests.arm 46 | tag-prefix: arm32v7- 47 | platform: linux/arm 48 | publish: true 49 | secrets: inherit 50 | publish-devcontainer: 51 | permissions: 52 | contents: read 53 | packages: write 54 | attestations: write 55 | id-token: write 56 | uses: ./.github/workflows/pipeline-docker-build.yml 57 | with: 58 | docker-name: devcontainer 59 | dockerfile: Dockerfile.devcontainer 60 | publish: true 61 | secrets: inherit 62 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN groupadd --gid 999 builduser \ 4 | && useradd --uid 999 --gid builduser --shell /bin/bash --create-home builduser \ 5 | && mkdir -p /setup 6 | 7 | # Set up TEMP directory 8 | ENV TEMP=/tmp 9 | RUN chmod a+rwx /tmp 10 | 11 | # Install Linux packages 12 | ADD tools/install-deps.sh /tmp/ 13 | ADD tools/azure_cli_deb_install.sh /tmp/ 14 | RUN bash /tmp/install-deps.sh --32bit 15 | 16 | # Add xvfb init script 17 | ADD tools/xvfb-init.sh /etc/init.d/xvfb 18 | RUN chmod a+x /etc/init.d/xvfb 19 | 20 | RUN rm -rf /var/lib/apt/lists/* 21 | 22 | USER builduser 23 | WORKDIR /home/builduser 24 | -------------------------------------------------------------------------------- /Dockerfile.devcontainer: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN groupadd --gid 999 builduser \ 4 | && useradd --uid 999 --gid builduser --shell /bin/bash --create-home builduser \ 5 | && mkdir -p /setup 6 | 7 | # Set up TEMP directory 8 | ENV TEMP=/tmp 9 | RUN chmod a+rwx /tmp 10 | 11 | # Install Linux packages 12 | ADD tools/install-deps.sh /tmp/ 13 | ADD tools/azure_cli_deb_install.sh /tmp/ 14 | RUN bash /tmp/install-deps.sh 15 | 16 | # Add xvfb init script 17 | ADD tools/xvfb-init.sh /etc/init.d/xvfb 18 | RUN chmod a+x /etc/init.d/xvfb 19 | 20 | USER builduser 21 | WORKDIR /home/builduser 22 | 23 | # Configure build-tools 24 | RUN rm -rf /home/builduser/.electron_build_tools && \ 25 | git clone https://github.com/electron/build-tools.git /home/builduser/.electron_build_tools && \ 26 | cd /home/builduser/.electron_build_tools && \ 27 | npx --yes yarn && \ 28 | sudo locale-gen "en_US.UTF-8" 29 | 30 | # Configure VNC 31 | COPY tools/vnc-setup.sh /tmp/library-scripts/ 32 | RUN sudo apt update && export DEBIAN_FRONTEND=noninteractive \ 33 | && sudo bash /tmp/library-scripts/vnc-setup.sh \ 34 | && sudo add-apt-repository ppa:mozillateam/ppa \ 35 | && sudo apt -y install firefox-esr \ 36 | && sudo apt clean -y && sudo rm -rf /var/lib/apt/lists/* /tmp/library-scripts/ 37 | 38 | # Env vars for VNC 39 | ENV DBUS_SESSION_BUS_ADDRESS="autolaunch:" \ 40 | VNC_RESOLUTION="1440x768x16" \ 41 | VNC_DPI="96" \ 42 | VNC_PORT="5901" \ 43 | NOVNC_PORT="6080" \ 44 | DISPLAY=":1" \ 45 | LANG="en_US.UTF-8" \ 46 | LANGUAGE="en_US.UTF-8" 47 | 48 | COPY tools/bashrc-setup.sh /tmp/library-scripts/ 49 | RUN bash /tmp/library-scripts/bashrc-setup.sh 50 | 51 | ENTRYPOINT ["/usr/local/share/desktop-init.sh"] 52 | -------------------------------------------------------------------------------- /Dockerfile.tests.arm: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | LABEL org.opencontainers.image.source https://github.com/electron/build-images 4 | 5 | RUN groupadd --gid 999 builduser \ 6 | && useradd --uid 999 --gid builduser --shell /bin/bash --create-home builduser \ 7 | && mkdir -p /setup 8 | 9 | # Set up TEMP directory 10 | ENV TEMP=/tmp 11 | RUN chmod a+rwx /tmp 12 | 13 | # Install Linux packages 14 | ADD tools/install-deps.sh /tmp/ 15 | ADD tools/azure_cli_deb_install.sh /tmp/ 16 | RUN bash /tmp/install-deps.sh --arm 17 | 18 | # Add xvfb init script 19 | ADD tools/xvfb-init.sh /etc/init.d/xvfb 20 | RUN chmod a+x /etc/init.d/xvfb 21 | 22 | RUN rm -rf /var/lib/apt/lists/* 23 | 24 | USER builduser 25 | WORKDIR /home/builduser 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Electron Build Images 2 | 3 | > Docker containers used to build Electron on Linux 4 | 5 | [![Actions Status](https://github.com/electron/build-images/workflows/Build%20and%20Publish%20Docker%20images/badge.svg)](https://github.com/electron/build-images/actions) 6 | 7 | ## Published Images 8 | 9 | All images are published to the GitHub Container Registry. 10 | 11 | Specific versions of the build image are available under a docker tag equivalent to a git commit SHA. E.g. 12 | 13 | ```bash 14 | docker pull ghcr.io/electron/build:3d8d44d0f15b05bef6149e448f9cc522111847e9 15 | ``` 16 | 17 | ### Linux x64 18 | 19 | ```bash 20 | docker pull ghcr.io/electron/build:latest 21 | ``` 22 | 23 | ### Linux Arm 24 | 25 | This image is used for testing 32 bit Arm builds 26 | 27 | ```bash 28 | docker pull ghcr.io/electron/test:arm32v7-latest 29 | ``` 30 | 31 | ### Linux Arm64 32 | 33 | This image is used for testing 64 bit Arm builds 34 | 35 | ```bash 36 | docker pull ghcr.io/electron/test:arm64v8-latest 37 | ``` 38 | 39 | ### Linux Devcontainer 40 | 41 | This image is used for Electron Codespaces environments or other isolated docker-backed developer environments. It contains additional dependencies like a VNC server that can make testing Electron easier. 42 | 43 | ```bash 44 | docker pull ghcr.io/electron/devcontainer:latest 45 | ``` 46 | -------------------------------------------------------------------------------- /tools/azure_cli_deb_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ####################################################################################################################### 4 | # This script does three fundamental things: # 5 | # 1. Add Microsoft's GPG Key has a trusted source of apt packages. # 6 | # 2. Add Microsoft's repositories as a source for apt packages. # 7 | # 3. Installs the Azure CLI from those repositories. # 8 | # Given the nature of this script, it must be executed with elevated privileges, i.e. with `sudo`. # # # # 9 | # # 10 | # Copied from https://azurecliprod.blob.core.windows.net/$root/deb_install.sh # 11 | ####################################################################################################################### 12 | 13 | set -e 14 | 15 | if [[ $# -ge 1 && $1 == "-y" ]]; then 16 | global_consent=0 17 | else 18 | global_consent=1 19 | fi 20 | 21 | function assert_consent { 22 | if [[ $2 -eq 0 ]]; then 23 | return 0 24 | fi 25 | 26 | echo -n "$1 [Y/n] " 27 | read consent 28 | if [[ ! "${consent}" == "y" && ! "${consent}" == "Y" && ! "${consent}" == "" ]]; then 29 | echo "'${consent}'" 30 | exit 1 31 | fi 32 | } 33 | 34 | global_consent=0 # Artificially giving global consent after review-feedback. Remove this line to enable interactive mode 35 | 36 | setup() { 37 | 38 | assert_consent "Add packages necessary to modify your apt-package sources?" ${global_consent} 39 | set -v 40 | export DEBIAN_FRONTEND=noninteractive 41 | apt-get update 42 | apt-get install --assume-yes --no-install-recommends apt-transport-https ca-certificates curl gnupg lsb-release 43 | set +v 44 | 45 | assert_consent "Add Microsoft as a trusted package signer?" ${global_consent} 46 | set -v 47 | mkdir -p /etc/apt/keyrings 48 | curl -sLS https://packages.microsoft.com/keys/microsoft.asc | 49 | gpg --dearmor > /etc/apt/keyrings/microsoft.gpg 50 | chmod go+r /etc/apt/keyrings/microsoft.gpg 51 | set +v 52 | 53 | assert_consent "Add the Azure CLI Repository to your apt sources?" ${global_consent} 54 | set -v 55 | # Use env var DIST_CODE for the package dist name if provided 56 | if [[ -z $DIST_CODE ]]; then 57 | CLI_REPO=$(lsb_release -cs) 58 | shopt -s nocasematch 59 | ERROR_MSG="Unable to find a package for your system. Please check if an existing package in https://packages.microsoft.com/repos/azure-cli/dists/ can be used in your system and install with the dist name: 'curl -sL https://aka.ms/InstallAzureCLIDeb | sudo DIST_CODE= bash'" 60 | if [[ ! $(curl -sL https://packages.microsoft.com/repos/azure-cli/dists/) =~ $CLI_REPO ]]; then 61 | DIST=$(lsb_release -is) 62 | if [[ $DIST =~ "Ubuntu" ]]; then 63 | CLI_REPO="jammy" 64 | elif [[ $DIST =~ "Debian" ]]; then 65 | CLI_REPO="bookworm" 66 | elif [[ $DIST =~ "LinuxMint" ]]; then 67 | CLI_REPO=$(grep -Po 'UBUNTU_CODENAME=\K.*' /etc/os-release) || true 68 | if [[ -z $CLI_REPO ]]; then 69 | echo "$ERROR_MSG" 70 | exit 1 71 | fi 72 | else 73 | echo "$ERROR_MSG" 74 | exit 1 75 | fi 76 | fi 77 | else 78 | CLI_REPO=$DIST_CODE 79 | if [[ ! $(curl -sL https://packages.microsoft.com/repos/azure-cli/dists/) =~ $CLI_REPO ]]; then 80 | echo "Unable to find an azure-cli package with DIST_CODE=$CLI_REPO in https://packages.microsoft.com/repos/azure-cli/dists/." 81 | exit 1 82 | fi 83 | fi 84 | 85 | if [ -f /etc/apt/sources.list.d/azure-cli.list ]; then 86 | rm /etc/apt/sources.list.d/azure-cli.list 87 | fi 88 | 89 | echo "Types: deb 90 | URIs: https://packages.microsoft.com/repos/azure-cli/ 91 | Suites: ${CLI_REPO} 92 | Components: main 93 | Architectures: $(dpkg --print-architecture) 94 | Signed-by: /etc/apt/keyrings/microsoft.gpg" | tee /etc/apt/sources.list.d/azure-cli.sources 95 | apt-get update 96 | set +v 97 | 98 | assert_consent "Install the Azure CLI?" ${global_consent} 99 | apt-get install --assume-yes azure-cli 100 | 101 | } 102 | 103 | setup # ensure the whole file is downloaded before executing 104 | -------------------------------------------------------------------------------- /tools/bashrc-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo export PATH=\"\$PATH:/home/builduser/.electron_build_tools/src\" >> ~/.bashrc 4 | echo "cd /workspaces/gclient/src/electron" >> ~/.bashrc 5 | echo export LC_ALL=\"en_US.UTF-8\" >> ~/.bashrc 6 | -------------------------------------------------------------------------------- /tools/install-deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | debconf-set-selections 6 | 7 | if [[ "$1" == "--32bit" ]]; then 8 | dpkg --add-architecture i386 9 | fi 10 | apt-get update 11 | 12 | package_list=" 13 | ca-certificates \ 14 | curl \ 15 | file \ 16 | gcc-10 \ 17 | g++-10 \ 18 | gdb \ 19 | gnupg \ 20 | jq \ 21 | libnotify-bin \ 22 | locales \ 23 | lsb-release \ 24 | nano \ 25 | sudo \ 26 | vim-nox \ 27 | wget \ 28 | lsof \ 29 | libasound2 \ 30 | libfuse2 \ 31 | software-properties-common \ 32 | desktop-file-utils \ 33 | xvfb" 34 | 35 | package_list_32bit=" 36 | g++-multilib \ 37 | libgl1:i386 \ 38 | libgtk-3-0:i386 \ 39 | libgdk-pixbuf-2.0-0:i386 \ 40 | libdbus-1-3:i386 41 | libgbm1:i386 \ 42 | libnss3:i386 \ 43 | libcurl4:i386 \ 44 | libasound2:i386" 45 | 46 | package_list_arm=" 47 | unzip \ 48 | libnss3 \ 49 | libatk1.0-0 \ 50 | libatk-bridge2.0-0 \ 51 | libcups2 \ 52 | libgbm1 \ 53 | libgtk-3-0 \ 54 | make \ 55 | build-essential \ 56 | git" 57 | 58 | DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $package_list 59 | if [[ "$1" == "--32bit" ]]; then 60 | DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $package_list_32bit 61 | fi 62 | if [[ "$1" == "--arm" ]]; then 63 | DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends $package_list_arm 64 | fi 65 | 66 | add-apt-repository ppa:git-core/ppa -y && apt-get update 67 | 68 | # Download deps installation files from Chromium 69 | curl https://chromium.googlesource.com/chromium/src/+/HEAD/build/install-build-deps.sh\?format\=TEXT | base64 --decode | cat > /setup/install-build-deps.sh 70 | curl https://chromium.googlesource.com/chromium/src/+/HEAD/build/install-build-deps.py\?format\=TEXT | base64 --decode | cat > /setup/install-build-deps.py 71 | 72 | # Remove snapcraft to avoid issues on docker build 73 | sed -i 's/packages.append("snapcraft")/print("skipping snapcraft")/g' /setup/install-build-deps.py 74 | 75 | # Ensure installation files are executable 76 | chmod +x /setup/install-build-deps.sh 77 | chmod +x /setup/install-build-deps.py 78 | 79 | # Ensure g++ and gcc are linked to the correct version 80 | current_gcc_version=$(g++ -dumpversion | cut -d. -f1) 81 | if [[ "$current_gcc_version" -lt 10 ]]; then 82 | update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 83 | update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 100 84 | 85 | sudo update-alternatives --config gcc 86 | sudo update-alternatives --config g++ 87 | fi 88 | 89 | # No Sudo Prompt 90 | echo 'builduser ALL=NOPASSWD: ALL' >> /etc/sudoers.d/50-builduser 91 | echo 'Defaults env_keep += "DEBIAN_FRONTEND"' >> /etc/sudoers.d/env_keep 92 | 93 | if [[ "$1" == "--32bit" ]]; then 94 | DEBIAN_FRONTEND=noninteractive bash /setup/install-build-deps.sh --syms --no-prompt --no-chromeos-fonts --lib32 --arm --no-nacl 95 | elif [[ "$1" == "--arm" ]]; then 96 | echo Not installing Chromium deps 97 | else 98 | DEBIAN_FRONTEND=noninteractive bash /setup/install-build-deps.sh --syms --no-prompt --no-chromeos-fonts --no-arm --no-nacl 99 | fi 100 | rm -rf /var/lib/apt/lists/* 101 | 102 | # Install Node.js 103 | mkdir -p /etc/apt/keyrings 104 | curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg 105 | NODE_MAJOR=22 106 | echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list 107 | apt-get update 108 | apt-get install nodejs -y 109 | 110 | # Install Yarn 111 | npm i -g yarn 112 | 113 | # dbusmock is needed for Electron tests 114 | apt-get install -y python3-dbusmock 115 | 116 | # Install Azure CLI for use in CI 117 | sudo rm -rf /var/lib/apt/lists/* 118 | /tmp/azure_cli_deb_install.sh 119 | 120 | mkdir /tmp/workspace 121 | chown builduser:builduser /tmp/workspace 122 | -------------------------------------------------------------------------------- /tools/vnc-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | USERNAME="builduser" 4 | VNC_PASSWORD="builduser" 5 | INSTALL_NOVNC="true" 6 | 7 | NOVNC_VERSION=1.2.0 8 | WEBSOCKETIFY_VERSION=0.9.0 9 | 10 | package_list=" 11 | tigervnc-standalone-server \ 12 | tigervnc-common \ 13 | tigervnc-tools \ 14 | fluxbox \ 15 | dbus-x11 \ 16 | x11-utils \ 17 | x11-xserver-utils \ 18 | xdg-utils \ 19 | fbautostart \ 20 | at-spi2-core \ 21 | xterm \ 22 | eterm \ 23 | nautilus\ 24 | mousepad \ 25 | seahorse \ 26 | gnome-icon-theme \ 27 | gnome-keyring \ 28 | libx11-dev \ 29 | libxkbfile-dev \ 30 | libsecret-1-dev \ 31 | libgbm-dev \ 32 | libnotify4 \ 33 | libnss3 \ 34 | libxss1 \ 35 | libasound2 \ 36 | xfonts-base \ 37 | xfonts-terminus \ 38 | fonts-noto \ 39 | fonts-wqy-microhei \ 40 | fonts-droid-fallback \ 41 | htop \ 42 | ncdu \ 43 | curl \ 44 | ca-certificates\ 45 | unzip \ 46 | nano \ 47 | locales" 48 | 49 | set -e 50 | 51 | # Function to run apt-get if needed 52 | apt_get_update_if_needed() 53 | { 54 | if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then 55 | echo "Running apt-get update..." 56 | apt-get update 57 | else 58 | echo "Skipping apt-get update." 59 | fi 60 | } 61 | 62 | # Checks if packages are installed and installs them if not 63 | check_packages() { 64 | if ! dpkg -s "$@" > /dev/null 2>&1; then 65 | apt_get_update_if_needed 66 | apt-get -y install --no-install-recommends "$@" 67 | fi 68 | } 69 | 70 | # Ensure apt is in non-interactive to avoid prompts 71 | export DEBIAN_FRONTEND=noninteractive 72 | 73 | apt_get_update_if_needed 74 | 75 | # On older Ubuntu, Tilix is in a PPA. on Debian strech its in backports. 76 | if [[ -z $(apt-cache --names-only search ^tilix$) ]]; then 77 | . /etc/os-release 78 | if [ "${ID}" = "ubuntu" ]; then 79 | apt-get install -y --no-install-recommends apt-transport-https software-properties-common 80 | add-apt-repository -y ppa:webupd8team/terminix 81 | elif [ "${VERSION_CODENAME}" = "stretch" ]; then 82 | echo "deb http://deb.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/stretch-backports.list 83 | fi 84 | apt-get update 85 | if [[ -z $(apt-cache --names-only search ^tilix$) ]]; then 86 | echo "(!) WARNING: Tilix not available on ${ID} ${VERSION_CODENAME} architecture $(uname -m). Skipping." 87 | else 88 | package_list="${package_list} tilix" 89 | fi 90 | fi 91 | 92 | # Install X11, fluxbox and VS Code dependencies 93 | check_packages ${package_list} 94 | 95 | # Install Emoji font if available in distro - Available in Debian 10+, Ubuntu 18.04+ 96 | if dpkg-query -W fonts-noto-color-emoji > /dev/null 2>&1 && ! dpkg -s fonts-noto-color-emoji > /dev/null 2>&1; then 97 | apt-get -y install --no-install-recommends fonts-noto-color-emoji 98 | fi 99 | 100 | # Check at least one locale exists 101 | if ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then 102 | echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen 103 | locale-gen 104 | fi 105 | 106 | # Install the Cascadia Code fonts - https://github.com/microsoft/cascadia-code 107 | if [ ! -d "/usr/share/fonts/truetype/cascadia" ]; then 108 | curl -sSL https://github.com/microsoft/cascadia-code/releases/download/v2008.25/CascadiaCode-2008.25.zip -o /tmp/cascadia-fonts.zip 109 | unzip /tmp/cascadia-fonts.zip -d /tmp/cascadia-fonts 110 | mkdir -p /usr/share/fonts/truetype/cascadia 111 | mv /tmp/cascadia-fonts/ttf/* /usr/share/fonts/truetype/cascadia/ 112 | rm -rf /tmp/cascadia-fonts.zip /tmp/cascadia-fonts 113 | fi 114 | 115 | # Install noVNC 116 | if [ "${INSTALL_NOVNC}" = "true" ] && [ ! -d "/usr/local/novnc" ]; then 117 | mkdir -p /usr/local/novnc 118 | curl -sSL https://github.com/novnc/noVNC/archive/v${NOVNC_VERSION}.zip -o /tmp/novnc-install.zip 119 | unzip /tmp/novnc-install.zip -d /usr/local/novnc 120 | cp /usr/local/novnc/noVNC-${NOVNC_VERSION}/vnc.html /usr/local/novnc/noVNC-${NOVNC_VERSION}/index.html 121 | curl -sSL https://github.com/novnc/websockify/archive/v${WEBSOCKETIFY_VERSION}.zip -o /tmp/websockify-install.zip 122 | unzip /tmp/websockify-install.zip -d /usr/local/novnc 123 | ln -s /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION} /usr/local/novnc/noVNC-${NOVNC_VERSION}/utils/websockify 124 | rm -f /tmp/websockify-install.zip /tmp/novnc-install.zip 125 | 126 | novnc_python_package="python-is-python3" 127 | novnc_numpy_package="python3-numpy" 128 | 129 | if ! dpkg -s ${novnc_python_package} ${novnc_numpy_package} > /dev/null 2>&1; then 130 | apt-get -y install --no-install-recommends ${novnc_python_package} ${novnc_numpy_package} 131 | fi 132 | sed -i -E 's/^python /python2 /' /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION}/run 133 | fi 134 | 135 | # Set up folders for scripts and init files 136 | mkdir -p /var/run/dbus /usr/local/etc/electron-dev-containers/ /root/.fluxbox 137 | 138 | # Script to change resolution of desktop 139 | tee /usr/local/bin/set-resolution > /dev/null \ 140 | << EOF 141 | #!/bin/bash 142 | RESOLUTION=\${1:-\${VNC_RESOLUTION:-1920x1080}} 143 | DPI=\${2:-\${VNC_DPI:-96}} 144 | IGNORE_ERROR=\${3:-"false"} 145 | if [ -z "\$1" ]; then 146 | echo -e "**Current Settings **\n" 147 | xrandr 148 | echo -n -e "\nEnter new resolution (WIDTHxHEIGHT, blank for \${RESOLUTION}, Ctrl+C to abort).\n> " 149 | read NEW_RES 150 | if [ "\${NEW_RES}" != "" ]; then 151 | RESOLUTION=\${NEW_RES} 152 | fi 153 | if ! echo "\${RESOLUTION}" | grep -E '[0-9]+x[0-9]+' > /dev/null; then 154 | echo -e "\nInvalid resolution format!\n" 155 | exit 1 156 | fi 157 | if [ -z "\$2" ]; then 158 | echo -n -e "\nEnter new DPI (blank for \${DPI}, Ctrl+C to abort).\n> " 159 | read NEW_DPI 160 | if [ "\${NEW_DPI}" != "" ]; then 161 | DPI=\${NEW_DPI} 162 | fi 163 | fi 164 | fi 165 | 166 | xrandr --fb \${RESOLUTION} --dpi \${DPI} > /dev/null 2>&1 167 | 168 | if [ \$? -ne 0 ] && [ "\${IGNORE_ERROR}" != "true" ]; then 169 | echo -e "\nFAILED TO SET RESOLUTION!\n" 170 | exit 1 171 | fi 172 | 173 | echo -e "\nSuccess!\n" 174 | EOF 175 | 176 | # Container ENTRYPOINT script 177 | tee /usr/local/share/desktop-init.sh > /dev/null \ 178 | << EOF 179 | #!/bin/bash 180 | 181 | USERNAME=${USERNAME} 182 | LOG=/tmp/container-init.log 183 | 184 | # Execute the command it not already running 185 | startInBackgroundIfNotRunning() 186 | { 187 | log "Starting \$1." 188 | echo -e "\n** \$(date) **" | sudoIf tee -a /tmp/\$1.log > /dev/null 189 | if ! pidof \$1 > /dev/null; then 190 | keepRunningInBackground "\$@" 191 | while ! pidof \$1 > /dev/null; do 192 | sleep 1 193 | done 194 | log "\$1 started." 195 | else 196 | echo "\$1 is already running." | sudoIf tee -a /tmp/\$1.log > /dev/null 197 | log "\$1 is already running." 198 | fi 199 | } 200 | 201 | # Keep command running in background 202 | keepRunningInBackground() 203 | { 204 | (\$2 bash -c "while :; do echo [\\\$(date)] Process started.; \$3; echo [\\\$(date)] Process exited!; sleep 5; done 2>&1" | sudoIf tee -a /tmp/\$1.log > /dev/null & echo "\$!" | sudoIf tee /tmp/\$1.pid > /dev/null) 205 | } 206 | 207 | # Use sudo to run as root when required 208 | sudoIf() 209 | { 210 | if [ "\$(id -u)" -ne 0 ]; then 211 | sudo "\$@" 212 | else 213 | "\$@" 214 | fi 215 | } 216 | 217 | # Use sudo to run as non-root user if not already running 218 | sudoUserIf() 219 | { 220 | if [ "\$(id -u)" -eq 0 ] && [ "\${USERNAME}" != "root" ]; then 221 | sudo -u \${USERNAME} "\$@" 222 | else 223 | "\$@" 224 | fi 225 | } 226 | 227 | # Log messages 228 | log() 229 | { 230 | echo -e "[\$(date)] \$@" | sudoIf tee -a \$LOG > /dev/null 231 | } 232 | 233 | log "** SCRIPT START **" 234 | 235 | # Start dbus. 236 | log 'Running "/etc/init.d/dbus start".' 237 | if [ -f "/var/run/dbus/pid" ] && ! pidof dbus-daemon > /dev/null; then 238 | sudoIf rm -f /var/run/dbus/pid 239 | fi 240 | sudoIf /etc/init.d/dbus start 2>&1 | sudoIf tee -a /tmp/dbus-daemon-system.log > /dev/null 241 | while ! pidof dbus-daemon > /dev/null; do 242 | sleep 1 243 | done 244 | 245 | # Startup tigervnc server and fluxbox 246 | sudo rm -rf /tmp/.X11-unix /tmp/.X*-lock 247 | mkdir -p /tmp/.X11-unix 248 | sudoIf chmod 1777 /tmp/.X11-unix 249 | sudoIf chown root:\${USERNAME} /tmp/.X11-unix 250 | if [ "\$(echo "\${VNC_RESOLUTION}" | tr -cd 'x' | wc -c)" = "1" ]; then VNC_RESOLUTION=\${VNC_RESOLUTION}x16; fi 251 | startInBackgroundIfNotRunning "Xtigervnc" sudoUserIf "tigervncserver -screen \${DISPLAY:-:1} \${VNC_RESOLUTION:-1440x768x16} -rfbport \${VNC_PORT:-5901} -dpi \${VNC_DPI:-96} -localhost -desktop fluxbox -fg -passwd /usr/local/etc/electron-dev-containers/vnc-passwd" 252 | 253 | # Spin up noVNC if installed and not runnning. 254 | if [ -d "/usr/local/novnc" ] && [ "\$(ps -ef | grep /usr/local/novnc/noVNC*/utils/launch.sh | grep -v grep)" = "" ]; then 255 | keepRunningInBackground "noVNC" sudoIf "/usr/local/novnc/noVNC*/utils/launch.sh --listen \${NOVNC_PORT:-6080} --vnc localhost:\${VNC_PORT:-5901}" 256 | log "noVNC started." 257 | else 258 | log "noVNC is already running or not installed." 259 | fi 260 | 261 | # Run whatever was passed in 262 | log "Executing \"\$@\"." 263 | exec "\$@" 264 | log "** SCRIPT EXIT **" 265 | EOF 266 | 267 | echo "${VNC_PASSWORD}" | vncpasswd -f > /usr/local/etc/electron-dev-containers/vnc-passwd 268 | touch /root/.Xmodmap 269 | chmod +x /usr/local/share/desktop-init.sh /usr/local/bin/set-resolution 270 | 271 | tee /root/.fluxbox/apps > /dev/null \ 272 | < /dev/null \ 280 | < /dev/null \ 294 | < 297 | [exec] (Text Editor) { mousepad } <> 298 | [exec] (Terminal) { tilix -w ~ -e $(readlink -f /proc/$$/exe) -il } <> 299 | [exec] (Web Browser) { x-www-browser --disable-dev-shm-usage } <> 300 | [submenu] (System) {} 301 | [exec] (Set Resolution) { tilix -t "Set Resolution" -e bash /usr/local/bin/set-resolution } <> 302 | [exec] (Edit Application Menu) { mousepad ~/.fluxbox/menu } <> 303 | [exec] (Passwords and Keys) { seahorse } <> 304 | [exec] (Top Processes) { tilix -t "Top" -e htop } <> 305 | [exec] (Disk Utilization) { tilix -t "Disk Utilization" -e ncdu / } <> 306 | [exec] (Editres) {editres} <> 307 | [exec] (Xfontsel) {xfontsel} <> 308 | [exec] (Xkill) {xkill} <> 309 | [exec] (Xrefresh) {xrefresh} <> 310 | [end] 311 | [config] (Configuration) 312 | [workspaces] (Workspaces) 313 | [end] 314 | EOF 315 | 316 | # Set up vnc user 317 | touch /home/${USERNAME}/.Xmodmap 318 | cp -R /root/.fluxbox /home/${USERNAME} 319 | chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/.Xmodmap /home/${USERNAME}/.fluxbox 320 | chown ${USERNAME}:root /usr/local/share/desktop-init.sh /usr/local/bin/set-resolution /usr/local/etc/electron-dev-containers/vnc-passwd 321 | 322 | echo "Done!" 323 | -------------------------------------------------------------------------------- /tools/xvfb-init.sh: -------------------------------------------------------------------------------- 1 | XVFB=/usr/bin/Xvfb 2 | XVFBARGS="$DISPLAY -ac -screen 0 1024x768x16 +extension RANDR" 3 | /sbin/start-stop-daemon --start --quiet --background --exec $XVFB -- $XVFBARGS 4 | --------------------------------------------------------------------------------