├── .github ├── FUNDING.yml └── workflows │ ├── dev.yml │ ├── release.md │ └── release.yml ├── .gitignore ├── Gemfile ├── README.md ├── bin ├── cli.rb ├── cli_handler.rb ├── dockerfile_data.rb └── filegen ├── build.sh ├── build ├── arm-none-eabi-plugins │ ├── assets │ │ ├── .gitkeep │ │ └── shell │ │ │ └── .gitkeep │ └── docker │ │ └── .gitkeep ├── arm-none-eabi │ ├── assets │ │ ├── .gitkeep │ │ └── shell │ │ │ └── .gitkeep │ ├── contents.yml │ ├── docker │ │ └── .gitkeep │ └── packages.yml ├── base │ ├── Dockerfile-assets │ ├── Dockerfile-build │ ├── assets │ │ ├── gems │ │ │ ├── Gemfile │ │ │ └── ceedling-1.0.1.gem │ │ └── shell │ │ │ ├── zshrc-dev │ │ │ └── zshrc-root │ ├── contents.yml │ ├── packages.yml │ └── templates │ │ ├── Dockerfile.erb │ │ └── welcome.erb ├── plugins │ ├── Dockerfile-assets │ ├── Dockerfile-build │ ├── Dockerfile-user │ ├── assets │ │ ├── .gitkeep │ │ ├── dotnet │ │ │ └── packages-microsoft-prod.deb │ │ └── shell │ │ │ └── .gitkeep │ ├── contents.yml │ ├── docker │ │ └── .gitkeep │ └── packages.yml └── standard │ ├── Dockerfile-build │ ├── assets │ ├── .gitkeep │ └── shell │ │ └── .gitkeep │ ├── contents.yml │ ├── docker │ └── .gitkeep │ └── packages.yml ├── docs └── SECURITY.md └── license.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ThrowTheSwitch 2 | #patreon: # Replace with a single Patreon username 3 | #open_collective: # Replace with a single Open Collective username 4 | #ko_fi: # Replace with a single Ko-fi username 5 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 6 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 7 | #liberapay: # Replace with a single Liberapay username 8 | #issuehunt: # Replace with a single IssueHunt username 9 | #lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 10 | #polar: # Replace with a single Polar username 11 | #buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 12 | #thanks_dev: # Replace with a single thanks.dev username 13 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: Docker images dev build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - "**" 8 | pull_request: 9 | branches: 10 | - "main" 11 | 12 | env: 13 | IMAGE_ORG: 'throwtheswitch' 14 | IMAGE_BASE_NAME: 'madsciencelab' 15 | 16 | 17 | jobs: 18 | # Jobs organized for concurrent Docker image builds 19 | # Jobs only build :latest images without pushing to Docker Hub 20 | 21 | # This is a workaround to the limitation that an `env:` map cannot reference the `env:` map to create additional environment variables 22 | image-details: 23 | runs-on: ubuntu-latest 24 | steps: 25 | # A step must be present in order to make use of `outputs:` 26 | - run: echo "Setting Docker image details..." 27 | outputs: 28 | base-name: 'madsciencelab' 29 | base-url: 'throwtheswitch/madsciencelab' 30 | 31 | madsciencelab: 32 | runs-on: ubuntu-latest 33 | needs: [image-details] 34 | permissions: 35 | contents: read 36 | packages: write 37 | attestations: write 38 | id-token: write 39 | env: 40 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }} 41 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }} 42 | # Image variant name is drawn from final `--dir` entry in file generation command line 43 | IMAGE_DIR: build/standard 44 | 45 | steps: 46 | - name: 'Set up Ruby for generation tool' 47 | uses: ruby/setup-ruby@v1 48 | with: 49 | ruby-version: '3.3' 50 | bundler-cache: true 51 | 52 | - name: 'Checkout GitHub Action' 53 | uses: actions/checkout@v4 54 | 55 | - name: 'Install file generation Ruby dependencies' 56 | run: bundle install 57 | 58 | - name: 'Run file generation' 59 | id: file-gen 60 | run: bash build.sh --dir ${{ env.IMAGE_DIR }} --version dev 61 | 62 | - name: 'Set up QEMU' 63 | uses: docker/setup-qemu-action@v3 64 | 65 | - name: 'Set up Docker Buildx' 66 | uses: docker/setup-buildx-action@v3 67 | 68 | - name: 'Login to Docker Hub' 69 | if: github.event_name != 'pull_request' 70 | uses: docker/login-action@v3 71 | with: 72 | username: ${{ secrets.DOCKERHUB_USERNAME }} 73 | password: ${{ secrets.DOCKERHUB_TOKEN }} 74 | 75 | # Docker image: madsciencelab 76 | # Note: standard/ directory maps to madsciencelab image (no variants) 77 | - name: 'Build Docker image ${{ env.IMAGE_NAME }}' 78 | uses: docker/build-push-action@v6 79 | with: 80 | platforms: linux/amd64,linux/arm64 81 | context: . 82 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 83 | build-args: | 84 | CONTAINER_VERSION=${{ github.ref_name }} 85 | IMAGE_NAME=${{ env.IMAGE_NAME }} 86 | tags: ${{ env.IMAGE_URL }}:latest 87 | # Connect Docker driver to GitHub Action cache service 88 | cache-from: type=gha 89 | cache-to: type=gha,mode=max 90 | 91 | # Zip generated files as a single artifact 92 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 93 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 94 | 95 | # Upload the zip artifact 96 | - uses: actions/upload-artifact@v4 97 | with: 98 | name: ${{ env.IMAGE_NAME }} 99 | path: ${{ env.IMAGE_NAME }}.zip 100 | if-no-files-found: error 101 | 102 | madsciencelab-plugins: 103 | runs-on: ubuntu-latest 104 | needs: [image-details] 105 | permissions: 106 | contents: read 107 | packages: write 108 | attestations: write 109 | id-token: write 110 | env: 111 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-plugins 112 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-plugins 113 | # Image variant name is drawn from final `--dir` entry in file generation command line 114 | IMAGE_DIR: build/plugins 115 | 116 | steps: 117 | - name: 'Set up Ruby for generation tool' 118 | uses: ruby/setup-ruby@v1 119 | with: 120 | ruby-version: '3.3' 121 | bundler-cache: true 122 | 123 | - name: 'Checkout GitHub Action' 124 | uses: actions/checkout@v4 125 | 126 | - name: 'Install file generation Ruby dependencies' 127 | run: bundle install 128 | 129 | - name: 'Run file generation' 130 | run: bash build.sh --dir build/standard --dir ${{ env.IMAGE_DIR }} --version dev 131 | 132 | - name: 'Set up QEMU' 133 | uses: docker/setup-qemu-action@v3 134 | 135 | - name: 'Set up Docker Buildx' 136 | uses: docker/setup-buildx-action@v3 137 | 138 | - name: 'Login to Docker Hub' 139 | if: github.event_name != 'pull_request' 140 | uses: docker/login-action@v3 141 | with: 142 | username: ${{ secrets.DOCKERHUB_USERNAME }} 143 | password: ${{ secrets.DOCKERHUB_TOKEN }} 144 | 145 | # Docker image: madsciencelab-plugins 146 | - name: 'Build Docker image ${{ env.IMAGE_NAME }}' 147 | uses: docker/build-push-action@v6 148 | with: 149 | platforms: linux/amd64,linux/arm64 150 | context: . 151 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 152 | build-args: | 153 | CONTAINER_VERSION=${{ github.ref_name }} 154 | IMAGE_NAME=${{ env.IMAGE_NAME }} 155 | tags: ${{ env.IMAGE_URL }}:latest 156 | # Connect Docker driver to GitHub Action cache service 157 | cache-from: type=gha 158 | cache-to: type=gha,mode=max 159 | 160 | # Zip generated files as a single artifact 161 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 162 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 163 | 164 | # Upload the zip artifact 165 | - uses: actions/upload-artifact@v4 166 | with: 167 | name: ${{ env.IMAGE_NAME }} 168 | path: ${{ env.IMAGE_NAME }}.zip 169 | if-no-files-found: error 170 | 171 | madsciencelab-arm-none-eabi: 172 | runs-on: ubuntu-latest 173 | needs: [image-details] 174 | permissions: 175 | contents: read 176 | packages: write 177 | attestations: write 178 | id-token: write 179 | env: 180 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-arm-none-eabi 181 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-arm-none-eabi 182 | # Image variant name is drawn from final `--dir` entry in file generation command line 183 | IMAGE_DIR: build/arm-none-eabi 184 | 185 | steps: 186 | - name: 'Set up Ruby for generation tool' 187 | uses: ruby/setup-ruby@v1 188 | with: 189 | ruby-version: '3.3' 190 | bundler-cache: true 191 | 192 | - name: 'Checkout GitHub Action' 193 | uses: actions/checkout@v4 194 | 195 | - name: 'Install file generation Ruby dependencies' 196 | run: bundle install 197 | 198 | - name: 'Run file generation' 199 | run: bash build.sh --dir ${{ env.IMAGE_DIR }} --version dev 200 | 201 | - name: 'Set up QEMU' 202 | uses: docker/setup-qemu-action@v3 203 | 204 | - name: 'Set up Docker Buildx' 205 | uses: docker/setup-buildx-action@v3 206 | 207 | - name: 'Login to Docker Hub' 208 | if: github.event_name != 'pull_request' 209 | uses: docker/login-action@v3 210 | with: 211 | username: ${{ secrets.DOCKERHUB_USERNAME }} 212 | password: ${{ secrets.DOCKERHUB_TOKEN }} 213 | 214 | # Docker image: madsciencelab-arm-none-eabi 215 | - name: 'Build Docker image ${{ env.IMAGE_NAME }}' 216 | uses: docker/build-push-action@v6 217 | with: 218 | platforms: linux/amd64,linux/arm64 219 | context: . 220 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 221 | build-args: | 222 | CONTAINER_VERSION=${{ github.ref_name }} 223 | IMAGE_NAME=${{ env.IMAGE_NAME }} 224 | tags: ${{ env.IMAGE_URL }}:latest 225 | # Connect Docker driver to GitHub Action cache service 226 | cache-from: type=gha 227 | cache-to: type=gha,mode=max 228 | 229 | # Zip generated files as a single artifact 230 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 231 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 232 | 233 | # Upload the zip artifact 234 | - uses: actions/upload-artifact@v4 235 | with: 236 | name: ${{ env.IMAGE_NAME }} 237 | path: ${{ env.IMAGE_NAME }}.zip 238 | if-no-files-found: error 239 | 240 | madsciencelab-arm-none-eabi-plugins: 241 | runs-on: ubuntu-latest 242 | needs: [image-details] 243 | permissions: 244 | contents: read 245 | packages: write 246 | attestations: write 247 | id-token: write 248 | env: 249 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-arm-none-eabi-plugins 250 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-arm-none-eabi-plugins 251 | # Image variant name is drawn from final `--dir` entry in file generation command line 252 | IMAGE_DIR: build/arm-none-eabi-plugins 253 | 254 | steps: 255 | - name: 'Set up Ruby for generation tool' 256 | uses: ruby/setup-ruby@v1 257 | with: 258 | ruby-version: '3.3' 259 | bundler-cache: true 260 | 261 | - name: 'Checkout GitHub Action' 262 | uses: actions/checkout@v4 263 | 264 | - name: 'Install file generation Ruby dependencies' 265 | run: bundle install 266 | 267 | - name: 'Run file generation' 268 | run: bash build.sh --dir build/arm-none-eabi --dir build/plugins --dir ${{ env.IMAGE_DIR }} --version dev 269 | 270 | - name: 'Set up QEMU' 271 | uses: docker/setup-qemu-action@v3 272 | 273 | - name: 'Set up Docker Buildx' 274 | uses: docker/setup-buildx-action@v3 275 | 276 | - name: 'Login to Docker Hub' 277 | if: github.event_name != 'pull_request' 278 | uses: docker/login-action@v3 279 | with: 280 | username: ${{ secrets.DOCKERHUB_USERNAME }} 281 | password: ${{ secrets.DOCKERHUB_TOKEN }} 282 | 283 | # Docker image: madsciencelab-arm-none-eabi-plugins 284 | - name: 'Build Docker image ${{ env.IMAGE_NAME }}' 285 | uses: docker/build-push-action@v6 286 | with: 287 | platforms: linux/amd64,linux/arm64 288 | context: . 289 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 290 | build-args: | 291 | CONTAINER_VERSION=${{ github.ref_name }} 292 | IMAGE_NAME=${{ env.IMAGE_NAME }} 293 | tags: ${{ env.IMAGE_URL }}:latest 294 | # Connect Docker driver to GitHub Action cache service 295 | cache-from: type=gha 296 | cache-to: type=gha,mode=max 297 | 298 | # Zip generated files as a single artifact 299 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 300 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 301 | 302 | # Upload the zip artifact 303 | - uses: actions/upload-artifact@v4 304 | with: 305 | name: ${{ env.IMAGE_NAME }} 306 | path: ${{ env.IMAGE_NAME }}.zip 307 | if-no-files-found: error 308 | 309 | # After all Docker image builds, collect results and publish a pre-release 310 | artifacts-dev-build: 311 | runs-on: ubuntu-latest 312 | needs: 313 | - madsciencelab 314 | - madsciencelab-plugins 315 | - madsciencelab-arm-none-eabi 316 | - madsciencelab-arm-none-eabi-plugins 317 | permissions: 318 | contents: write 319 | 320 | steps: 321 | # Get the repo so we have info for generating release details 322 | - name: 'Checkout GitHub Action' 323 | uses: actions/checkout@v4 324 | 325 | # Download all artifacts from the 4 Docker image builds 326 | - uses: actions/download-artifact@v4 327 | with: 328 | # `pattern:` is a workaround to an artifact upload incompatibility with docker/build-push-action@v6 329 | # Otherwise, apart from this bug requiring `pattern:` the default of all artifacts would occur without any intervention 330 | # https://github.com/docker/build-push-action/issues/1167 331 | pattern: "madsciencelab*" 332 | path: artifacts 333 | 334 | # Capture the SHA string 335 | - name: 'Git commit short SHA as environment variable' 336 | shell: bash 337 | run: | 338 | echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 339 | 340 | - uses: ncipollo/release-action@v1 341 | with: 342 | prerelease: true 343 | allowUpdates: true 344 | bodyFile: .github/workflows/release.md 345 | commit: ${{ github.sha }} 346 | tag: ${{ env.SHA_SHORT }} 347 | name: Dev Build ${{ env.SHA_SHORT }} 348 | artifacts: "artifacts/*/*.zip" 349 | -------------------------------------------------------------------------------- /.github/workflows/release.md: -------------------------------------------------------------------------------- 1 | ## MadScienceLab Docker Images Builds 2 | 3 | Each build produces multiple variants of the `throwtheswitch/madsciencelab` Docker images containing [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) and its supporting frameworks as well as various utilities and compilation toolchains. Each image built from this repository targets multiple runtime host platforms. 4 | 5 | Build types (via Github Actions): 6 | 7 | 1. A dev build of this repository generates files and validates the Docker image build. 8 | 1. A release build adds to (1) by also pushing the resulting Docker images to Docker Hub. 9 | 10 | See the [Docker Hub repository](https://hub.docker.com/r/throwtheswitch) for official releases of the resulting Docker images and their documentation. 11 | 12 | Versioning of this repository and the resulting tags in Docker Hub tracks Ceedling’s version. Docker image changes are maintained with a lowercase letter suffix appended to the version of Ceedling contained in each image itself. 13 | 14 | ## Build Artifacts 15 | 16 | * A zip archive for each Docker image containing the generated Dockerfile and any other generated file artifacts used to build the image in Docker Hub. 17 | * A zip archive of the entire project including the static assets used to build the Docker images. 18 | 19 | See this reository’s documentation for instructions on how to use the tools of this repository and how to manually build the Docker images this repository maintains. 20 | 21 | ## Changelog 22 | 23 | ### Added 24 | 25 | * ... 26 | 27 | ### Fixed 28 | 29 | * ... 30 | 31 | ### Changed 32 | 33 | * ... 34 | 35 | ### Removed 36 | 37 | * ... 38 | 39 | 40 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Docker images release build + Docker Hub push 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - '*' 8 | 9 | env: 10 | IMAGE_ORG: 'throwtheswitch' 11 | IMAGE_BASE_NAME: 'madsciencelab' 12 | 13 | 14 | jobs: 15 | # Jobs organized for concurrent Docker image builds 16 | # Jobs build tagged and :latest images and push to Docker Hub 17 | 18 | # This is a workaround to the limitation that an `env:` map cannot reference the `env:` map to create additional environment variables 19 | image-details: 20 | runs-on: ubuntu-latest 21 | steps: 22 | # A step must be present in order to make use of `outputs:` 23 | - run: echo "Setting Docker image details..." 24 | outputs: 25 | base-name: 'madsciencelab' 26 | base-url: 'throwtheswitch/madsciencelab' 27 | 28 | madsciencelab: 29 | runs-on: ubuntu-latest 30 | needs: [image-details] 31 | permissions: 32 | contents: read 33 | packages: write 34 | attestations: write 35 | id-token: write 36 | env: 37 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }} 38 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }} 39 | # Image variant name is drawn from final `--dir` entry in file generation command line 40 | IMAGE_DIR: build/standard 41 | 42 | steps: 43 | - name: 'Set up Ruby for generation tool' 44 | uses: ruby/setup-ruby@v1 45 | with: 46 | ruby-version: '3.3' 47 | bundler-cache: true 48 | 49 | - name: 'Checkout GitHub Action' 50 | uses: actions/checkout@v4 51 | 52 | - name: 'Install file generation Ruby dependencies' 53 | run: bundle install 54 | 55 | - name: 'Run file generation' 56 | id: file-gen 57 | run: bash build.sh --dir ${{ env.IMAGE_DIR }} --version ${{ github.ref_name }} 58 | 59 | - name: 'Set up QEMU' 60 | uses: docker/setup-qemu-action@v3 61 | 62 | - name: 'Set up Docker Buildx' 63 | uses: docker/setup-buildx-action@v3 64 | 65 | - name: 'Login to Docker Hub' 66 | if: github.event_name != 'pull_request' 67 | uses: docker/login-action@v3 68 | with: 69 | username: ${{ secrets.DOCKERHUB_USERNAME }} 70 | password: ${{ secrets.DOCKERHUB_TOKEN }} 71 | 72 | # Docker image: madsciencelab 73 | # Note: standard/ directory maps to madsciencelab image (no variants) 74 | - name: 'Build and push Docker image ${{ env.IMAGE_NAME }}:${{ github.ref_name }}' 75 | uses: docker/build-push-action@v6 76 | with: 77 | platforms: linux/amd64,linux/arm64 78 | context: . 79 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 80 | build-args: | 81 | CONTAINER_VERSION=${{ github.ref_name }} 82 | IMAGE_NAME=${{ env.IMAGE_NAME }} 83 | push: ${{ github.event_name != 'pull_request' }} 84 | tags: ${{ env.IMAGE_URL }}:${{ github.ref_name }}, ${{ env.IMAGE_URL }}:latest 85 | # Connect Docker driver to GitHub Action cache service 86 | cache-from: type=gha 87 | cache-to: type=gha,mode=max 88 | 89 | # Zip generated files as a single artifact 90 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 91 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 92 | 93 | # Upload the zip artifact 94 | - uses: actions/upload-artifact@v4 95 | with: 96 | name: ${{ env.IMAGE_NAME }} 97 | path: ${{ env.IMAGE_NAME }}.zip 98 | if-no-files-found: error 99 | 100 | madsciencelab-plugins: 101 | runs-on: ubuntu-latest 102 | needs: [image-details] 103 | permissions: 104 | contents: read 105 | packages: write 106 | attestations: write 107 | id-token: write 108 | env: 109 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-plugins 110 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-plugins 111 | # Image variant name is drawn from final `--dir` entry in file generation command line 112 | IMAGE_DIR: build/plugins 113 | 114 | steps: 115 | - name: 'Set up Ruby for generation tool' 116 | uses: ruby/setup-ruby@v1 117 | with: 118 | ruby-version: '3.3' 119 | bundler-cache: true 120 | 121 | - name: 'Checkout GitHub Action' 122 | uses: actions/checkout@v4 123 | 124 | - name: 'Install file generation Ruby dependencies' 125 | run: bundle install 126 | 127 | - name: 'Run file generation' 128 | run: bash build.sh --dir build/standard --dir ${{ env.IMAGE_DIR }} --version ${{ github.ref_name }} 129 | 130 | - name: 'Set up QEMU' 131 | uses: docker/setup-qemu-action@v3 132 | 133 | - name: 'Set up Docker Buildx' 134 | uses: docker/setup-buildx-action@v3 135 | 136 | - name: 'Login to Docker Hub' 137 | if: github.event_name != 'pull_request' 138 | uses: docker/login-action@v3 139 | with: 140 | username: ${{ secrets.DOCKERHUB_USERNAME }} 141 | password: ${{ secrets.DOCKERHUB_TOKEN }} 142 | 143 | # Docker image: madsciencelab-plugins 144 | - name: 'Build and push Docker image ${{ env.IMAGE_NAME }}:${{ github.ref_name }}' 145 | uses: docker/build-push-action@v6 146 | with: 147 | platforms: linux/amd64,linux/arm64 148 | context: . 149 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 150 | build-args: | 151 | CONTAINER_VERSION=${{ github.ref_name }} 152 | IMAGE_NAME=${{ env.IMAGE_NAME }} 153 | push: ${{ github.event_name != 'pull_request' }} 154 | tags: ${{ env.IMAGE_URL }}:${{ github.ref_name }}, ${{ env.IMAGE_URL }}:latest 155 | # Connect Docker driver to GitHub Action cache service 156 | cache-from: type=gha 157 | cache-to: type=gha,mode=max 158 | 159 | # Zip generated files as a single artifact 160 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 161 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 162 | 163 | # Upload the zip artifact 164 | - uses: actions/upload-artifact@v4 165 | with: 166 | name: ${{ env.IMAGE_NAME }} 167 | path: ${{ env.IMAGE_NAME }}.zip 168 | if-no-files-found: error 169 | 170 | madsciencelab-arm-none-eabi: 171 | runs-on: ubuntu-latest 172 | needs: [image-details] 173 | permissions: 174 | contents: read 175 | packages: write 176 | attestations: write 177 | id-token: write 178 | env: 179 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-arm-none-eabi 180 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-arm-none-eabi 181 | # Image variant name is drawn from final `--dir` entry in file generation command line 182 | IMAGE_DIR: build/arm-none-eabi 183 | 184 | steps: 185 | - name: 'Set up Ruby for generation tool' 186 | uses: ruby/setup-ruby@v1 187 | with: 188 | ruby-version: '3.3' 189 | bundler-cache: true 190 | 191 | - name: 'Checkout GitHub Action' 192 | uses: actions/checkout@v4 193 | 194 | - name: 'Install file generation Ruby dependencies' 195 | run: bundle install 196 | 197 | - name: 'Run file generation' 198 | run: bash build.sh --dir ${{ env.IMAGE_DIR }} --version ${{ github.ref_name }} 199 | 200 | - name: 'Set up QEMU' 201 | uses: docker/setup-qemu-action@v3 202 | 203 | - name: 'Set up Docker Buildx' 204 | uses: docker/setup-buildx-action@v3 205 | 206 | - name: 'Login to Docker Hub' 207 | if: github.event_name != 'pull_request' 208 | uses: docker/login-action@v3 209 | with: 210 | username: ${{ secrets.DOCKERHUB_USERNAME }} 211 | password: ${{ secrets.DOCKERHUB_TOKEN }} 212 | 213 | # Docker image: madsciencelab-arm-none-eabi 214 | - name: 'Build and push Docker image ${{ env.IMAGE_NAME }}:${{ github.ref_name }}' 215 | uses: docker/build-push-action@v6 216 | with: 217 | platforms: linux/amd64,linux/arm64 218 | context: . 219 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 220 | build-args: | 221 | CONTAINER_VERSION=${{ github.ref_name }} 222 | IMAGE_NAME=${{ env.IMAGE_NAME }} 223 | push: ${{ github.event_name != 'pull_request' }} 224 | tags: ${{ env.IMAGE_URL }}:${{ github.ref_name }}, ${{ env.IMAGE_URL }}:latest 225 | # Connect Docker driver to GitHub Action cache service 226 | cache-from: type=gha 227 | cache-to: type=gha,mode=max 228 | 229 | # Zip generated files as a single artifact 230 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 231 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 232 | 233 | # Upload the zip artifact 234 | - uses: actions/upload-artifact@v4 235 | with: 236 | name: ${{ env.IMAGE_NAME }} 237 | path: ${{ env.IMAGE_NAME }}.zip 238 | if-no-files-found: error 239 | 240 | madsciencelab-arm-none-eabi-plugins: 241 | runs-on: ubuntu-latest 242 | needs: [image-details] 243 | permissions: 244 | contents: read 245 | packages: write 246 | attestations: write 247 | id-token: write 248 | env: 249 | IMAGE_NAME: ${{ needs.image-details.outputs.base-name }}-arm-none-eabi-plugins 250 | IMAGE_URL: ${{ needs.image-details.outputs.base-url }}-arm-none-eabi-plugins 251 | # Image variant name is drawn from final `--dir` entry in file generation command line 252 | IMAGE_DIR: build/arm-none-eabi-plugins 253 | 254 | steps: 255 | - name: 'Set up Ruby for generation tool' 256 | uses: ruby/setup-ruby@v1 257 | with: 258 | ruby-version: '3.3' 259 | bundler-cache: true 260 | 261 | - name: 'Checkout GitHub Action' 262 | uses: actions/checkout@v4 263 | 264 | - name: 'Install file generation Ruby dependencies' 265 | run: bundle install 266 | 267 | - name: 'Run file generation' 268 | run: bash build.sh --dir build/arm-none-eabi --dir build/plugins --dir ${{ env.IMAGE_DIR }} --version ${{ github.ref_name }} 269 | 270 | - name: 'Set up QEMU' 271 | uses: docker/setup-qemu-action@v3 272 | 273 | - name: 'Set up Docker Buildx' 274 | uses: docker/setup-buildx-action@v3 275 | 276 | - name: 'Login to Docker Hub' 277 | if: github.event_name != 'pull_request' 278 | uses: docker/login-action@v3 279 | with: 280 | username: ${{ secrets.DOCKERHUB_USERNAME }} 281 | password: ${{ secrets.DOCKERHUB_TOKEN }} 282 | 283 | # Docker image: madsciencelab-arm-none-eabi-plugins 284 | - name: 'Build and push Docker image ${{ env.IMAGE_NAME }}:${{ github.ref_name }}' 285 | uses: docker/build-push-action@v6 286 | with: 287 | platforms: linux/amd64,linux/arm64 288 | context: . 289 | file: ${{ env.IMAGE_DIR }}/docker/Dockerfile 290 | build-args: | 291 | CONTAINER_VERSION=${{ github.ref_name }} 292 | IMAGE_NAME=${{ env.IMAGE_NAME }} 293 | push: ${{ github.event_name != 'pull_request' }} 294 | tags: ${{ env.IMAGE_URL }}:${{ github.ref_name }}, ${{ env.IMAGE_URL }}:latest 295 | # Connect Docker driver to GitHub Action cache service 296 | cache-from: type=gha 297 | cache-to: type=gha,mode=max 298 | 299 | # Zip generated files as a single artifact 300 | - name: 'Archive ${{ env.IMAGE_NAME }} generated files as a single artifact' 301 | run: zip -j ${{ env.IMAGE_NAME }}.zip ${{ env.IMAGE_DIR }}/docker/Dockerfile ${{ env.IMAGE_DIR }}/assets/shell/welcome 302 | 303 | # Upload the zip artifact 304 | - uses: actions/upload-artifact@v4 305 | with: 306 | name: ${{ env.IMAGE_NAME }} 307 | path: ${{ env.IMAGE_NAME }}.zip 308 | if-no-files-found: error 309 | 310 | artifacts-release: 311 | runs-on: ubuntu-latest 312 | needs: 313 | - madsciencelab 314 | - madsciencelab-plugins 315 | - madsciencelab-arm-none-eabi 316 | - madsciencelab-arm-none-eabi-plugins 317 | permissions: 318 | contents: write 319 | 320 | steps: 321 | # Get the repo so we have info for generating release details 322 | - name: 'Checkout GitHub Action' 323 | uses: actions/checkout@v4 324 | 325 | # Download all artifacts from the 4 Docker image builds 326 | - uses: actions/download-artifact@v4 327 | with: 328 | # `pattern:` is a workaround to an artifact upload incompatibility with docker/build-push-action@v6 329 | # Otherwise, apart from this bug requiring `pattern:` the default of all artifacts would occur without any intervention 330 | # https://github.com/docker/build-push-action/issues/1167 331 | pattern: "madsciencelab*" 332 | path: artifacts 333 | 334 | # Capture the SHA string 335 | - name: 'Git commit short SHA as environment variable' 336 | shell: bash 337 | run: | 338 | echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV 339 | 340 | - uses: ncipollo/release-action@v1 341 | with: 342 | # Defaults to using commit tag for `tag:`. 343 | # This workflow is only triggered by tags. 344 | prerelease: false 345 | allowUpdates: true 346 | bodyFile: .github/workflows/release.md 347 | name: ${{ github.ref_name }} 348 | artifacts: "artifacts/*/*.zip" 349 | 350 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS junk 2 | .DS_Store 3 | 4 | # Generated artifacts 5 | build/*/docker/Dockerfile 6 | build/*/assets/shell/welcome 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org/" 2 | 3 | # File generation dependencies 4 | gem "thor", "~> 1.3" 5 | gem "erb", "~> 4.0" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🧪 Mad Science Lab C Unit Testing & Build Environment Docker Images 2 | 3 | Self-contained C unit testing & release build environment with [Ceedling], [Unity], [CMock] and supporting tools. 4 | 5 | ## Overview & contents 6 | 7 | The Docker images produced from this repository contain everything needed for running unit tests and release builds with [Ceedling] and its supporting frameworks. 8 | 9 | This repository contains custom tooling, templates, and the assets necessary to produce multiple variations of the _MadScienceLab_ Docker images targeting different toolchains and containing various collections of supporting tools. A Github Action builds the images and publishes them to Docker Hub. 10 | 11 | * [Docker Hub _MadScienceLab_ images][hub-images]. 12 | * See this [repository’s releases][releases] for the versioned Dockerfiles produced by the Github Action builds. 13 | 14 | The basic idea of this repository is to generate Dockerfiles rather than only maintain the text of one or more Dockerfiles. A custom Ruby-based command line tool uses a template and conventions for directories and files to build up Dockerfiles. This approach has a couple benefits: 15 | 16 | 1. In this way, common base elements can be easily maintained across multiple Dockerfiles. 17 | 1. Entirely new — potentially proprietary — Dockerfiles can be generated as extensions of the _MadScienceLab_ images with elements maintained outside of this repository. 18 | 19 | ## Supporting this work 20 | 21 | These Docker images and complementary [ThrowTheSwitch] pieces and parts are and always will be freely available and open source. 22 | 23 | 💼 **_[Ceedling Suite][ceedling-suite]_** is a growing collection of paid products and services built around Ceedling to help you do even more. **_[Ceedling Assist][ceedling-assist]_** for support contracts and training is now available. 24 | 25 | 🙏🏻 **[Please consider supporting Ceedling as a Github Sponsor][tts-sponsor]** 26 | 27 | [Ceedling]: https://github.com/ThrowTheSwitch/Ceedling 28 | [Unity]: https://github.com/ThrowTheSwitch/Unity 29 | [CMock]: https://github.com/ThrowTheSwitch/CMock 30 | 31 | [hub-images]: https://hub.docker.com/r/throwtheswitch 32 | [releases]: https://github.com/ThrowTheSwitch/MadScienceLabDocker/releases 33 | 34 | [ThrowTheSwitch]: https://github.com/ThrowTheSwitch 35 | [ceedling-suite]: https://www.thingamabyte.com/ceedling 36 | [ceedling-assist]: https://www.thingamabyte.com/ceedlingassist 37 | [tts-sponsor]: https://github.com/sponsors/ThrowTheSwitch 38 | 39 | # 🏭 Usage 40 | 41 | _January, 2025_: More complete documentation on working with the contents of this repository is forthcoming. This repository underwent significant changes in step with the 1.0.0 release of Ceedling. 42 | 43 | ## Generating Dockerfiles 44 | 45 | To generate the four Dockerfiles and related artifacts managed by this project from a local clone of this repository, install all Ruby dependencies using the Gemfile in the root of the project and execute the build shell script also in the root of the repository: 46 | 47 | Examples: 48 | 49 | * `./build.sh --dir build/standard --variant "" --version ` 50 | * `./build.sh --dir build/standard --dir build/plugins --version ` 51 | * `./build.sh --dir build/arm-none-eabi --version 1.0.0` 52 | * `./build.sh --dir build/arm-none-eabi --dir build/plugins --dir build/arm-none-eabi-plugins --version ` 53 | 54 | The Github Action maintained in this repository uses the same approach as the preceding to generate the Dockerfiles attached to releases. The Github Action goes on to build images from those Dockerfiles and pushes them to Docker Hub. 55 | 56 | ## Ruby tool & shell script 57 | 58 | The Ruby tool maintained in this repository does all of the Dockerfile text generation. 59 | 60 | The shell script that calls the Ruby tool includes many options useful to a developer working on this repostory or anyone working to extend the Dockerfiles created by the tooling. Run `./build.sh -h` for a listing of the various options. 61 | 62 | # 🔢 Versioning 63 | 64 | Versioning of this repository and the resulting tags in Docker Hub track [Ceedling]’s version. Docker image changes are maintained with a lowercase letter suffix appended to the version of Ceedling contained in each _MadScienceLab_ image itself. 65 | 66 | # 🔒 Security 67 | 68 | Security documentation is maintained in the [Docker Hub image repositories][hub-images]. 69 | 70 | # 👩‍🏫 Intro to Unit Testing Supported by the MadScienceLab containers 71 | 72 | * The “stock” Docker images maintained by this repository use Ceedling to build “native” code as described [here][which-build]. For additional help and tips for building native tests, read [this](native-tests). 73 | * Advanced users of Ceedling also have the option of creating cross-compiled ARM test executable binaries with the `arm-none-eabi` Docker image variants. These binaries could be native tests on a target platform, or you could run them with a simulator test fixture on a host system. Read more about the simulator option [here][which-build] and how to work with it [here][simulator-tests]. 74 | 75 | [which-build]: http://www.throwtheswitch.org/build/which 76 | [native-tests]: http://www.throwtheswitch.org/build/native 77 | [simulator-tests]: https://www.throwtheswitch.org/build/cross 78 | 79 | # 📄 License(s) 80 | 81 | * The base image, [`minideb`][minideb], for the _MadScienceLab_ variants is [Apache 2.0][apache-20] licensed. 82 | * The _ThrowTheSwitch_ work layered on top of `minideb` is [MIT] licensed (the license file is maintained in the root of this repository). 83 | 84 | [minideb]: https://hub.docker.com/r/bitnami/minideb 85 | [apache-20]: https://www.apache.org/licenses/LICENSE-2.0 86 | [MIT]: https://opensource.org/license/mit -------------------------------------------------------------------------------- /bin/cli.rb: -------------------------------------------------------------------------------- 1 | require 'thor' 2 | 3 | module FileGeneratorTasks 4 | 5 | class CLI < Thor 6 | # Ensure we bail out with non-zero exit code if the command line is wrong 7 | def self.exit_on_failure?() true end 8 | 9 | # Intercept construction to extract configuration and injected dependencies 10 | def initialize(args, config, options) 11 | super(args, config, options) 12 | 13 | @handler = options[:objects][:handler] 14 | end 15 | 16 | desc "welcome TEMPLATE WELCOMEFILE_PATH", "Create a welcome file from components" 17 | method_option :dir, :type => :string, :repeatable => true, :required => true, :desc => "Directory to inspect" 18 | method_option :debug, :type => :boolean, :default => false, :desc => "Set debug logging" 19 | long_desc <<-LONGDESC 20 | `filegen welcome` creates a welcome file from a template and directory contents files. 21 | 22 | `filegen welcome` inspects each provided directory and assembles contents (in order) from any discovered contents files. 23 | The collected contents are expanded within the template into a welcome file for a Docker container shell. 24 | 25 | WELCOMEFILE_PATH is a required filepath to the source welcome file ERB template. 26 | 27 | DEST is a required output filepath for the final welcome file. 28 | 29 | Flags: 30 | 31 | • `--dir` lists directories to inspect (1 or more flags required). 32 | 33 | • `--debug` optionally enables debug output (primarily stack traces). 34 | LONGDESC 35 | def welcome(template, welcomefile_path) 36 | @handler.welcome( template, welcomefile_path, options ) 37 | end 38 | 39 | desc "dockerfile TEMPLATE DOCKERFILE_PATH", "Create a new Dockerfile from components" 40 | method_option :dir, :type => :string, :repeatable => true, :required => true, :desc => "Directory to inspect" 41 | method_option :variant, :type => :string, :required => false, :default => "", :desc => "Docker image variant" 42 | method_option :debug, :type => :boolean, :default => false, :desc => "Set debug logging" 43 | long_desc <<-LONGDESC 44 | `filegen dockerfile` creates a Dockerfile from a template and contributing files. 45 | 46 | `filegen dockerfile` inspects each provided directory (in order) looking for files whose content will be 47 | expanded within the template file referencing their contents. The final path in this list is the home of 48 | the variant being assembled. Earlier paths are contributors to the final output. 49 | 50 | TEMPLATE is a required filepath to the source Dockerfile ERB template. 51 | 52 | DOCKERFILE_PATH is a required output filepath for the generated Dockerfile. 53 | 54 | Flags: 55 | 56 | • `--dir` lists directories to inspect (1 or more flags required). 57 | 58 | • `--variant` provides the Docker image variant name. 59 | 60 | • `--debug` optionally enables debug output (primarily stack traces). 61 | LONGDESC 62 | def dockerfile(template, dockerfile_path) 63 | @handler.dockerfile( template, dockerfile_path, options ) 64 | end 65 | 66 | end 67 | 68 | end -------------------------------------------------------------------------------- /bin/cli_handler.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | require 'erb' 3 | require 'fileutils' 4 | 5 | module DockerGeneratorTasks 6 | 7 | class Handler 8 | 9 | FILENAME_PACKAGES = 'packages.yml' 10 | FILENAME_CONTENTS = 'contents.yml' 11 | FILENAME_SETUP_BLOCKS = 'Dockerfile-setup' 12 | FILENAME_ASSET_BLOCKS = 'Dockerfile-assets' 13 | FILENAME_BUILD_BLOCKS = 'Dockerfile-build' 14 | FILENAME_USER_BLOCKS = 'Dockerfile-user' 15 | 16 | def initialize(objects) 17 | @dockerfile_data = objects[:dockerfile_data] 18 | end 19 | 20 | def dockerfile(template, dest, options) 21 | set_debug( options[:debug] ) 22 | 23 | puts ( 'Generating Dockerfile...' ) 24 | 25 | dirs = options[:dir] 26 | 27 | # Validate directories 28 | dirs.each do |dir| 29 | raise "Directory '#{dir}' not found" if !File.directory?( dir ) 30 | end 31 | 32 | @dockerfile_data.variant_dir = dirs[-1] # Last in ordered list 33 | @dockerfile_data.variant = options[:variant] 34 | 35 | # Process all components in batches across all directories 36 | ingest_setup_blocks( dirs, FILENAME_SETUP_BLOCKS ) 37 | ingest_packages( dirs, FILENAME_PACKAGES ) 38 | ingest_asset_blocks( dirs, FILENAME_ASSET_BLOCKS ) 39 | ingest_build_blocks( dirs, FILENAME_BUILD_BLOCKS ) 40 | ingest_user_blocks( dirs, FILENAME_USER_BLOCKS ) 41 | 42 | template = ERB.new( File.read( template ), trim_mode:'<>-' ) 43 | 44 | FileUtils.mkdir_p( File.dirname( dest ) ) 45 | 46 | File.write( 47 | dest, 48 | template.result( @dockerfile_data.get_binding() ), 49 | mode:'w' 50 | ) 51 | 52 | puts( "📄 Wrote Dockerfile to #{dest}" ) 53 | end 54 | 55 | 56 | def welcome(template, dest, options) 57 | set_debug( options[:debug] ) 58 | 59 | puts ( 'Generating welcome file...' ) 60 | 61 | dirs = options[:dir] 62 | 63 | # Validate sources base paths 64 | dirs.each do |dir| 65 | raise "Directory '#{dir}' not found" if !File.directory?( dir ) 66 | end 67 | 68 | # Instance variable for ERB binding 69 | @contents = [] 70 | 71 | msg = 'welcome file contents' 72 | 73 | ingest_components( 74 | dirs, FILENAME_CONTENTS, msg ) { |filepath| 75 | @contents += YAML.load( File.read( filepath ) ) 76 | } 77 | 78 | template = ERB.new( File.read( template ), trim_mode:'<>-' ) 79 | 80 | FileUtils.mkdir_p( File.dirname( dest ) ) 81 | 82 | File.write( 83 | dest, 84 | template.result( binding ), 85 | mode:'w' 86 | ) 87 | 88 | puts( "👋 Wrote welcome file to #{dest}" ) 89 | end 90 | 91 | ### Private ### 92 | 93 | private 94 | 95 | def set_debug(debug) 96 | # Create global constant PROJECT_DEBUG 97 | Object.module_eval("PROJECT_DEBUG = debug") 98 | PROJECT_DEBUG.freeze() 99 | end 100 | 101 | def ingest_setup_blocks(dirs, filename) 102 | ingest_components( 103 | dirs, filename, 'setup handling blocks' ) { |filepath| 104 | @dockerfile_data.add_setup_block( File.read( filepath ) ) 105 | } 106 | end 107 | 108 | def ingest_packages(dirs, filename) 109 | ingest_components( 110 | dirs, filename, 'packages to add to image' ) { |filepath| 111 | @dockerfile_data.add_packages( YAML.load( File.read( filepath ) ) ) 112 | } 113 | end 114 | 115 | def ingest_asset_blocks(dirs, filename) 116 | ingest_components( 117 | dirs, filename, 'asset handling blocks' ) { |filepath| 118 | @dockerfile_data.add_asset_block( File.read( filepath ) ) 119 | } 120 | end 121 | 122 | def ingest_build_blocks(dirs, filename) 123 | ingest_components( 124 | dirs, filename, 'build & installation handling blocks' ) { |filepath| 125 | @dockerfile_data.add_build_block( File.read( filepath ) ) 126 | } 127 | end 128 | 129 | def ingest_user_blocks(dirs, filename) 130 | ingest_components( 131 | dirs, filename, 'user account handling blocks' ) { |filepath| 132 | @dockerfile_data.add_user_block( File.read( filepath ) ) 133 | } 134 | end 135 | 136 | def ingest_components(dirs, filename, msg, &block) 137 | dirs.each do |dir| 138 | filepath = File.join( dir, filename ) 139 | 140 | if File.exist?( filepath ) 141 | block.call(filepath) 142 | puts ( "+ Ingested #{msg} from #{dir}/" ) 143 | end 144 | end 145 | end 146 | 147 | end 148 | 149 | end 150 | -------------------------------------------------------------------------------- /bin/dockerfile_data.rb: -------------------------------------------------------------------------------- 1 | 2 | # Dockerfile template data class. 3 | class DockerfileData 4 | 5 | attr_accessor :variant 6 | 7 | def initialize() 8 | @setup = [] 9 | @packages = [] 10 | @assets = [] 11 | @build = [] 12 | @user = [] 13 | 14 | @variant_dir = '' 15 | @variant = '' 16 | end 17 | 18 | def variant_dir=(dir) 19 | @variant_dir = dir.split( File::SEPARATOR ).drop(1).join( File::SEPARATOR ) 20 | end 21 | 22 | def add_setup_block( block ) 23 | @setup << block_strip( block ) 24 | end 25 | 26 | def add_packages( packages ) 27 | @packages += packages 28 | @packages.sort! 29 | @packages.uniq! 30 | end 31 | 32 | def add_asset_block( block ) 33 | @assets << block_strip( block ) 34 | end 35 | 36 | def add_build_block( block ) 37 | @build << block_strip( block ) 38 | end 39 | 40 | def add_user_block( block ) 41 | @user << block_strip( block ) 42 | end 43 | 44 | # Support templating of member data. 45 | def get_binding 46 | binding 47 | end 48 | 49 | ### Private ### 50 | 51 | private 52 | 53 | def block_strip(block) 54 | # Remove leading blank lines (but not leading whitespace on first line) 55 | # Remove trailing whitespace 56 | return block.gsub(/^$\n/, '').rstrip() 57 | end 58 | 59 | end -------------------------------------------------------------------------------- /bin/filegen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | BIN = File.expand_path( File.dirname( __FILE__ ) ) 4 | 5 | $LOAD_PATH.unshift( BIN ) 6 | 7 | require 'cli' 8 | require 'cli_handler' 9 | require 'dockerfile_data' 10 | 11 | # Entry point 12 | begin 13 | 14 | # Dependency injection 15 | cli_handler = DockerGeneratorTasks::Handler.new( { 16 | :dockerfile_data => DockerfileData.new() 17 | } 18 | ) 19 | 20 | FileGeneratorTasks::CLI.start( ARGV, { 21 | :objects => 22 | { 23 | :handler => cli_handler, 24 | } 25 | } 26 | ) 27 | 28 | # Boom handling 29 | rescue StandardError => e 30 | $stderr.puts( "\n ERROR: #{e.message}" ) 31 | $stderr.puts( e.backtrace ) if ( defined?( PROJECT_DEBUG ) and PROJECT_DEBUG ) 32 | exit(1) 33 | end 34 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script argument handling reference: https://joshtronic.com/2023/03/12/parsing-arguments-in-shell-script/ 4 | 5 | # Default image name (can be overridden by CLI argument) 6 | IMAGE="throwtheswitch/madsciencelab" 7 | 8 | ## 9 | ## Usage output 10 | ## 11 | 12 | # Function to print usage instructions 13 | function usage { 14 | echo "" 15 | echo "Usage: $0 [--dir ]* [--variant ] [-b|--build] [-v|--version ] [-i|--image ] [--platform] [--push|--validate] [-d|--debug] [--verbose] " 16 | echo "" 17 | echo "throwtheswitch/madsciencelab Dockerfile + asset generation with multi-platform Docker image build" 18 | echo "" 19 | echo "File generation options:" 20 | echo " --dir Add to be processed in addition to build/base" 21 | echo " May be specified multiple times" 22 | echo " Last instance provides variant name" 23 | echo " --variant Override auto-discovered variant name" 24 | echo "" 25 | echo "Docker image build options:" 26 | echo " -b, --build Build Docker image after generating a Dockerfile [defaults to local image on host]" 27 | echo " -v, --version Docker image version, ex: '1.2.3' [default: 'latest']" 28 | echo " -i, --image Override image name [default: '$IMAGE']" 29 | echo " --platform Docker target platforms, ex: 'linux/arm64,linux/amd64'" 30 | echo " --push Push a multi-platform Docker image build to its repository (only with --platform)" 31 | echo " --validate Execute a multi-platform build (only with --platform)" 32 | echo " -d, --debug Produce full Docker image build log" 33 | echo "" 34 | echo "Script options:" 35 | echo " --verbose Print script steps" 36 | echo " -h, --help Print this usage message" 37 | exit 1 38 | } 39 | 40 | # If no command line parameters, print usage and exit 41 | if [ $# -eq 0 ]; then usage; fi 42 | 43 | ## 44 | ## Defaults 45 | ## 46 | 47 | # Docker image tag / version handling 48 | IMAGE_TAG="latest" # Docker image tag (can include 'latest') 49 | CONTAINER_VERSION="" # Version provided to running container via environment variable (blank or a version string) 50 | 51 | # Variant handling 52 | VARIANT_NAME_OVERRIDE=false 53 | VARIANT_NAME_RENAME="" 54 | VARIANT_NAME="" 55 | VARIANT_DIR_PATH="" 56 | 57 | # First, necessary base directory in list of directories to process 58 | DOCKERFILE_GEN_DIRS="--dir=build/base" 59 | 60 | # Docker buildx platforms list (empty defaults to host platform where build is happening) 61 | PLATFORMS="" 62 | # Docker buildx command line argument 63 | PLATFORM_ARGS="" 64 | 65 | # Default to standard, simple `docker build` 66 | BUILD_ACTION="build" 67 | 68 | # Special build action flags 69 | MULTIPLATFORM_BUILD=false 70 | PUSH=false 71 | VALIDATE=false 72 | 73 | ## 74 | ## Command line argument handling 75 | ## 76 | 77 | # Parse command line arguments 78 | while [[ $# -gt 0 ]]; do 79 | case $1 in 80 | 81 | --dir) 82 | if [ -z "$2" ]; then 83 | echo "" 84 | echo "ERROR: Directory name required for --dir" 85 | usage 86 | fi 87 | 88 | if [[ ! -d "$2" ]]; then 89 | echo "" 90 | echo "ERROR: Invalid directory $2. Path does not exist." 91 | exit 1 92 | fi 93 | 94 | # Variant name defaults to last provided --dir option 95 | VARIANT_NAME=`basename "$2"` 96 | # Variant directory is last provided in --dir list 97 | VARIANT_DIR_PATH="$2" 98 | # Concatenate to list of --dir arguments for `filegen` utility 99 | DOCKERFILE_GEN_DIRS="$DOCKERFILE_GEN_DIRS --dir=$2" 100 | shift 101 | shift 102 | ;; 103 | 104 | --variant) 105 | # Capture varient name override, including blank option 106 | # Since we can't control order of CLI args, we save and process later 107 | VARIANT_NAME_RENAME="$2" 108 | VARIANT_NAME_OVERRIDE=true 109 | shift 110 | shift 111 | ;; 112 | 113 | -b|--build) 114 | BUILD=true 115 | shift 116 | ;; 117 | 118 | -v|--version) 119 | if [ -z "$2" ]; then 120 | echo "" 121 | echo "ERROR: No argument provided for --version" 122 | usage 123 | fi 124 | 125 | CONTAINER_VERSION="$2" 126 | shift 127 | shift 128 | ;; 129 | 130 | -i|--image) 131 | if [ -z "$2" ]; then 132 | echo "" 133 | echo "ERROR: No name provided for --image" 134 | usage 135 | fi 136 | 137 | IMAGE="$2" 138 | shift 139 | shift 140 | ;; 141 | 142 | --platform) 143 | if [ -z "$2" ]; then 144 | echo "" 145 | echo "ERROR: One or more platforms required by --platform" 146 | usage 147 | fi 148 | 149 | PLATFORMS="$2" 150 | PLATFORM_ARGS="--platform=$2" 151 | shift 152 | shift 153 | ;; 154 | 155 | --push) 156 | # Override default of image build with push to repository 157 | PUSH=true 158 | shift 159 | ;; 160 | 161 | --validate) 162 | # Override default of image build with push to repository 163 | VALIDATE=true 164 | shift 165 | ;; 166 | 167 | -d|--debug) 168 | # Force the Docker build to skip caching and produce a full progress dump for review 169 | LOG_ARGS="--no-cache --progress=plain" 170 | shift 171 | ;; 172 | 173 | --verbose) 174 | VERBOSE=true 175 | shift 176 | ;; 177 | 178 | -h|--help) 179 | usage 180 | ;; 181 | 182 | *) 183 | echo "Invalid option: $1" 184 | usage 185 | ;; 186 | esac 187 | done 188 | 189 | 190 | # If platforms blank, ensure --push or --validate not set 191 | if [ -z "$PLATFORMS" ]; then 192 | if [ "$PUSH" = true ]; then 193 | echo "" 194 | echo "ERROR: --push only available in combination with --platform" 195 | usage 196 | fi 197 | 198 | if [ "$VALIDATE" = true ]; then 199 | echo "" 200 | echo "ERROR: --validate only available in combination with --platform" 201 | usage 202 | fi 203 | 204 | # If platforms not blank, ensure --push or --validate used properly and add to BUILD_ACTION accordingly 205 | else 206 | if [ "$PUSH" = true && "$VALIDATE" = true ]; then 207 | echo "" 208 | echo "ERROR: --validate and --push are mutually exclusive options" 209 | usage 210 | fi 211 | fi 212 | 213 | # After build option combination validation above, set our build options 214 | if [ "$PUSH" = true ]; then 215 | BUILD_ACTION="buildx build --push" 216 | MULTIPLATFORM_BUILD=true 217 | elif [ "$VALIDATE" = true ]; then 218 | BUILD_ACTION="buildx build -o type=image" 219 | MULTIPLATFORM_BUILD=true 220 | fi 221 | 222 | 223 | # Print script statements to STDOUT if --verbose set 224 | if [ "$VERBOSE" = true ]; then 225 | set -x 226 | fi 227 | 228 | # Reset variant name auto discovered from --dir list 229 | if $VARIANT_NAME_OVERRIDE; then 230 | VARIANT_NAME="$VARIANT_NAME_RENAME" 231 | fi 232 | 233 | # Add variant suffix to image name 234 | if [ -n "$VARIANT_NAME" ]; then 235 | IMAGE="$IMAGE-$VARIANT_NAME" 236 | fi 237 | 238 | # Create Docker image tag other than 'latest', if version string provided 239 | if [ -n "$CONTAINER_VERSION" ]; then 240 | IMAGE_TAG="$CONTAINER_VERSION" 241 | fi 242 | 243 | ## 244 | ## File Generation 245 | ## 246 | 247 | 248 | echo "🎯 Target Docker image $IMAGE:$IMAGE_TAG" 249 | echo "" 250 | 251 | # Generate the Welcome file displayed within the shell at container launch 252 | bin/filegen welcome $DOCKERFILE_GEN_DIRS build/base/templates/welcome.erb "$VARIANT_DIR_PATH"/assets/shell/welcome 253 | if [ $? -ne 0 ]; then 254 | echo "❌ ERROR: Could not generate welcome file(s)" 255 | echo "" 256 | exit 1 257 | fi 258 | 259 | echo "" 260 | 261 | # Generate the Dockerfile 262 | bin/filegen dockerfile $DOCKERFILE_GEN_DIRS --variant="$VARIANT_NAME" build/base/templates/Dockerfile.erb "$VARIANT_DIR_PATH"/docker/Dockerfile 263 | if [ $? -ne 0 ]; then 264 | echo "❌ ERROR: Could not generate Dockerfile" 265 | echo "" 266 | exit 1 267 | fi 268 | 269 | echo "" 270 | 271 | ## 272 | ## Docker Image Build 273 | ## 274 | 275 | # Build the Dockerfile we just created with any additional options 276 | if [ "$BUILD" = true ]; then 277 | 278 | # If a multi-platform build option is set, enable multi-platform builder 279 | if [ $MULTIPLATFORM_BUILD == true ]; then 280 | # If a buildx builder doesn't already exist, set one up 281 | if ! (docker buildx ls 2>&1 | grep -q 'madsciencelab-builder'); then 282 | docker buildx create --name madsciencelab-builder 283 | if [ $? -ne 0 ]; then 284 | echo "❌ ERROR: Could not create multi-platform Docker builder" 285 | echo "" 286 | exit 1 287 | fi 288 | fi 289 | 290 | # Ensure we're using a buildx builder 291 | docker buildx use madsciencelab-builder 292 | if [ $? -ne 0 ]; then 293 | echo "❌ ERROR: Could not enable multi-platform Docker builder" 294 | echo "" 295 | exit 1 296 | fi 297 | fi 298 | 299 | # Perform multi-platform build with output as an image or optionally a direct push to the repository 300 | # Always echo this command to the command line 301 | (set -x; docker $BUILD_ACTION $LOG_ARGS -t "$IMAGE":"$IMAGE_TAG" $PLATFORM_ARGS --build-arg CONTAINER_VERSION="$CONTAINER_VERSION" --build-arg IMAGE_NAME="$IMAGE" -f "$VARIANT_DIR_PATH"/docker/Dockerfile .) 302 | 303 | # Capture exit code from attempted Docker image build 304 | success=$? 305 | 306 | # Stop the buildx builder started above 307 | if [ $MULTIPLATFORM_BUILD == true ]; then 308 | docker buildx stop madsciencelab-builder 309 | fi 310 | 311 | operation="" 312 | platforms="" 313 | 314 | if [ $PUSH == true ]; then 315 | operation="Built and pushed" 316 | else 317 | operation="Built" 318 | fi 319 | 320 | if [ -z "$PLATFORMS" ]; then 321 | platforms="host platform" 322 | else 323 | # Break up Docker command line option 'platform,platform' to be readable 324 | platforms="${PLATFORMS/,/, }" 325 | fi 326 | 327 | if [ $success -eq 0 ]; then 328 | echo "" 329 | echo "📦 $operation $IMAGE:$IMAGE_TAG for $platforms" 330 | echo "" 331 | else 332 | echo "" 333 | echo "❌ ERROR: Could not build $IMAGE:$IMAGE_TAG for $platforms" 334 | echo "" 335 | fi 336 | fi 337 | -------------------------------------------------------------------------------- /build/arm-none-eabi-plugins/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi-plugins/assets/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi-plugins/assets/shell/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi-plugins/assets/shell/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi-plugins/docker/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi-plugins/docker/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi/assets/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi/assets/shell/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi/assets/shell/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi/contents.yml: -------------------------------------------------------------------------------- 1 | 2 | - {platform: '*', entry: 'GNU Compiler Collection (gcc, etc.) for ARM'} 3 | - {platform: '*', entry: 'Standard C libraries (ARM)'} 4 | -------------------------------------------------------------------------------- /build/arm-none-eabi/docker/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/arm-none-eabi/docker/.gitkeep -------------------------------------------------------------------------------- /build/arm-none-eabi/packages.yml: -------------------------------------------------------------------------------- 1 | 2 | - gcc-arm-none-eabi 3 | - libnewlib-arm-none-eabi 4 | -------------------------------------------------------------------------------- /build/base/Dockerfile-assets: -------------------------------------------------------------------------------- 1 | 2 | ## 3 | ## Copy Ruby assets for inclusion in image 4 | ## 5 | ## Notes: 6 | ## - Gems must be downloaded manually to the vendored bse/assets/gems directory. 7 | ## - To find the list of gems and versions needed, visit 8 | ## https://rubygems.org/gems/ceedling/versions//dependencies 9 | ## - The easiest way to vendor a gem is `gem fetch -v ` with volume mapped to assets/gems. 10 | ## 11 | 12 | COPY build/base/assets /assets/base 13 | -------------------------------------------------------------------------------- /build/base/Dockerfile-build: -------------------------------------------------------------------------------- 1 | 2 | # Install Ceedling, CMock, Unity, CException + gem dependencies 3 | RUN set -ex \ 4 | # Prevent documentation installation taking up space 5 | echo -e "---\ngem: --no-ri --no-rdoc\n...\n" > .gemrc \ 6 | # Install Ceedling and related gems 7 | && gem install --force --local /assets/base/gems/*.gem \ 8 | && gem install bundler \ 9 | && bundle install --gemfile=/assets/base/gems/Gemfile \ 10 | && rm .gemrc 11 | -------------------------------------------------------------------------------- /build/base/assets/gems/Gemfile: -------------------------------------------------------------------------------- 1 | # ========================================================================= 2 | # Ceedling - Test-Centered Build System for C 3 | # ThrowTheSwitch.org 4 | # Copyright (c) 2010-24 Mike Karlesky, Mark VanderVoord, & Greg Williams 5 | # SPDX-License-Identifier: MIT 6 | # ========================================================================= 7 | 8 | source "http://rubygems.org/" 9 | 10 | gem "bundler", "~> 2.5" 11 | 12 | # Testing tools 13 | gem "rspec", "~> 3.8" 14 | gem "rake", ">= 12", "< 14" 15 | gem "rr" 16 | gem "require_all" 17 | 18 | # Ceedling dependencies 19 | gem "diy", "~> 1.1" 20 | gem "constructor", "~> 2" 21 | gem "thor", "~> 1.3" 22 | gem "deep_merge", "~> 1.2" 23 | gem "unicode-display_width", "~> 3.1" 24 | -------------------------------------------------------------------------------- /build/base/assets/gems/ceedling-1.0.1.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/base/assets/gems/ceedling-1.0.1.gem -------------------------------------------------------------------------------- /build/base/assets/shell/zshrc-dev: -------------------------------------------------------------------------------- 1 | # Lines configured by zsh-newuser-install 2 | HISTFILE=~/.histfile 3 | HISTSIZE=1000 4 | SAVEHIST=1000 5 | # End of lines configured by zsh-newuser-install 6 | # The following lines were added by compinstall 7 | zstyle :compinstall filename '/home/nonroot/.zshrc' 8 | 9 | autoload -Uz compinit 10 | compinit 11 | # End of lines added by compinstall 12 | 13 | CLICOLOR=1 14 | 15 | # Working directory only (displaying `dev` user is sorta confusing and unnecessary) 16 | PROMPT="%F{cyan}%~%f > " 17 | 18 | # Display contents of container as colored text list when shell first loads 19 | source $HOME/.welcome 20 | -------------------------------------------------------------------------------- /build/base/assets/shell/zshrc-root: -------------------------------------------------------------------------------- 1 | # Lines configured by zsh-newuser-install 2 | HISTFILE=~/.histfile 3 | HISTSIZE=1000 4 | SAVEHIST=1000 5 | # End of lines configured by zsh-newuser-install 6 | # The following lines were added by compinstall 7 | zstyle :compinstall filename '/home/nonroot/.zshrc' 8 | 9 | autoload -Uz compinit 10 | compinit 11 | # End of lines added by compinstall 12 | 13 | CLICOLOR=1 14 | 15 | # User (helpful to highlight that we're root) + working directory 16 | PROMPT="%F{blue}%n%f | %F{cyan}%~%f > " 17 | -------------------------------------------------------------------------------- /build/base/contents.yml: -------------------------------------------------------------------------------- 1 | 2 | - {platform: '*', entry: 'Ceedling, Unity, CMock & CException'} 3 | - {platform: '*', entry: 'Ruby 3'} 4 | - {platform: '*', entry: 'Essential Unix utilities'} 5 | - {platform: '*', entry: 'Essential build tools (make, etc.)'} 6 | - {platform: '*', entry: 'nano for simple text editing'} 7 | -------------------------------------------------------------------------------- /build/base/packages.yml: -------------------------------------------------------------------------------- 1 | 2 | - coreutils 3 | - build-essential # Make, etc. 4 | - nano # Simple, helpful text editor 5 | - ruby=1:3.1 # Latest Ruby (3.1) in Debian packages for Bookworm 6 | - zsh # Z shell 7 | - locales # Locale management (`locales-gen`) for UTF-8 encoding 8 | -------------------------------------------------------------------------------- /build/base/templates/Dockerfile.erb: -------------------------------------------------------------------------------- 1 | ## Base Docker Image 2 | ## minideb is a slim Debian base image well maintained by VMWare 3 | ## https://github.com/bitnami/minideb 4 | FROM bitnami/minideb:bookworm 5 | 6 | # This image is meant to include multi-platform support via Docker's buildx/BuildKit client and service. 7 | # In recent versions of Docker desktop `docker build` uses the buildx client by default. Under such a build, 8 | # the build argument TARGETPLATFORM is set automatically. 9 | # 10 | # If this image is built without buildx/BuildKit, the build argument below must be set from the command line. 11 | # The command line must include `--build-arg TARGETPLATFORM=` where platform is a Docker- 12 | # recognized platform string (e.g. "linux/amd64"). 13 | ARG TARGETPLATFORM 14 | 15 | # Docker image name used for Metadata, set via Docker build argument 16 | # The command line must include `--build-arg IMAGE_NAME=` / 17 | ARG IMAGE_NAME 18 | 19 | # This build argument allows setting the image tag at build time to support CI-based builds 20 | # The command line must include `--build-arg CONTAINER_VERSION=` 21 | ARG CONTAINER_VERSION 22 | 23 | # Capture TARGETPLATFORM as an environment variable in the image 24 | ENV CONTAINER_PLATFORM=$TARGETPLATFORM 25 | 26 | # Docker image tag for internal container use, set via Docker build argument 27 | ENV MADSCIENCELAB_VERSION=$CONTAINER_VERSION 28 | 29 | # Docker Hub URL 30 | ENV DOCKERHUB_URL=https://hub.docker.com/r/$IMAGE_NAME 31 | 32 | ## 33 | ## Docker Image Best Practices 34 | ## https://docs.docker.com/develop/develop-images/instructions/ 35 | ## 36 | 37 | ## Metadata 38 | LABEL org.opencontainers.image.source=https://github.com/ThrowTheSwitch/MadScienceLabDocker/releases 39 | LABEL org.opencontainers.image.url=$DOCKERHUB_URL 40 | LABEL org.opencontainers.image.licenses="Apache-2.0 and MIT" 41 | LABEL org.opencontainers.image.base.name=docker.io/bitnami/minideb 42 | LABEL org.opencontainers.image.title="Mad Science Lab" 43 | LABEL org.opencontainers.image.description="Contains Ceedling, supporting frameworks, and GNU C toolchain to provide a unit testing and build system environment for C projects" 44 | 45 | # Image base / set up 46 | RUN set -ex \ 47 | # Update package management environment 48 | && apt update \ 49 | && apt -y upgrade \ 50 | <%# INSERT SETUP BLOCKS -%> 51 | <% @setup.each {|block| %><%= block.concat("\n") %><% } -%> 52 | && apt install -y \ 53 | <%# INSERT PACKAGE LIST TO INSTALL -%> 54 | <% @packages.each {|package|%><%= " #{package} \\\n"%><% } -%> 55 | --no-install-recommends \ 56 | && apt autoremove \ 57 | && apt clean \ 58 | && rm -rf /var/lib/apt/lists/* 59 | 60 | ## 61 | ## Locale setting for Ruby encoding handling 62 | ## 63 | ## https://stackoverflow.com/questions/17031651/rails-invalid-byte-sequence-in-us-ascii-argument-error-when-i-run-rake-dbsee 64 | ## https://www.graalvm.org/latest/reference-manual/ruby/UTF8Locale/ 65 | ## 66 | 67 | # Set environment variables 68 | ENV LANG=en_US.UTF-8 69 | ENV LANGUAGE=en_US:en 70 | ENV LC_ALL=en_US.UTF-8 71 | 72 | # Run Debian locale setting operation 73 | RUN set -ex \ 74 | # Uncomment the en_US.UTF-8 line in /etc/locale.gen 75 | && sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \ 76 | # locale-gen generates locales for all uncommented locales in /etc/locale.gen 77 | && locale-gen 78 | 79 | <%# INSERT ASSET HANDLING BLOCKS -%> 80 | <% @assets.each {|block| -%> 81 | <%= block + " \n" %> 82 | <% } -%> 83 | <%# COPY GENERATED WELCOME FILE -%> 84 | # Copy generated shell welcome file into image 85 | COPY build/<%= @variant_dir -%>/assets/shell/welcome /assets/<%= @variant_dir -%>/shell/welcome 86 | 87 | 88 | <%# INSERT BUILD / INSTALLATION BLOCKS -%> 89 | <% @build.each {|block| -%> 90 | <%= block + " \n" %> 91 | <% } -%> 92 | 93 | ## 94 | ## Permissions Security & Cleanup 95 | ## - After necessary installations, etc. as root user ensure default container user is not root 96 | ## - Create user `dev` (with group 999) and make `dev` the default user 97 | ## - Delete /assets directory 98 | ## 99 | 100 | RUN set -ex \ 101 | && groupadd -r nonroot --gid 999 \ 102 | && useradd -s /usr/bin/zsh -r -g nonroot dev 103 | 104 | # Set up new user home directory and cleanup /assets 105 | RUN set -ex \ 106 | # Give the new user home directory +rwx permissions to group members 107 | # This will allow us to dynamically specify the host user for the container but give them group permissions 108 | && mkdir -p /home/dev \ 109 | && chown dev:nonroot /home/dev \ 110 | && chmod -R ug+rwx /home/dev \ 111 | # Copy simple Z shell config file & give new user permissions 112 | && cp /assets/base/shell/zshrc-dev /home/dev/.zshrc \ 113 | && chown dev:nonroot /home/dev/.zshrc \ 114 | # Copy welcome file & give new user permissions 115 | && cp /assets/<%= @variant_dir -%>/shell/welcome /home/dev/.welcome \ 116 | && chown dev:nonroot /home/dev/.welcome \ 117 | # Copy simple Z shell config file for root user (for running container as `-u root`) 118 | && cp /assets/base/shell/zshrc-root /root/.zshrc \ 119 | # Cleanup assets 120 | && rm -rf /assets 121 | 122 | # Become / set new user 123 | USER dev 124 | 125 | <%# INSERT USER-LEVEL BLOCKS -%> 126 | <% @user.each {|block| -%> 127 | <%= block + " \n" %> 128 | <% } -%> 129 | 130 | WORKDIR /home/dev/project 131 | 132 | # When the container launches, run a shell that launches in WORKDIR 133 | CMD ["/usr/bin/zsh"] 134 | 135 | -------------------------------------------------------------------------------- /build/base/templates/welcome.erb: -------------------------------------------------------------------------------- 1 | echo "" 2 | echo "\e[35mWelcome to the Mad Science Lab $MADSCIENCELAB_VERSION \e[0m" 3 | echo "\e[37m" 4 | echo " This container includes:" 5 | <%# INSERT CONTENTS LIST -%> 6 | <% @contents.each {|item|%><%= "if [[ \"$CONTAINER_PLATFORM\" == #{item['platform']} ]]; then echo \" * #{item['entry']}\"; fi\n"%><% } -%> 7 | echo "\e[0m" 8 | echo " Documentation available at $DOCKERHUB_URL" 9 | echo " NOTICE: Container user \`$(whoami)\` lacks root privileges as a security best practice." 10 | echo "" 11 | echo " Please consider supporting this work: https://github.com/sponsors/ThrowTheSwitch" 12 | echo "\e[33m" 13 | echo " To get started, enter \`ceedling help\` at the command line..." 14 | echo "\e[0m" 15 | -------------------------------------------------------------------------------- /build/plugins/Dockerfile-assets: -------------------------------------------------------------------------------- 1 | 2 | ## 3 | ## Copy Dotnet assets for temporary use 4 | ## 5 | ## Notes: 6 | ## - The Microsoft Debian package sources file is needed to install Dotnet 7 | ## - The file should be downloaded and vendored to assets/ 8 | ## wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 9 | ## 10 | 11 | COPY build/plugins/assets /assets/plugins 12 | -------------------------------------------------------------------------------- /build/plugins/Dockerfile-build: -------------------------------------------------------------------------------- 1 | 2 | # Microsoft Dotnet installation to support `reportgenerator` for `gcov` plugin 3 | # Only available on AMD64 image builds 4 | RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then set -ex \ 5 | && dpkg -i /assets/plugins/dotnet/packages-microsoft-prod.deb \ 6 | && apt update \ 7 | && apt install -y \ 8 | dotnet-sdk-8.0 \ 9 | --no-install-recommends \ 10 | && apt clean \ 11 | && rm -rf /var/lib/apt/lists/* ; fi 12 | -------------------------------------------------------------------------------- /build/plugins/Dockerfile-user: -------------------------------------------------------------------------------- 1 | 2 | # Install `reportgenerator` (for `gcov` plugin) 3 | # Only available in AMD64 containers 4 | RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then set -ex \ 5 | # Install the dotnet tool as global (which means global for the current user vs. a local directory) 6 | && dotnet tool install --global dotnet-reportgenerator-globaltool \ 7 | # Modify the PATH so the new tool is findable 8 | && echo "[[ -d \"$HOME/.dotnet/tools\" ]] && export PATH=\"$PATH:$HOME/.dotnet/tools\"" >> $HOME/.zshenv ; fi 9 | -------------------------------------------------------------------------------- /build/plugins/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/plugins/assets/.gitkeep -------------------------------------------------------------------------------- /build/plugins/assets/dotnet/packages-microsoft-prod.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/plugins/assets/dotnet/packages-microsoft-prod.deb -------------------------------------------------------------------------------- /build/plugins/assets/shell/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/plugins/assets/shell/.gitkeep -------------------------------------------------------------------------------- /build/plugins/contents.yml: -------------------------------------------------------------------------------- 1 | 2 | - {platform: '*', entry: 'gcovr for use by GCov plugin'} 3 | - {platform: 'linux/amd64', entry: 'reportgenerator for use by GCov plugin'} 4 | - {platform: '*', entry: 'unzip, git & svn for use by Dependencies plugin'} 5 | - {platform: '*', entry: 'tput for use by Beep plugin'} 6 | - {platform: '*', entry: 'Python 3, needed by gcovr'} 7 | - {platform: 'linux/amd64', entry: 'Dotnet 8, needed by reportgenerator'} 8 | -------------------------------------------------------------------------------- /build/plugins/docker/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/plugins/docker/.gitkeep -------------------------------------------------------------------------------- /build/plugins/packages.yml: -------------------------------------------------------------------------------- 1 | 2 | - gcovr # For `gcov` plugin 3 | - valgrind # For `valgrind` plugin 4 | - ncurses-bin # For `tput` (`beep` plugin) 5 | - unzip # For `dependencies` plugin 6 | - git-all # For `git` (`dependencies` plugin) 7 | - subversion # For `svn` (`dependencies` plugin) 8 | 9 | # Note: `reportgenerator` (for `gcov` plugin) is a Dotnet tool handled elsehwere -------------------------------------------------------------------------------- /build/standard/Dockerfile-build: -------------------------------------------------------------------------------- 1 | 2 | # gcc-multilib for processor architectures is only available for AMD64 image builds 3 | RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then set -ex \ 4 | && apt update \ 5 | && apt install -y \ 6 | gcc-multilib \ 7 | --no-install-recommends \ 8 | && apt clean \ 9 | && rm -rf /var/lib/apt/lists/* ; fi 10 | -------------------------------------------------------------------------------- /build/standard/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/standard/assets/.gitkeep -------------------------------------------------------------------------------- /build/standard/assets/shell/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/standard/assets/shell/.gitkeep -------------------------------------------------------------------------------- /build/standard/contents.yml: -------------------------------------------------------------------------------- 1 | # Ruby symbols not allowed as keys in inline YML 2 | - {platform: '*', entry: 'The GNU Compiler Collection (gcc, etc.)'} 3 | - {platform: '*', entry: 'Standard C libraries'} 4 | - {platform: 'linux/amd64', entry: 'GCC Multilib support for platform architectures'} 5 | - {platform: '*', entry: "The GNU Debugger (gdb) for Ceedling's backtrace feature"} 6 | -------------------------------------------------------------------------------- /build/standard/docker/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThrowTheSwitch/MadScienceLabDocker/b48c56d6900e4675d7fdb57221a8d10b0e6f421b/build/standard/docker/.gitkeep -------------------------------------------------------------------------------- /build/standard/packages.yml: -------------------------------------------------------------------------------- 1 | 2 | - gcc # GNU Compiler Collection 3 | - libc-dev # Common C development packages 4 | - gdb # Debugger (for Ceedling `backtrace` feature) 5 | -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policies and Procedures 2 | 3 | This document outlines security procedures and general policies for all `ThrowTheSwitch.org` 4 | projects, including `Unity`, `CMock`, and `Ceedling`. 5 | 6 | * [Reporting a Bug](#reporting-a-bug) 7 | * [Disclosure Policy](#disclosure-policy) 8 | * [Comments on this Policy](#comments-on-this-policy) 9 | 10 | ## Reporting a Bug 11 | 12 | The tools from `ThrowTheSwitch.org` are made to collaborate with other tools like compilers, 13 | simulators, and such, and therefore have very low-level access to the world they live in. 14 | However, they are typically used in controlled development-centered environments. As such, 15 | they are typically not directly exposed to security concerns. 16 | 17 | The `ThrowTheSwitch.org` community takes security bugs seriously. Where possible, we will 18 | make every effort to improve our tools safe use. Thank you for improving the security of 19 | our tools. We appreciate your efforts and responsible disclosure and will make every effort 20 | to acknowledge your contributions. 21 | 22 | Report security bugs by opening a Github Issue on the corresponding project or (when this 23 | itself would pose a risk) by emailing security@thingamabyte.com. 24 | 25 | Report security bugs in third-party modules to the person or team maintaining 26 | the module. 27 | 28 | ## Disclosure Policy 29 | 30 | Each issue will be assigned to a primary handler. This person will coordinate the fix and 31 | release process, involving the following steps: 32 | 33 | * Confirm the problem and determine the affected versions. 34 | * Audit code to find any potential similar problems. 35 | * Prepare fixes for all releases still under maintenance. These fixes will be 36 | released as fast as possible. 37 | 38 | ## Comments on this Policy 39 | 40 | If you have suggestions on how this process could be improved please submit a 41 | pull request. -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2010-25 Michael Karlesky, Mark VanderVoord, & Greg Williams 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | OTHER DEALINGS IN THE SOFTWARE. 25 | --------------------------------------------------------------------------------