Compare commits
288 commits
automated-
...
main
Author | SHA1 | Date | |
---|---|---|---|
768d4c8398 | |||
0a4f338966 | |||
297c9da2d8 | |||
f0abbb5ccd | |||
fd426c9ceb | |||
dfb174d4e4 | |||
|
3ea4d6bbd7 | ||
|
def3a41f57 | ||
|
d53b9d1816 | ||
|
710103a638 | ||
|
7324b6d03c | ||
|
d4ecc7be06 | ||
|
719901a1b4 | ||
|
4c2c9f7b95 | ||
|
e645120a39 | ||
|
1155a9906b | ||
|
36a3604b90 | ||
|
4fca96b5e8 | ||
|
0d7ad7c5fc | ||
|
90a9b1d604 | ||
|
c3f9105048 | ||
|
04cb7d1e79 | ||
|
cf92754bf4 | ||
|
803ec6e0e5 | ||
|
0599c63f8f | ||
|
3aad9a72f4 | ||
|
243671eece | ||
|
0d2fc3ad5b | ||
|
e7f7d194d6 | ||
|
9852ca8888 | ||
|
3a22c41940 | ||
|
f92f7ba7ae | ||
|
97eea5deee | ||
|
a771e8cb42 | ||
|
8ad7c749b3 | ||
|
96c1eea40f | ||
|
038bed3d58 | ||
|
96bff00970 | ||
|
95a169b9ef | ||
|
0668db5ede | ||
|
0cf690ee14 | ||
|
a08434f2b1 | ||
|
71ac2021e1 | ||
|
a4b31f314f | ||
|
9fd5daf06b | ||
|
c58b614202 | ||
|
1d1a23625d | ||
|
f90cb26c7f | ||
|
8b6f088256 | ||
|
be082b0ef5 | ||
|
9e75db9a1d | ||
|
f2594c5cc8 | ||
|
bbb24d10d4 | ||
|
29859aff28 | ||
|
685fa2e0f1 | ||
|
836ea1e9fa | ||
|
ea2d79070e | ||
|
7fcec6e7c9 | ||
|
0e8940abea | ||
|
07693965d7 | ||
|
c4ffeebdac | ||
|
300814be97 | ||
|
8a51aa9066 | ||
|
ef76ff97b6 | ||
|
b6dbe7051c | ||
|
610286c369 | ||
|
972fdffa71 | ||
|
ccce957d7e | ||
|
de40074875 | ||
|
d934503a05 | ||
|
2258fcb040 | ||
|
2fb386db11 | ||
|
931262d20c | ||
|
ee9f0bfbf0 | ||
|
367308c736 | ||
|
852f1f0567 | ||
|
cfae3b0f0d | ||
|
b48d8700ff | ||
|
1869e5931c | ||
|
4420cd5d27 | ||
|
4312340798 | ||
|
b16ff1efb7 | ||
|
e2b3b48bc5 | ||
|
f52ff611c5 | ||
|
fad03b19d4 | ||
|
2237731474 | ||
|
8d3e9aca9d | ||
|
74959ec149 | ||
|
585ee2a42c | ||
|
7f605b9452 | ||
|
f0dd470ba8 | ||
|
2952d87f1d | ||
|
1118b992d9 | ||
|
0e079baaf7 | ||
|
e7e4aa8a98 | ||
|
d4c3fefc4a | ||
|
1449f416a0 | ||
|
adf7240a7c | ||
|
5d6f1ae9b9 | ||
|
de1e634a67 | ||
|
fe449253f1 | ||
|
3e6ee966ba | ||
|
3cc059ea8a | ||
|
4b7efebea1 | ||
|
83c6103db2 | ||
|
d84e46be47 | ||
|
8d3685e09f | ||
|
900cbfc1f9 | ||
|
4a9929f964 | ||
|
36d7664eba | ||
|
c997f9af69 | ||
|
6bf4a7dbec | ||
|
7763e0b7db | ||
|
fbdc4556d5 | ||
|
258d5029a5 | ||
|
676e824e92 | ||
|
3a579894a0 | ||
|
bebf87e33c | ||
|
7a3a9c5fca | ||
|
24b33c5f79 | ||
|
d78a153492 | ||
|
f7314671e1 | ||
|
58b8fe093d | ||
|
79588ef3da | ||
|
1726222515 | ||
|
74dd2710dc | ||
|
e67f4dc0fd | ||
|
c8f5c3cbee | ||
|
7e32db56c0 | ||
|
59fa3e3c21 | ||
|
04143e31ff | ||
|
a9a7a25d60 | ||
|
c546f4bf8c | ||
|
ef192bf467 | ||
|
8f7eec80d4 | ||
|
2c646ed9fe | ||
|
eef35a4399 | ||
|
6c76a7b488 | ||
|
dbf069a5db | ||
|
29babe4245 | ||
|
f9de0e43f8 | ||
|
19bc8bb633 | ||
|
80ed2fbc30 | ||
|
00dd4f4a19 | ||
|
592fdc8177 | ||
|
5fb5c388b5 | ||
|
b6921f9b9f | ||
|
b9bfe406d2 | ||
|
48678001d1 | ||
|
42e5a013cc | ||
|
2472653c31 | ||
|
e46fe0eb34 | ||
|
fede405549 | ||
|
9af65a01c7 | ||
|
7867e008c1 | ||
|
2af02c198a | ||
|
e46c73de74 | ||
|
a3dc31d31f | ||
|
bf058dc494 | ||
|
7fa90110d7 | ||
|
baf47e22b0 | ||
|
84f3e62d1c | ||
|
7b009e661f | ||
|
aae9de7ebc | ||
|
e28358e33b | ||
|
779fa44930 | ||
|
57e15bc8e8 | ||
|
7a47fbff00 | ||
|
46dfa11ecd | ||
|
64f0e10fab | ||
|
cf36e7ac3a | ||
|
d1972b4d8d | ||
|
4af4c29122 | ||
|
30f2876053 | ||
|
4b3ccf36ea | ||
|
188f1ef26b | ||
|
133b4cf23c | ||
|
c4648ab98c | ||
|
173c7ca3c7 | ||
|
3fc9604dda | ||
|
be4f0498e4 | ||
|
bff3178837 | ||
|
1e35500bda | ||
|
f9acb6aae1 | ||
|
a5655189a2 | ||
|
474444fa9f | ||
|
ada30c21f5 | ||
|
58fed08dcf | ||
|
eafa28287e | ||
|
e00724a0c6 | ||
|
17580ee22f | ||
|
258b107b39 | ||
|
0e25800486 | ||
|
e9c4f9f8c5 | ||
|
7172641514 | ||
|
00a51775eb | ||
|
1c61d1a039 | ||
|
a2b1c19a51 | ||
|
f7f05f76fa | ||
|
3020d6da64 | ||
|
73a9c7d382 | ||
|
d003c1b1ac | ||
|
b7c70d3d9b | ||
|
752ba5db21 | ||
|
a94558576c | ||
|
268368beeb | ||
|
0752a52b0c | ||
|
748be9320c | ||
|
1313517fc4 | ||
|
2ce89c4a57 | ||
|
9366ef7ed1 | ||
|
f1c981d064 | ||
|
0ee38a48e4 | ||
|
85d2150997 | ||
|
22050f2fd4 | ||
|
2963ae9119 | ||
|
ab021f0dfb | ||
|
520a4abc40 | ||
|
fd31e97db0 | ||
|
7ae8c5c16d | ||
|
4dae930c16 | ||
|
40206f4774 | ||
|
aad4e3a7af | ||
|
67b15cae12 | ||
|
7860eb85a4 | ||
|
2bec6f056c | ||
|
43f0b34aa3 | ||
|
2c82571f42 | ||
|
530997ce54 | ||
|
a244dc394f | ||
|
a8cb375d46 | ||
|
065b5ec9e1 | ||
|
14c7ee7897 | ||
|
2d63a582d9 | ||
|
602c3ec7b6 | ||
|
2d89dc301e | ||
|
a9441adf0e | ||
|
82960fd16b | ||
|
960f21c2c5 | ||
|
8c19bb1626 | ||
|
7aad197228 | ||
|
c62bd1a9c8 | ||
|
091aa5082a | ||
|
3a28652790 | ||
|
ceb4544cc3 | ||
|
bae7812259 | ||
|
0258e7e66a | ||
|
cd5126ee2d | ||
|
ef939f908c | ||
|
987ebe8ea6 | ||
|
9a92823e9a | ||
|
811a93f06a | ||
|
674b096863 | ||
|
b7b5d8b1c0 | ||
|
e90f4f9e0a | ||
|
32578d6c4d | ||
|
8218a6d3c1 | ||
|
023d623196 | ||
|
aed075c7a5 | ||
|
a5fbdab3c0 | ||
|
d8ee2e8cf1 | ||
|
7e6dd4b070 | ||
|
a4f1532faf | ||
|
9e7d6a35d5 | ||
|
f8dba16f44 | ||
|
771a300594 | ||
|
14d98b7795 | ||
|
d50ef0016a | ||
|
964e4a3404 | ||
|
8f64809e5d | ||
|
6851eadfcb | ||
|
2e928d96ed | ||
|
8befe8c114 | ||
|
e43c0de319 | ||
|
41e3e4c748 | ||
|
f82307ad60 | ||
|
84f4996643 | ||
|
0cafeee862 | ||
|
58e425039a | ||
|
ec1deb8280 | ||
|
ea030fa0ae | ||
|
ad088a11bb | ||
|
97c1abf391 | ||
|
023e9c46ff | ||
|
3ac132483a | ||
|
9c60d26d96 | ||
|
2e03507e5a | ||
|
a630e92c46 |
351 changed files with 15717 additions and 15092 deletions
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"postCreateCommand": "npm install -g @devcontainers/cli"
|
|
||||||
}
|
|
17
.devcontainer/devcontainer.json
Normal file
17
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-18",
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
||||||
|
},
|
||||||
|
"postCreateCommand": "npm install -g @devcontainers/cli",
|
||||||
|
"hostRequirements": {
|
||||||
|
"cpus": 4
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"mads-hartmann.bash-ide-vscode"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
.github/devcontainers-action/README.md
vendored
3
.github/devcontainers-action/README.md
vendored
|
@ -1,3 +0,0 @@
|
||||||
# Devcontainers/action
|
|
||||||
|
|
||||||
Temporary copy of [devcontainers/action](https://github.com/devcontainers/action).
|
|
32
.github/devcontainers-action/action.yml
vendored
32
.github/devcontainers-action/action.yml
vendored
|
@ -1,32 +0,0 @@
|
||||||
name: 'Dev Container'
|
|
||||||
description: 'Publish custom development container assets'
|
|
||||||
author: 'GitHub'
|
|
||||||
branding:
|
|
||||||
icon: box
|
|
||||||
color: blue
|
|
||||||
inputs:
|
|
||||||
# Global options
|
|
||||||
publish-features:
|
|
||||||
required: false
|
|
||||||
default: "false"
|
|
||||||
description: "['true'/'false'] Publish dev container 'feature' artifacts"
|
|
||||||
generate-docs:
|
|
||||||
required: false
|
|
||||||
default: "false"
|
|
||||||
description: "Parse machine-readable (.json) configuration files and commit standardized documentation"
|
|
||||||
|
|
||||||
# 'features' options
|
|
||||||
base-path-to-features:
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
description: "Relative path to the 'src' folder containing dev container 'feature(s)'"
|
|
||||||
oci-registry:
|
|
||||||
required: false
|
|
||||||
description: "Name of the OCI registry that implements the OCI Artifact Distribution Specification"
|
|
||||||
features-namespace:
|
|
||||||
required: false
|
|
||||||
description: "A unique indentifier for the collection of features"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: 'node16'
|
|
||||||
main: 'dist/index.js'
|
|
11354
.github/devcontainers-action/dist/index.js
vendored
11354
.github/devcontainers-action/dist/index.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
659
.github/devcontainers-action/dist/licenses.txt
vendored
659
.github/devcontainers-action/dist/licenses.txt
vendored
|
@ -1,659 +0,0 @@
|
||||||
@actions/core
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright 2019 GitHub
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
@actions/exec
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright 2019 GitHub
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
@actions/github
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright 2019 GitHub
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
@actions/http-client
|
|
||||||
MIT
|
|
||||||
Actions Http Client for Node.js
|
|
||||||
|
|
||||||
Copyright (c) GitHub, Inc.
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
||||||
associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
||||||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
||||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
||||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@actions/io
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright 2019 GitHub
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
@octokit/auth-token
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/core
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/endpoint
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2018 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/graphql
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2018 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/plugin-paginate-rest
|
|
||||||
MIT
|
|
||||||
MIT License Copyright (c) 2019 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/plugin-rest-endpoint-methods
|
|
||||||
MIT
|
|
||||||
MIT License Copyright (c) 2019 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/request
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2018 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@octokit/request-error
|
|
||||||
MIT
|
|
||||||
The MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2019 Octokit contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
@vercel/ncc
|
|
||||||
MIT
|
|
||||||
Copyright 2018 ZEIT, Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
before-after-hook
|
|
||||||
Apache-2.0
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright 2018 Gregor Martynus and other contributors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
|
|
||||||
deprecation
|
|
||||||
ISC
|
|
||||||
The ISC License
|
|
||||||
|
|
||||||
Copyright (c) Gregor Martynus and contributors
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
||||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
is-plain-object
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014-2017, Jon Schlinkert.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
node-fetch
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 David Frank
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
once
|
|
||||||
ISC
|
|
||||||
The ISC License
|
|
||||||
|
|
||||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
||||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
tr46
|
|
||||||
MIT
|
|
||||||
|
|
||||||
tunnel
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2012 Koichi Kobayashi
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
universal-user-agent
|
|
||||||
ISC
|
|
||||||
# [ISC License](https://spdx.org/licenses/ISC)
|
|
||||||
|
|
||||||
Copyright (c) 2018, Gregor Martynus (https://github.com/gr2m)
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
uuid
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2010-2020 Robert Kieffer and other contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
webidl-conversions
|
|
||||||
BSD-2-Clause
|
|
||||||
# The BSD 2-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2014, Domenic Denicola
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
whatwg-url
|
|
||||||
MIT
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015–2016 Sebastian Mayr
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
wrappy
|
|
||||||
ISC
|
|
||||||
The ISC License
|
|
||||||
|
|
||||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
||||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
File diff suppressed because one or more lines are too long
|
@ -1,2 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
@ -1,2 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
@ -1,2 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
166
.github/devcontainers-action/lib/generateDocs.js
vendored
166
.github/devcontainers-action/lib/generateDocs.js
vendored
|
@ -1,166 +0,0 @@
|
||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.generateTemplateDocumentation = exports.generateFeaturesDocumentation = void 0;
|
|
||||||
const fs = __importStar(require("fs"));
|
|
||||||
const core = __importStar(require("@actions/core"));
|
|
||||||
const path = __importStar(require("path"));
|
|
||||||
const utils_1 = require("./utils");
|
|
||||||
const FEATURES_README_TEMPLATE = `
|
|
||||||
# #{Name}
|
|
||||||
|
|
||||||
#{Description}
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
\`\`\`json
|
|
||||||
"features": {
|
|
||||||
"#{Registry}/#{Namespace}/#{Id}:#{Version}": {
|
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
#{OptionsTable}
|
|
||||||
|
|
||||||
#{Notes}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](#{RepoUrl}). Add additional notes to a \`NOTES.md\`._
|
|
||||||
`;
|
|
||||||
const TEMPLATE_README_TEMPLATE = `
|
|
||||||
# #{Name}
|
|
||||||
|
|
||||||
#{Description}
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
#{OptionsTable}
|
|
||||||
`;
|
|
||||||
function generateFeaturesDocumentation(basePath, ociRegistry, namespace) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield _generateDocumentation(basePath, FEATURES_README_TEMPLATE, 'devcontainer-feature.json', ociRegistry, namespace);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.generateFeaturesDocumentation = generateFeaturesDocumentation;
|
|
||||||
function generateTemplateDocumentation(basePath) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield _generateDocumentation(basePath, TEMPLATE_README_TEMPLATE, 'devcontainer-template.json');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.generateTemplateDocumentation = generateTemplateDocumentation;
|
|
||||||
function _generateDocumentation(basePath, readmeTemplate, metadataFile, ociRegistry = '', namespace = '') {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const directories = fs.readdirSync(basePath);
|
|
||||||
yield Promise.all(directories.map((f) => __awaiter(this, void 0, void 0, function* () {
|
|
||||||
var _a, _b, _c;
|
|
||||||
if (!f.startsWith('.')) {
|
|
||||||
const readmePath = path.join(basePath, f, 'README.md');
|
|
||||||
// Reads in feature.json
|
|
||||||
const jsonPath = path.join(basePath, f, metadataFile);
|
|
||||||
if (!fs.existsSync(jsonPath)) {
|
|
||||||
core.error(`${metadataFile} not found at path '${jsonPath}'`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let parsedJson = undefined;
|
|
||||||
try {
|
|
||||||
parsedJson = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.error(`Failed to parse ${jsonPath}: ${err}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!parsedJson || !(parsedJson === null || parsedJson === void 0 ? void 0 : parsedJson.id)) {
|
|
||||||
core.error(`${metadataFile} for '${f}' does not contain an 'id'`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const srcInfo = (0, utils_1.getGitHubMetadata)();
|
|
||||||
// Add version
|
|
||||||
let version = 'latest';
|
|
||||||
const parsedVersion = parsedJson === null || parsedJson === void 0 ? void 0 : parsedJson.version;
|
|
||||||
if (parsedVersion) {
|
|
||||||
// example - 1.0.0
|
|
||||||
const splitVersion = parsedVersion.split('.');
|
|
||||||
version = splitVersion[0];
|
|
||||||
}
|
|
||||||
const generateOptionsMarkdown = () => {
|
|
||||||
const options = parsedJson === null || parsedJson === void 0 ? void 0 : parsedJson.options;
|
|
||||||
if (!options) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
const keys = Object.keys(options);
|
|
||||||
const contents = keys
|
|
||||||
.map(k => {
|
|
||||||
const val = options[k];
|
|
||||||
return `| ${k} | ${val.description || '-'} | ${val.type || '-'} | ${val.default || '-'} |`;
|
|
||||||
})
|
|
||||||
.join('\n');
|
|
||||||
return '| Options Id | Description | Type | Default Value |\n' + '|-----|-----|-----|-----|\n' + contents;
|
|
||||||
};
|
|
||||||
const generateNotesMarkdown = () => {
|
|
||||||
const notesPath = path.join(basePath, f, 'NOTES.md');
|
|
||||||
return fs.existsSync(notesPath) ? fs.readFileSync(path.join(notesPath), 'utf8') : '';
|
|
||||||
};
|
|
||||||
let urlToConfig = './devcontainer-feature.json';
|
|
||||||
const basePathTrimmed = basePath.startsWith('./') ? basePath.substring(2) : basePath;
|
|
||||||
if (srcInfo.owner && srcInfo.repo) {
|
|
||||||
urlToConfig = `https://github.com/${srcInfo.owner}/${srcInfo.repo}/blob/main/${basePathTrimmed}/${f}/devcontainer-feature.json`;
|
|
||||||
}
|
|
||||||
const newReadme = readmeTemplate
|
|
||||||
// Templates & Features
|
|
||||||
.replace('#{Id}', parsedJson.id)
|
|
||||||
.replace('#{Name}', parsedJson.name ? `${parsedJson.name} (${parsedJson.id})` : `${parsedJson.id}`)
|
|
||||||
.replace('#{Description}', (_a = parsedJson.description) !== null && _a !== void 0 ? _a : '')
|
|
||||||
.replace('#{OptionsTable}', generateOptionsMarkdown())
|
|
||||||
.replace('#{Notes}', generateNotesMarkdown())
|
|
||||||
// Features Only
|
|
||||||
.replace('#{Registry}', ociRegistry)
|
|
||||||
.replace('#{Namespace}', namespace)
|
|
||||||
.replace('#{Version}', version)
|
|
||||||
// Templates Only
|
|
||||||
.replace('#{ManifestName}', (_c = (_b = parsedJson === null || parsedJson === void 0 ? void 0 : parsedJson.image) === null || _b === void 0 ? void 0 : _b.manifest) !== null && _c !== void 0 ? _c : '')
|
|
||||||
.replace('#{RepoUrl}', urlToConfig);
|
|
||||||
// Remove previous readme
|
|
||||||
if (fs.existsSync(readmePath)) {
|
|
||||||
fs.unlinkSync(readmePath);
|
|
||||||
}
|
|
||||||
// Write new readme
|
|
||||||
fs.writeFileSync(readmePath, newReadme);
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
});
|
|
||||||
}
|
|
93
.github/devcontainers-action/lib/main.js
vendored
93
.github/devcontainers-action/lib/main.js
vendored
|
@ -1,93 +0,0 @@
|
||||||
"use strict";
|
|
||||||
/*--------------------------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
|
||||||
*-------------------------------------------------------------------------------------------------------------*/
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const core = __importStar(require("@actions/core"));
|
|
||||||
const generateDocs_1 = require("./generateDocs");
|
|
||||||
const utils_1 = require("./utils");
|
|
||||||
const exec = __importStar(require("@actions/exec"));
|
|
||||||
function run() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
core.debug('Reading input parameters...');
|
|
||||||
// Read inputs
|
|
||||||
const shouldPublishFeatures = core.getInput('publish-features').toLowerCase() === 'true';
|
|
||||||
const shouldGenerateDocumentation = core.getInput('generate-docs').toLowerCase() === 'true';
|
|
||||||
const featuresBasePath = core.getInput('base-path-to-features');
|
|
||||||
const sourceMetadata = (0, utils_1.getGitHubMetadata)();
|
|
||||||
const inputOciRegistry = core.getInput('oci-registry');
|
|
||||||
const ociRegistry = inputOciRegistry && inputOciRegistry !== '' ? inputOciRegistry : 'ghcr.io';
|
|
||||||
const inputNamespace = core.getInput('namespace');
|
|
||||||
const namespace = inputNamespace && inputNamespace !== '' ? inputNamespace : `${sourceMetadata.owner}/${sourceMetadata.repo}`;
|
|
||||||
const cliDebugMode = core.getInput('devcontainer-cli-debug-mode').toLowerCase() === 'true';
|
|
||||||
// -- Publish
|
|
||||||
if (shouldPublishFeatures) {
|
|
||||||
core.info('Publishing features...');
|
|
||||||
yield publishFeatures(featuresBasePath, ociRegistry, namespace, cliDebugMode);
|
|
||||||
}
|
|
||||||
// -- Generate Documentation
|
|
||||||
if (shouldGenerateDocumentation && featuresBasePath) {
|
|
||||||
core.info('Generating documentation for features...');
|
|
||||||
yield (0, generateDocs_1.generateFeaturesDocumentation)(featuresBasePath, ociRegistry, namespace);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function publishFeatures(basePath, ociRegistry, namespace, cliDebugMode = false) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Ensures we have the devcontainer CLI installed.
|
|
||||||
if (!(yield (0, utils_1.ensureDevcontainerCliPresent)(cliDebugMode))) {
|
|
||||||
core.setFailed('Failed to install devcontainer CLI');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let cmd = 'devcontainer';
|
|
||||||
let args = ['features', 'publish', '-r', ociRegistry, '-n', namespace, basePath];
|
|
||||||
if (cliDebugMode) {
|
|
||||||
cmd = 'npx';
|
|
||||||
args = ['-y', './devcontainer.tgz', ...args];
|
|
||||||
}
|
|
||||||
const res = yield exec.getExecOutput(cmd, args, {
|
|
||||||
ignoreReturnCode: true
|
|
||||||
});
|
|
||||||
return res.exitCode === 0;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
core.setFailed(err === null || err === void 0 ? void 0 : err.message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
run();
|
|
107
.github/devcontainers-action/lib/utils.js
vendored
107
.github/devcontainers-action/lib/utils.js
vendored
|
@ -1,107 +0,0 @@
|
||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.ensureDevcontainerCliPresent = exports.isDevcontainerCliAvailable = exports.getGitHubMetadata = exports.renameLocal = exports.mkdirLocal = exports.writeLocalFile = exports.readLocalFile = void 0;
|
|
||||||
const github = __importStar(require("@actions/github"));
|
|
||||||
const fs = __importStar(require("fs"));
|
|
||||||
const util_1 = require("util");
|
|
||||||
const core = __importStar(require("@actions/core"));
|
|
||||||
const exec = __importStar(require("@actions/exec"));
|
|
||||||
exports.readLocalFile = (0, util_1.promisify)(fs.readFile);
|
|
||||||
exports.writeLocalFile = (0, util_1.promisify)(fs.writeFile);
|
|
||||||
exports.mkdirLocal = (0, util_1.promisify)(fs.mkdir);
|
|
||||||
exports.renameLocal = (0, util_1.promisify)(fs.rename);
|
|
||||||
function getGitHubMetadata() {
|
|
||||||
// Insert github repo metadata
|
|
||||||
const ref = github.context.ref;
|
|
||||||
let metadata = {
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
ref,
|
|
||||||
sha: github.context.sha
|
|
||||||
};
|
|
||||||
// Add tag if parseable
|
|
||||||
if (ref.includes('refs/tags/')) {
|
|
||||||
const tag = ref.replace('refs/tags/', '');
|
|
||||||
metadata = Object.assign(Object.assign({}, metadata), { tag });
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
exports.getGitHubMetadata = getGitHubMetadata;
|
|
||||||
function isDevcontainerCliAvailable(cliDebugMode = false) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
try {
|
|
||||||
let cmd = 'devcontainer';
|
|
||||||
let args = ['--version'];
|
|
||||||
if (cliDebugMode) {
|
|
||||||
cmd = 'npx';
|
|
||||||
args = ['-y', './devcontainer.tgz', ...args];
|
|
||||||
}
|
|
||||||
const res = yield exec.getExecOutput(cmd, args, {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
});
|
|
||||||
core.info(`Devcontainer CLI version '${res.stdout}' is installed.`);
|
|
||||||
return res.exitCode === 0;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.isDevcontainerCliAvailable = isDevcontainerCliAvailable;
|
|
||||||
function ensureDevcontainerCliPresent(cliDebugMode = false) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (yield isDevcontainerCliAvailable(cliDebugMode)) {
|
|
||||||
core.info('devcontainer CLI is already installed');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (cliDebugMode) {
|
|
||||||
core.error('Cannot remotely fetch CLI in debug mode');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
core.info('Fetching the latest @devcontainer/cli...');
|
|
||||||
const res = yield exec.getExecOutput('npm', ['install', '-g', '@devcontainers/cli'], {
|
|
||||||
ignoreReturnCode: true,
|
|
||||||
silent: true
|
|
||||||
});
|
|
||||||
return res.exitCode === 0;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
exports.ensureDevcontainerCliPresent = ensureDevcontainerCliPresent;
|
|
13
.github/devcontainers-action/sync-action.sh
vendored
13
.github/devcontainers-action/sync-action.sh
vendored
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Temporary!
|
|
||||||
|
|
||||||
pushd /workspaces/features/.github/devcontainers-action
|
|
||||||
|
|
||||||
rm ./action.yml
|
|
||||||
rm -rf ./dist
|
|
||||||
rm -rf ./lib
|
|
||||||
|
|
||||||
cp /home/codespace/action/action.yml ./action.yml
|
|
||||||
cp -r /home/codespace/action/dist ./dist
|
|
||||||
cp -r /home/codespace/action/lib ./lib
|
|
37
.github/workflows/docker-in-docker-stress-test.yaml
vendored
Normal file
37
.github/workflows/docker-in-docker-stress-test.yaml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
name: "Stress test - Docker in Docker"
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'src/docker-in-docker/**'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
test-pass: [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50 ]
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Install latest devcontainer CLI"
|
||||||
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
|
- name: "Generating tests for 'docker-in-docker' which validates if docker daemon is running"
|
||||||
|
run: devcontainer features test --skip-scenarios -f docker-in-docker -i mcr.microsoft.com/devcontainers/base:ubuntu .
|
||||||
|
|
||||||
|
test-onCreate:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
test-pass: [ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50 ]
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Install latest devcontainer CLI"
|
||||||
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
|
- name: "Generating tests for 'docker-in-docker' which validates if docker daemon is available within 'onCreateCommand'"
|
||||||
|
run: devcontainer features test -f docker-in-docker --skip-autogenerated --filter "docker_with_on_create_command"
|
5
.github/workflows/linter-automated.yaml
vendored
5
.github/workflows/linter-automated.yaml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: "(CI) Shell Script Linter"
|
name: "CI - Shell Script Linter"
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
@ -8,9 +8,8 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
shellchecker:
|
shellchecker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "!contains(github.event.head_commit.message, 'no-ci') && !contains(github.event.head_commit.message, 'CI ignore')"
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Shell Linter
|
- name: Shell Linter
|
||||||
uses: azohra/shell-linter@v0.6.0
|
uses: azohra/shell-linter@v0.6.0
|
||||||
|
|
4
.github/workflows/linter-manual.yaml
vendored
4
.github/workflows/linter-manual.yaml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: "(Manual) Shell Script Linter"
|
name: "Manual - Shell Script Linter"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
@ -15,7 +15,7 @@ jobs:
|
||||||
shellchecker:
|
shellchecker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Shell Linter
|
- name: Shell Linter
|
||||||
uses: azohra/shell-linter@v0.6.0
|
uses: azohra/shell-linter@v0.6.0
|
||||||
|
|
11
.github/workflows/release.yaml
vendored
11
.github/workflows/release.yaml
vendored
|
@ -1,16 +1,19 @@
|
||||||
name: "(Release) Release dev container features (v2)"
|
name: "Release dev container features"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
if: ${{ github.ref == 'refs/heads/main' }}
|
if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: "Publish features to OCI"
|
- name: "Publish"
|
||||||
uses: ./.github/devcontainers-action # TODO: Once 'devcontainers/action' is published, use that.
|
uses: devcontainers/action@v1
|
||||||
with:
|
with:
|
||||||
publish-features: "true"
|
publish-features: "true"
|
||||||
base-path-to-features: "./src"
|
base-path-to-features: "./src"
|
||||||
|
|
79
.github/workflows/test-all.yaml
vendored
79
.github/workflows/test-all.yaml
vendored
|
@ -1,4 +1,4 @@
|
||||||
name: "(CI) Test Features"
|
name: "CI - Test Features"
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
@ -8,7 +8,6 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "!contains(github.event.head_commit.message, 'no-ci') && !contains(github.event.head_commit.message, 'CI ignore') && !contains(github.event.head_commit.message, 'Automated documentation update')"
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
@ -17,8 +16,9 @@ jobs:
|
||||||
"aws-cli",
|
"aws-cli",
|
||||||
"azure-cli",
|
"azure-cli",
|
||||||
"common-utils",
|
"common-utils",
|
||||||
|
"conda",
|
||||||
"desktop-lite",
|
"desktop-lite",
|
||||||
"docker-from-docker",
|
"docker-outside-of-docker",
|
||||||
"docker-in-docker",
|
"docker-in-docker",
|
||||||
"dotnet",
|
"dotnet",
|
||||||
"git",
|
"git",
|
||||||
|
@ -29,6 +29,7 @@ jobs:
|
||||||
"java",
|
"java",
|
||||||
"kubectl-helm-minikube",
|
"kubectl-helm-minikube",
|
||||||
"node",
|
"node",
|
||||||
|
"nvidia-cuda",
|
||||||
"oryx",
|
"oryx",
|
||||||
"php",
|
"php",
|
||||||
"powershell",
|
"powershell",
|
||||||
|
@ -37,13 +38,77 @@ jobs:
|
||||||
"rust",
|
"rust",
|
||||||
"sshd",
|
"sshd",
|
||||||
"terraform",
|
"terraform",
|
||||||
|
"nix",
|
||||||
|
]
|
||||||
|
baseImage:
|
||||||
|
[
|
||||||
|
"ubuntu:focal",
|
||||||
|
"ubuntu:jammy",
|
||||||
|
"debian:11",
|
||||||
|
"debian:12",
|
||||||
|
"mcr.microsoft.com/devcontainers/base:ubuntu",
|
||||||
|
"mcr.microsoft.com/devcontainers/base:debian",
|
||||||
]
|
]
|
||||||
baseImage: [ "ubuntu:focal", "ubuntu:jammy", "debian:11", "mcr.microsoft.com/vscode/devcontainers/base:ubuntu", "mcr.microsoft.com/vscode/devcontainers/base:debian" ]
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: "Install latest devcontainer CLI"
|
- name: "Install latest devcontainer CLI"
|
||||||
run: npm install -g @devcontainers/cli
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
- name: " Testing '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
|
- name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
|
||||||
run: devcontainer features test -f ${{ matrix.features }} -i ${{ matrix.baseImage }} -c `pwd`
|
run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} .
|
||||||
|
|
||||||
|
test-scenarios:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
features: [
|
||||||
|
"anaconda",
|
||||||
|
"aws-cli",
|
||||||
|
"azure-cli",
|
||||||
|
"common-utils",
|
||||||
|
"conda",
|
||||||
|
"desktop-lite",
|
||||||
|
"docker-outside-of-docker",
|
||||||
|
"docker-in-docker",
|
||||||
|
"dotnet",
|
||||||
|
"git",
|
||||||
|
"git-lfs",
|
||||||
|
"github-cli",
|
||||||
|
"go",
|
||||||
|
"hugo",
|
||||||
|
"java",
|
||||||
|
"kubectl-helm-minikube",
|
||||||
|
"node",
|
||||||
|
"nvidia-cuda",
|
||||||
|
"oryx",
|
||||||
|
"php",
|
||||||
|
"powershell",
|
||||||
|
"python",
|
||||||
|
"ruby",
|
||||||
|
"rust",
|
||||||
|
"sshd",
|
||||||
|
"terraform",
|
||||||
|
"nix",
|
||||||
|
]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Install latest devcontainer CLI"
|
||||||
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
|
- name: "Testing '${{ matrix.features }}' scenarios"
|
||||||
|
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated .
|
||||||
|
|
||||||
|
test-global:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Install latest devcontainer CLI"
|
||||||
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
|
- name: "Testing global scenarios"
|
||||||
|
run: devcontainer features test --global-scenarios-only .
|
||||||
|
|
8
.github/workflows/test-manual.yaml
vendored
8
.github/workflows/test-manual.yaml
vendored
|
@ -1,9 +1,9 @@
|
||||||
name: "(Manual) Test Features"
|
name: "Manual - Test Features"
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
features:
|
features:
|
||||||
description: "list of features to execute tests against"
|
description: "List of features to execute tests against"
|
||||||
required: true
|
required: true
|
||||||
default: "go dotnet"
|
default: "go dotnet"
|
||||||
baseImage:
|
baseImage:
|
||||||
|
@ -19,10 +19,10 @@ jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: "Install latest devcontainer CLI"
|
- name: "Install latest devcontainer CLI"
|
||||||
run: npm install -g @devcontainers/cli
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
- name: "Testing '${{ github.event.inputs.features }}' against '${{ github.event.inputs.baseImage }}'"
|
- name: "Testing '${{ github.event.inputs.features }}' against '${{ github.event.inputs.baseImage }}'"
|
||||||
run: devcontainer features test --features ${{ github.event.inputs.features }} --base-image ${{ github.event.inputs.baseImage }} --collection-folder `pwd` --log-level ${{ github.event.inputs.logLevel }}
|
run: devcontainer features test --features ${{ github.event.inputs.features }} --base-image ${{ github.event.inputs.baseImage }} --log-level ${{ github.event.inputs.logLevel }} .
|
||||||
|
|
35
.github/workflows/test-pr.yaml
vendored
35
.github/workflows/test-pr.yaml
vendored
|
@ -1,11 +1,10 @@
|
||||||
name: "(PR) Test Updated Features"
|
name: "PR - Test Updated Features"
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
detect-changes:
|
detect-changes:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "!contains(github.event.head_commit.message, 'no-ci') && !contains(github.event.head_commit.message, 'CI ignore') && !contains(github.event.head_commit.message, 'Automated documentation update')"
|
|
||||||
outputs:
|
outputs:
|
||||||
features: ${{ steps.filter.outputs.changes }}
|
features: ${{ steps.filter.outputs.changes }}
|
||||||
steps:
|
steps:
|
||||||
|
@ -17,8 +16,9 @@ jobs:
|
||||||
aws-cli: ./**/aws-cli/**
|
aws-cli: ./**/aws-cli/**
|
||||||
azure-cli: ./**/azure-cli/**
|
azure-cli: ./**/azure-cli/**
|
||||||
common-utils: ./**/common-utils/**
|
common-utils: ./**/common-utils/**
|
||||||
|
conda: ./**/conda/**
|
||||||
desktop-lite: ./**/desktop-lite/**
|
desktop-lite: ./**/desktop-lite/**
|
||||||
docker-from-docker: ./**/docker-from-docker/**
|
docker-outside-of-docker: ./**/docker-outside-of-docker/**
|
||||||
docker-in-docker: ./**/docker-in-docker/**
|
docker-in-docker: ./**/docker-in-docker/**
|
||||||
dotnet: ./**/dotnet/**
|
dotnet: ./**/dotnet/**
|
||||||
git: ./**/git/**
|
git: ./**/git/**
|
||||||
|
@ -29,6 +29,7 @@ jobs:
|
||||||
java: ./**/java/**
|
java: ./**/java/**
|
||||||
kubectl-helm-minikube: ./**/kubectl-helm-minikube/**
|
kubectl-helm-minikube: ./**/kubectl-helm-minikube/**
|
||||||
node: ./**/node/**
|
node: ./**/node/**
|
||||||
|
nvidia-cuda: ./**/nvidia-cuda/**
|
||||||
oryx: ./**/oryx/**
|
oryx: ./**/oryx/**
|
||||||
php: ./**/php/**
|
php: ./**/php/**
|
||||||
powershell: ./**/powershell/**
|
powershell: ./**/powershell/**
|
||||||
|
@ -37,6 +38,7 @@ jobs:
|
||||||
rust: ./**/rust/**
|
rust: ./**/rust/**
|
||||||
sshd: ./**/sshd/**
|
sshd: ./**/sshd/**
|
||||||
terraform: ./**/terraform/**
|
terraform: ./**/terraform/**
|
||||||
|
nix: ./**/nix/**
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: [detect-changes]
|
needs: [detect-changes]
|
||||||
|
@ -50,14 +52,31 @@ jobs:
|
||||||
"ubuntu:focal",
|
"ubuntu:focal",
|
||||||
"ubuntu:jammy",
|
"ubuntu:jammy",
|
||||||
"debian:11",
|
"debian:11",
|
||||||
"mcr.microsoft.com/vscode/devcontainers/base:ubuntu",
|
"debian:12",
|
||||||
"mcr.microsoft.com/vscode/devcontainers/base:debian",
|
"mcr.microsoft.com/devcontainers/base:ubuntu",
|
||||||
|
"mcr.microsoft.com/devcontainers/base:debian",
|
||||||
]
|
]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: "Install latest devcontainer CLI"
|
- name: "Install latest devcontainer CLI"
|
||||||
run: npm install -g @devcontainers/cli
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
- name: "Testing '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
|
- name: "Generating tests for '${{ matrix.features }}' against '${{ matrix.baseImage }}'"
|
||||||
run: devcontainer features test -f ${{ matrix.features }} -i ${{ matrix.baseImage }} -c `pwd`
|
run: devcontainer features test --skip-scenarios -f ${{ matrix.features }} -i ${{ matrix.baseImage }} .
|
||||||
|
|
||||||
|
test-scenarios:
|
||||||
|
needs: [detect-changes]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
features: ${{ fromJSON(needs.detect-changes.outputs.features) }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Install latest devcontainer CLI"
|
||||||
|
run: npm install -g @devcontainers/cli
|
||||||
|
|
||||||
|
- name: "Testing '${{ matrix.features }}' scenarios"
|
||||||
|
run: devcontainer features test -f ${{ matrix.features }} --skip-autogenerated .
|
||||||
|
|
20
.github/workflows/test-scenarios.yaml
vendored
20
.github/workflows/test-scenarios.yaml
vendored
|
@ -1,20 +0,0 @@
|
||||||
name: "Test Scenarios"
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
scenarios:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: "!contains(github.event.head_commit.message, 'no-ci') && !contains(github.event.head_commit.message, 'CI ignore') && !contains(github.event.head_commit.message, 'Automated documentation update')"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: "Install latest devcontainer CLI"
|
|
||||||
run: npm install -g @devcontainers/cli
|
|
||||||
|
|
||||||
- name: "Running predefined test scenarios"
|
|
||||||
run: devcontainer features test --scenarios `pwd`/test-scenarios -c `pwd`
|
|
22
.github/workflows/update-documentation.yml
vendored
22
.github/workflows/update-documentation.yml
vendored
|
@ -8,20 +8,21 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
generate:
|
generate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, 'no-ci') && !contains(github.event.head_commit.message, 'CI ignore')"
|
environment: documentation
|
||||||
|
if: "github.ref == 'refs/heads/main'"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Generate Documentation
|
- name: Generate Documentation
|
||||||
uses: ./.github/devcontainers-action # devcontainers/action
|
uses: devcontainers/action@v1
|
||||||
with:
|
with:
|
||||||
generate-docs: "true"
|
generate-docs: "true"
|
||||||
base-path-to-features: "./src"
|
base-path-to-features: "./src"
|
||||||
|
|
||||||
- name: Add and Commit Documentation
|
- name: Create a PR for Documentation
|
||||||
id: push_image_info
|
id: push_image_info
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
echo "Start."
|
echo "Start."
|
||||||
|
@ -37,10 +38,17 @@ jobs:
|
||||||
|
|
||||||
# Add / update and commit
|
# Add / update and commit
|
||||||
git add */**/README.md
|
git add */**/README.md
|
||||||
git commit -m 'Automated documentation update' || export NO_UPDATES=true
|
git commit -m 'Automated documentation update [skip ci]' || export NO_UPDATES=true
|
||||||
|
|
||||||
# Push
|
# Push
|
||||||
if [ "$NO_UPDATES" != "true" ] ; then
|
if [ "$NO_UPDATES" != "true" ] ; then
|
||||||
git push origin "$branch"
|
git push origin "$branch"
|
||||||
gh pr create --title "$message" --body "$message"
|
gh api \
|
||||||
|
--method POST \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
/repos/${GITHUB_REPOSITORY}/pulls \
|
||||||
|
-f title="$message" \
|
||||||
|
-f body="$message" \
|
||||||
|
-f head="$branch" \
|
||||||
|
-f base='main'
|
||||||
fi
|
fi
|
||||||
|
|
52
.github/workflows/update-dotnet-install-script.yml
vendored
Normal file
52
.github/workflows/update-dotnet-install-script.yml
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
name: "Updates vendor 'dotnet-install' script"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0' # Runs every Sunday at midnight UTC (adjust as needed)
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
fetch-latest-dotnet-install:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: documentation # grants access to secrets.PAT, for creating pull requests
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Run fetch-latest-dotnet-install.sh
|
||||||
|
run: src/dotnet/scripts/fetch-latest-dotnet-install.sh
|
||||||
|
|
||||||
|
- name: Create a PR for dotnet-install.sh
|
||||||
|
id: push_image_info
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
echo "Start."
|
||||||
|
|
||||||
|
# Configure git and Push updates
|
||||||
|
git config --global user.email github-actions@github.com
|
||||||
|
git config --global user.name github-actions
|
||||||
|
git config pull.rebase false
|
||||||
|
|
||||||
|
branch=automated-script-update-$GITHUB_RUN_ID
|
||||||
|
git checkout -b $branch
|
||||||
|
message='[Updates] Automated vendor 'dotnet-install' script'
|
||||||
|
|
||||||
|
# Add / update and commit
|
||||||
|
git add src/dotnet/scripts/vendor/dotnet-install.sh
|
||||||
|
git commit -m 'Automated dotnet-install script update' || export NO_UPDATES=true
|
||||||
|
|
||||||
|
# Bump version and push
|
||||||
|
if [ "$NO_UPDATES" != "true" ] ; then
|
||||||
|
echo "$(jq --indent 4 '.version = (.version | split(".") | map(tonumber) | .[2] += 1 | join("."))' src/dotnet/devcontainer-feature.json)" > src/dotnet/devcontainer-feature.json
|
||||||
|
git add src/dotnet/devcontainer-feature.json
|
||||||
|
git commit -m 'Bump version'
|
||||||
|
git push origin "$branch"
|
||||||
|
gh api \
|
||||||
|
--method POST \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
/repos/${GITHUB_REPOSITORY}/pulls \
|
||||||
|
-f title="$message" \
|
||||||
|
-f body="$message" \
|
||||||
|
-f head="$branch" \
|
||||||
|
-f base="$GITHUB_REF_NAME"
|
||||||
|
fi
|
16
.github/workflows/validate-metadata-files.yml
vendored
Normal file
16
.github/workflows/validate-metadata-files.yml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
name: "Validate devcontainer-feature.json files"
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: "Validate devcontainer-feature.json files"
|
||||||
|
uses: devcontainers/action@v1
|
||||||
|
with:
|
||||||
|
validate-only: "true"
|
||||||
|
base-path-to-features: "./src"
|
60
CONTRIBUTING.md
Normal file
60
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
**Thanks for taking the time to contribute! ❤️**
|
||||||
|
|
||||||
|
All types of contributions are encouraged and valued, no matter if it's a bug
|
||||||
|
report 🐛, a feature request 💡, or a Pull Request 🚀.
|
||||||
|
|
||||||
|
- **❓ I have a question:** Ask in [our dev container community Slack channel]
|
||||||
|
- **🐛 I found a bug:** [Open an Issue]
|
||||||
|
- **💡 I have an idea:** [Open an Issue]
|
||||||
|
- **💻 I want to code:** See below
|
||||||
|
|
||||||
|
If you like the project, but just don't have time to contribute, that's OK too!
|
||||||
|
You can also star the project ⭐, rave about it online 💬, or add a link to us
|
||||||
|
🔗 in your project's readme.
|
||||||
|
|
||||||
|
⚠️ You must never report security 🔒 related issues, vulnerabilities or bugs
|
||||||
|
including sensitive information to the issue tracker, or elsewhere in public.
|
||||||
|
Instead, please [report them to the Microsoft Security Response Center]. You can
|
||||||
|
read more about our security policy in [`SECURITY.md`].
|
||||||
|
|
||||||
|
## Contributing code
|
||||||
|
|
||||||
|
👨💼 This repository is a collection of dev container Features managed by dev
|
||||||
|
container spec maintainers. This repository will **only accept improvements and
|
||||||
|
bug fixes** for the [current set of maintained Features].
|
||||||
|
|
||||||
|
🚀 If you're looking to create a new Feature, then we encourage adding it to a
|
||||||
|
separate repository of your control. The [devcontainers/feature-starter]
|
||||||
|
repository has more guidance on self authoring Features.
|
||||||
|
|
||||||
|
💡 Once you've self authored the Features and if you'd like to share them with
|
||||||
|
the community, then we'd recommend [adding it to the index].
|
||||||
|
|
||||||
|
👷 If you've identified an issue and you want to fix it, here's how you can get
|
||||||
|
started:
|
||||||
|
|
||||||
|
1. 🔀 Fork the repo
|
||||||
|
2. 💻 Open the repo in your editor
|
||||||
|
3. 👨💻 Add your changes to your workspace
|
||||||
|
4. ✨ [Test your changes using `devcontainer features test`] to make sure
|
||||||
|
everything still works
|
||||||
|
5. 🆚 Bump the version of the feature you changed according to [semver]
|
||||||
|
6. 🔖 Commit & push your changes
|
||||||
|
7. 🔁 Open a PR to get your changes merged
|
||||||
|
8. 🚀 Profit!
|
||||||
|
|
||||||
|
👩⚖️ When contributing code to this project, you may be asked to agree to our
|
||||||
|
[Contributor License Agreement].
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
[our dev container community Slack channel]: https://aka.ms/devcontainer_community
|
||||||
|
[open an issue]: https://github.com/devcontainers/features/issues/new
|
||||||
|
[current set of maintained Features]: https://github.com/devcontainers/features/tree/main/src
|
||||||
|
[devcontainers/feature-starter]: https://github.com/devcontainers/feature-starter#readme
|
||||||
|
[adding it to the index]: https://github.com/devcontainers/feature-starter#adding-features-to-the-index
|
||||||
|
[report them to the Microsoft Security Response Center]: https://msrc.microsoft.com/create-report
|
||||||
|
[`SECURITY.md`]: https://github.com/devcontainers/spec/blob/main/SECURITY.md
|
||||||
|
[contributor license agreement]: https://opensource.microsoft.com/cla/
|
||||||
|
[Test your changes using `devcontainer features test`]: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
|
||||||
|
[semver]: https://semver.org/
|
||||||
|
<!-- prettier-ignore-end -->
|
58
README.md
58
README.md
|
@ -4,36 +4,28 @@
|
||||||
<td style="width: 140px; text-align: center;"><a href="https://github.com/devcontainers"><img width="128px" src="https://raw.githubusercontent.com/microsoft/fluentui-system-icons/78c9587b995299d5bfc007a0077773556ecb0994/assets/Cube/SVG/ic_fluent_cube_32_filled.svg" alt="devcontainers organization logo"/></a></td>
|
<td style="width: 140px; text-align: center;"><a href="https://github.com/devcontainers"><img width="128px" src="https://raw.githubusercontent.com/microsoft/fluentui-system-icons/78c9587b995299d5bfc007a0077773556ecb0994/assets/Cube/SVG/ic_fluent_cube_32_filled.svg" alt="devcontainers organization logo"/></a></td>
|
||||||
<td>
|
<td>
|
||||||
<strong>Development Container 'Features'</strong><br />
|
<strong>Development Container 'Features'</strong><br />
|
||||||
<i>A set of simple and reusable 'features'. Quickly add a language/tool/CLI to a development container.
|
<i>A set of simple and reusable Features. Quickly add a language/tool/CLI to a development container.
|
||||||
</td>
|
</td>
|
||||||
</tr></table>
|
</tr></table>
|
||||||
|
|
||||||
'Features' are self-contained units of installation code and development container configuration. Features are designed
|
'Features' are self-contained units of installation code and development container configuration. Features are designed
|
||||||
to install atop a wide-range of base container images (**this repo focuses on `debian` based images**).
|
to install atop a wide-range of base container images.
|
||||||
|
|
||||||
Missing a CLI or language in your otherwise _perfect_ container image? Add the relevant 'feature' to the `features`
|
Missing a CLI or language in your otherwise _perfect_ container image? Add the relevant Feature to the `features`
|
||||||
property of a [`devcontainer.json`](https://containers.dev/implementors/json_reference/#general-properties). A
|
property of a [`devcontainer.json`](https://containers.dev/implementors/json_reference/#general-properties). A
|
||||||
[tool supporting the dev container specification](https://containers.dev/supporting) is required to build a development
|
[tool supporting the dev container specification](https://containers.dev/supporting) is required to build a development
|
||||||
container.
|
container.
|
||||||
|
|
||||||
⚠️ Development container 'features' are a
|
You may learn about Features at [containers.dev](https://containers.dev/implementors/features/), which is the website for the dev container specification.
|
||||||
[**proposed**](https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-features.md) addition to the
|
|
||||||
[development container specification](https://containers.dev/implementors/spec/). **Please note that 'features' are in
|
|
||||||
preview and subject to breaking changes**.
|
|
||||||
|
|
||||||
Once the [**proposed**](https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-features.md)
|
|
||||||
specification is accepted, implementation details will be published at
|
|
||||||
[https://containers.dev](https://containers.dev/).
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
To reference a feature from this repository, add the desired features to a `devcontainer.json`. Each feature has a `README.md` that shows how to reference the feature and which options are available for that feature.
|
To reference a Feature from this repository, add the desired Features to a `devcontainer.json`. Each Feature has a `README.md` that shows how to reference the Feature and which options are available for that Feature.
|
||||||
|
|
||||||
The example below installs the `go` and `docker-in-docker` declared in the [`./src`](./src) directory of this
|
The example below installs the `go` and `docker-in-docker` declared in the [`./src`](./src) directory of this
|
||||||
repository.
|
repository.
|
||||||
|
|
||||||
See the relevant feature's README for supported options.
|
See the relevant Feature's README for supported options.
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
"name": "my-project-devcontainer",
|
"name": "my-project-devcontainer",
|
||||||
|
@ -51,7 +43,7 @@ See the relevant feature's README for supported options.
|
||||||
|
|
||||||
The `:latest` version annotation is added implicitly if omitted. To pin to a specific package version
|
The `:latest` version annotation is added implicitly if omitted. To pin to a specific package version
|
||||||
([example](https://github.com/devcontainers/features/pkgs/container/features/go/versions)), append it to the end of the
|
([example](https://github.com/devcontainers/features/pkgs/container/features/go/versions)), append it to the end of the
|
||||||
feature. Features follow semantic versioning conventions, so you can pin to a major version `:1`, minor version `:1.0`, or patch version `:1.0.0` by specifying the appropriate label.
|
Feature. Features follow semantic versioning conventions, so you can pin to a major version `:1`, minor version `:1.0`, or patch version `:1.0.0` by specifying the appropriate label.
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
"features": {
|
"features": {
|
||||||
|
@ -63,7 +55,7 @@ feature. Features follow semantic versioning conventions, so you can pin to a ma
|
||||||
|
|
||||||
The [devcontainer CLI reference implementation](https://github.com/devcontainers/cli) (or a
|
The [devcontainer CLI reference implementation](https://github.com/devcontainers/cli) (or a
|
||||||
[supporting tool](https://containers.dev/supporting)) can be used to build a project's dev container declaring
|
[supporting tool](https://containers.dev/supporting)) can be used to build a project's dev container declaring
|
||||||
'features'.
|
Features.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <my-project-with-devcontainer>
|
git clone <my-project-with-devcontainer>
|
||||||
|
@ -88,40 +80,36 @@ devcontainer build --workspace-folder <path-to-my-project-with-devcontainer>
|
||||||
├── test
|
├── test
|
||||||
│ ├── dotnet
|
│ ├── dotnet
|
||||||
│ │ └── test.sh
|
│ │ └── test.sh
|
||||||
│ └── go
|
│ ├── go
|
||||||
|
| | ├── scenarios.json
|
||||||
|
| | ├── test_scenario_1.json
|
||||||
│ | └── test.sh
|
│ | └── test.sh
|
||||||
| ├── ...
|
| ├── ...
|
||||||
│ │ └── test.sh
|
│ │ └── test.sh
|
||||||
├── test-scenarios
|
...
|
||||||
│ ├── install_jupyterlab.sh
|
|
||||||
│ ├── install_python_twice.sh
|
|
||||||
| ├── ...
|
|
||||||
│ └── scenarios.json
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- [`src`](src) - A collection of subfolders, each declaring a feature. Each subfolder contains at least a
|
- [`src`](src) - A collection of subfolders, each declaring a Feature. Each subfolder contains at least a
|
||||||
`devcontainer-feature.json` and an `install.sh` script.
|
`devcontainer-feature.json` and an `install.sh` script.
|
||||||
- [`test`](test) - Mirroring `src`, a folder-per-feature with at least a `test.sh` script. The
|
- [`test`](test) - Mirroring `src`, a folder-per-feature with at least a `test.sh` script. The
|
||||||
[`devcontainer` CLI](https://github.com/devcontainers/cli) will execute
|
[`devcontainer` CLI](https://github.com/devcontainers/cli) will execute
|
||||||
[these tests in CI](https://github.com/devcontainers/features/blob/main/.github/workflows/test-all.yaml).
|
[these tests in CI](https://github.com/devcontainers/features/blob/main/.github/workflows/test-all.yaml).
|
||||||
- [`test-scenarios`](test-scenarios) - More complex scenarios involving a set of features from this repo. The
|
|
||||||
[`devcontainer` CLI](https://github.com/devcontainers/cli) will execute
|
|
||||||
[these tests in CI](https://github.com/devcontainers/features/blob/main/.github/workflows/test-scenarios.yaml).
|
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|
||||||
### Creating your own collection of features
|
### Creating your own collection of Features
|
||||||
|
|
||||||
Please see the
|
The [Feature distribution specification](https://containers.dev/implementors/features-distribution/) outlines a pattern for community members and organizations to self-author Features in repositories they control.
|
||||||
[proposed specification](https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-features-distribution.md)
|
|
||||||
on how to start to author and distribute your own features.
|
|
||||||
|
|
||||||
We're excited for you to create features! Our team is actively iterating on tools and examples to help members of the
|
A template repo [`devcontainers/feature-template`](https://github.com/devcontainers/feature-template) and [GitHub Action](https://github.com/devcontainers/action) are available to help bootstrap self-authored Features.
|
||||||
community author their own dev container features. If you have any feedback along the way, please let us know in the
|
|
||||||
specification repo's issues on [features](https://github.com/devcontainers/spec/issues/61) or
|
We are eager to hear your feedback on self-authoring! Please provide comments and feedback on [spec issue #70](https://github.com/devcontainers/spec/issues/70).
|
||||||
[feature distribution](https://github.com/devcontainers/spec/issues/70).
|
|
||||||
|
|
||||||
### Contributing to this repository
|
### Contributing to this repository
|
||||||
|
|
||||||
This repository will accept improvement and bug fix contributions related to the
|
This repository will accept improvement and bug fix contributions related to the
|
||||||
[current set of maintained features](./src).
|
[current set of maintained Features](./src).
|
||||||
|
|
||||||
|
🤝 You can read more about how to contribute in [`CONTRIBUTING.md`]. ❤️
|
||||||
|
|
||||||
|
[`CONTRIBUTING.md`]: CONTRIBUTING.md
|
||||||
|
|
|
@ -11,3 +11,10 @@ As covered in the [user FAQ](https://docs.anaconda.com/anaconda/user-guide/faq)
|
||||||
```bash
|
```bash
|
||||||
conda install python=3.7
|
conda install python=3.7
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/anaconda:1": {
|
"ghcr.io/devcontainers/features/anaconda:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -34,6 +32,13 @@ conda install python=3.7
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/anaconda/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/anaconda/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "anaconda",
|
"id": "anaconda",
|
||||||
"version": "1.0.0",
|
"version": "1.0.11",
|
||||||
"name": "Anaconda",
|
"name": "Anaconda",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/anaconda",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -14,6 +15,9 @@
|
||||||
},
|
},
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"CONDA_DIR": "/usr/local/conda",
|
"CONDA_DIR": "/usr/local/conda",
|
||||||
"PATH": "${PATH}:${CONDA_DIR}/bin:"
|
"PATH": "/usr/local/conda/bin:${PATH}"
|
||||||
}
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,17 @@
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
|
|
||||||
VERSION=${VERSION:-"latest"}
|
VERSION="${VERSION:-"latest"}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
UPDATE_RC=${UPDATE_RC:-"true"}
|
UPDATE_RC="${UPDATE_RC:-"true"}"
|
||||||
CONDA_DIR=${CONDA_DIR:-"/usr/local/conda"}
|
CONDA_DIR="${CONDA_DIR:-"/usr/local/conda"}"
|
||||||
|
|
||||||
set -eux
|
set -eux
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -64,7 +67,10 @@ updaterc() {
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt-get update
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -83,7 +89,7 @@ if ! conda --version &> /dev/null ; then
|
||||||
chown -R "${USERNAME}:conda" "${CONDA_DIR}"
|
chown -R "${USERNAME}:conda" "${CONDA_DIR}"
|
||||||
chmod -R g+r+w "${CONDA_DIR}"
|
chmod -R g+r+w "${CONDA_DIR}"
|
||||||
|
|
||||||
find "${CONDA_DIR}" -type d | xargs -n 1 chmod g+s
|
find "${CONDA_DIR}" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
echo "Installing Anaconda..."
|
echo "Installing Anaconda..."
|
||||||
|
|
||||||
CONDA_VERSION=$VERSION
|
CONDA_VERSION=$VERSION
|
||||||
|
@ -103,4 +109,32 @@ if ! conda --version &> /dev/null ; then
|
||||||
updaterc "export CONDA_DIR=${CONDA_DIR}/bin"
|
updaterc "export CONDA_DIR=${CONDA_DIR}/bin"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Display a notice on conda when not running in GitHub Codespaces
|
||||||
|
mkdir -p /usr/local/etc/vscode-dev-containers
|
||||||
|
cat << 'EOF' > /usr/local/etc/vscode-dev-containers/conda-notice.txt
|
||||||
|
When using "conda" from outside of GitHub Codespaces, note the Anaconda repository contains
|
||||||
|
restrictions on commercial use that may impact certain organizations. See https://aka.ms/ghcs-conda
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
notice_script="$(cat << 'EOF'
|
||||||
|
if [ -t 1 ] && [ "${IGNORE_NOTICE}" != "true" ] && [ "${TERM_PROGRAM}" = "vscode" ] && [ "${CODESPACES}" != "true" ] && [ ! -f "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed" ]; then
|
||||||
|
cat "/usr/local/etc/vscode-dev-containers/conda-notice.txt"
|
||||||
|
mkdir -p "$HOME/.config/vscode-dev-containers"
|
||||||
|
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed") &)
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -f "/etc/zsh/zshrc" ]; then
|
||||||
|
echo "${notice_script}" | tee -a /etc/zsh/zshrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/etc/bash.bashrc" ]; then
|
||||||
|
echo "${notice_script}" | tee -a /etc/bash.bashrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
7
src/aws-cli/NOTES.md
Normal file
7
src/aws-cli/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
Available versions of the AWS CLI can be found here: https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst.
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Installs the AWS CLI along with needed dependencies. Useful for base Dockerfiles
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/aws-cli:1": {
|
"ghcr.io/devcontainers/features/aws-cli:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -17,8 +15,21 @@ Installs the AWS CLI along with needed dependencies. Useful for base Dockerfiles
|
||||||
|
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter an AWS CLI version. (Available versions here: https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst) | string | latest |
|
| version | Select or enter an AWS CLI version. | string | latest |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `AmazonWebServices.aws-toolkit-vscode`
|
||||||
|
|
||||||
|
Available versions of the AWS CLI can be found here: https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst.
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "aws-cli",
|
"id": "aws-cli",
|
||||||
"version": "1.0.0",
|
"version": "1.0.7",
|
||||||
"name": "AWS CLI",
|
"name": "AWS CLI",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/aws-cli",
|
||||||
"description": "Installs the AWS CLI along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
|
"description": "Installs the AWS CLI along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -10,10 +11,17 @@
|
||||||
"latest"
|
"latest"
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select or enter an AWS CLI version. (Available versions here: https://github.com/aws/aws-cli/blob/v2/CHANGELOG.rst)"
|
"description": "Select or enter an AWS CLI version."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"AmazonWebServices.aws-toolkit-vscode"
|
"AmazonWebServices.aws-toolkit-vscode"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
VERSION=${VERSION:-"latest"}
|
VERSION=${VERSION:-"latest"}
|
||||||
|
|
||||||
AWSCLI_GPG_KEY=FB5DB77FD5C118B80511ADA8A6310ACC4672475C
|
AWSCLI_GPG_KEY=FB5DB77FD5C118B80511ADA8A6310ACC4672475C
|
||||||
|
@ -47,36 +50,19 @@ if [ "$(id -u)" -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
apt_get_update()
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -88,9 +74,6 @@ check_packages curl ca-certificates gnupg2 dirmngr unzip
|
||||||
verify_aws_cli_gpg_signature() {
|
verify_aws_cli_gpg_signature() {
|
||||||
local filePath=$1
|
local filePath=$1
|
||||||
local sigFilePath=$2
|
local sigFilePath=$2
|
||||||
|
|
||||||
get_common_setting AWSCLI_GPG_KEY
|
|
||||||
get_common_setting AWSCLI_GPG_KEY_MATERIAL true
|
|
||||||
local awsGpgKeyring=aws-cli-public-key.gpg
|
local awsGpgKeyring=aws-cli-public-key.gpg
|
||||||
|
|
||||||
echo "${AWSCLI_GPG_KEY_MATERIAL}" | gpg --dearmor > "./${awsGpgKeyring}"
|
echo "${AWSCLI_GPG_KEY_MATERIAL}" | gpg --dearmor > "./${awsGpgKeyring}"
|
||||||
|
@ -138,4 +121,7 @@ echo "(*) Installing AWS CLI..."
|
||||||
|
|
||||||
install
|
install
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
7
src/azure-cli/NOTES.md
Normal file
7
src/azure-cli/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Installs the Azure CLI along with needed dependencies. Useful for base Dockerfil
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/azure-cli:1": {
|
"ghcr.io/devcontainers/features/azure-cli:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,7 +16,23 @@ Installs the Azure CLI along with needed dependencies. Useful for base Dockerfil
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter an Azure CLI version. (Available versions may vary by Linux distribution.) | string | latest |
|
| version | Select or enter an Azure CLI version. (Available versions may vary by Linux distribution.) | string | latest |
|
||||||
|
| extensions | Optional comma separated list of Azure CLI extensions to install in profile. | string | - |
|
||||||
|
| installBicep | Optionally install Azure Bicep | boolean | false |
|
||||||
|
| installUsingPython | Install Azure CLI using Python instead of pipx | boolean | false |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `ms-vscode.azurecli`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "azure-cli",
|
"id": "azure-cli",
|
||||||
"version": "1.0.0",
|
"version": "1.2.2",
|
||||||
"name": "Azure CLI",
|
"name": "Azure CLI",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/azure-cli",
|
||||||
"description": "Installs the Azure CLI along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
|
"description": "Installs the Azure CLI along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like gpg.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -11,9 +12,31 @@
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select or enter an Azure CLI version. (Available versions may vary by Linux distribution.)"
|
"description": "Select or enter an Azure CLI version. (Available versions may vary by Linux distribution.)"
|
||||||
|
},
|
||||||
|
"extensions": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Optional comma separated list of Azure CLI extensions to install in profile."
|
||||||
|
},
|
||||||
|
"installBicep": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Optionally install Azure Bicep",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"installUsingPython": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Install Azure CLI using Python instead of pipx",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-vscode.azurecli"
|
"ms-vscode.azurecli"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
|
@ -9,8 +9,13 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
AZ_VERSION=${VERSION:-"latest"}
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
AZ_VERSION=${VERSION:-"latest"}
|
||||||
|
AZ_EXTENSIONS=${EXTENSIONS}
|
||||||
|
AZ_INSTALLBICEP=${INSTALLBICEP:-false}
|
||||||
|
INSTALL_USING_PYTHON=${INSTALL_USING_PYTHON:-true}
|
||||||
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
||||||
AZCLI_ARCHIVE_ARCHITECTURES="amd64"
|
AZCLI_ARCHIVE_ARCHITECTURES="amd64"
|
||||||
AZCLI_ARCHIVE_VERSION_CODENAMES="stretch buster bullseye bionic focal jammy"
|
AZCLI_ARCHIVE_VERSION_CODENAMES="stretch buster bullseye bionic focal jammy"
|
||||||
|
@ -20,42 +25,30 @@ if [ "$(id -u)" -ne 0 ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
if [ -z "${_REMOTE_USER}" ]; then
|
||||||
get_common_setting() {
|
echo -e 'Feature script must be executed by a tool that implements the dev container specification. See https://containers.dev/ for more information.'
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
exit 1
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
fi
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
echo "Effective REMOTE_USER: ${_REMOTE_USER}"
|
||||||
apt_get_update_if_needed()
|
|
||||||
|
apt_get_update()
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
# Soft version matching that resolves a version for a given package in the *current apt-cache*
|
# Soft version matching that resolves a version for a given package in the *current apt-cache*
|
||||||
# Return value is stored in first argument (the unprocessed version)
|
# Return value is stored in first argument (the unprocessed version)
|
||||||
apt_cache_version_soft_match() {
|
apt_cache_version_soft_match() {
|
||||||
|
@ -102,7 +95,6 @@ install_using_apt() {
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
|
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
|
||||||
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
|
# Import key safely (new 'signed-by' method rather than deprecated apt-key approach) and install
|
||||||
get_common_setting MICROSOFT_GPG_KEYS_URI
|
|
||||||
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
||||||
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/azure-cli/ ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/azure-cli.list
|
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/azure-cli/ ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/azure-cli.list
|
||||||
apt-get update
|
apt-get update
|
||||||
|
@ -124,10 +116,46 @@ install_using_apt() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_using_pip() {
|
install_using_pip_strategy() {
|
||||||
|
local ver=""
|
||||||
|
if [ "${AZ_VERSION}" = "latest" ] || [ "${AZ_VERSION}" = "lts" ] || [ "${AZ_VERSION}" = "stable" ]; then
|
||||||
|
# Empty, meaning grab the "latest" in the apt repo
|
||||||
|
ver=""
|
||||||
|
else
|
||||||
|
ver="==${AZ_VERSION}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${INSTALL_USING_PYTHON}" = "true" ]; then
|
||||||
|
install_with_complete_python_installation "${ver}" || install_with_pipx "${ver}" || return 1
|
||||||
|
else
|
||||||
|
install_with_pipx "${ver}" || install_with_complete_python_installation "${ver}" || return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_with_pipx() {
|
||||||
|
echo "(*) Attempting to install globally with pipx..."
|
||||||
|
local ver="$1"
|
||||||
|
export
|
||||||
|
local
|
||||||
|
|
||||||
|
if ! type pipx > /dev/null 2>&1; then
|
||||||
|
echo "(*) Installing pipx..."
|
||||||
|
check_packages pipx
|
||||||
|
pipx ensurepath # Ensures PIPX_BIN_DIR is on the PATH
|
||||||
|
fi
|
||||||
|
|
||||||
|
PIPX_HOME="/usr/local/pipx" \
|
||||||
|
PIPX_BIN_DIR=/usr/local/bin \
|
||||||
|
pipx install azure-cli${ver}
|
||||||
|
|
||||||
|
echo "(*) Finished installing globally with pipx."
|
||||||
|
}
|
||||||
|
|
||||||
|
install_with_complete_python_installation() {
|
||||||
|
local ver="$1"
|
||||||
echo "(*) No pre-built binaries available in apt-cache. Installing via pip3."
|
echo "(*) No pre-built binaries available in apt-cache. Installing via pip3."
|
||||||
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
|
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
|
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
|
||||||
fi
|
fi
|
||||||
export PIPX_HOME=/usr/local/pipx
|
export PIPX_HOME=/usr/local/pipx
|
||||||
|
@ -141,25 +169,20 @@ install_using_pip() {
|
||||||
pipx_bin=/tmp/pip-tmp/bin/pipx
|
pipx_bin=/tmp/pip-tmp/bin/pipx
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${AZ_VERSION}" = "latest" ] || [ "${AZ_VERSION}" = "lts" ] || [ "${AZ_VERSION}" = "stable" ]; then
|
|
||||||
# Empty, meaning grab the "latest" in the apt repo
|
|
||||||
ver=""
|
|
||||||
else
|
|
||||||
ver="==${AZ_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' -f azure-cli${ver}
|
${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' -f azure-cli${ver}
|
||||||
|
|
||||||
# Fail gracefully
|
# Fail gracefully
|
||||||
if [ "$?" != 0 ]; then
|
if [ "$?" != 0 ]; then
|
||||||
echo "Could not install azure-cli${ver} via pip"
|
echo "Could not install azure-cli${ver} via pip3"
|
||||||
rm -rf /tmp/pip-tmp
|
rm -rf /tmp/pip-tmp
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
set -e
|
set -e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# See if we're on x86_64 and if so, install via apt-get, otherwise use pip3
|
# See if we're on x86_64 and if so, install via apt-get, otherwise use pip3
|
||||||
echo "(*) Installing Azure CLI..."
|
echo "(*) Installing Azure CLI..."
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
|
@ -173,7 +196,7 @@ fi
|
||||||
|
|
||||||
if [ "${use_pip}" = "true" ]; then
|
if [ "${use_pip}" = "true" ]; then
|
||||||
AZ_VERSION=${CACHED_AZURE_VERSION}
|
AZ_VERSION=${CACHED_AZURE_VERSION}
|
||||||
install_using_pip
|
install_using_pip_strategy
|
||||||
|
|
||||||
if [ "$?" != 0 ]; then
|
if [ "$?" != 0 ]; then
|
||||||
echo "Please provide a valid version for your distribution ${ID} ${VERSION_CODENAME} (${architecture})."
|
echo "Please provide a valid version for your distribution ${ID} ${VERSION_CODENAME} (${architecture})."
|
||||||
|
@ -184,4 +207,42 @@ if [ "${use_pip}" = "true" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# If Azure CLI extensions are requested, loop through and install
|
||||||
|
if [ ${#AZ_EXTENSIONS[@]} -gt 0 ]; then
|
||||||
|
echo "Installing Azure CLI extensions: ${AZ_EXTENSIONS}"
|
||||||
|
extensions=(`echo ${AZ_EXTENSIONS} | tr ',' ' '`)
|
||||||
|
for i in "${extensions[@]}"
|
||||||
|
do
|
||||||
|
echo "Installing ${i}"
|
||||||
|
su ${_REMOTE_USER} -c "az extension add --name ${i} -y" || continue
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${AZ_INSTALLBICEP}" = "true" ]; then
|
||||||
|
# Install dependencies
|
||||||
|
check_packages apt-transport-https curl
|
||||||
|
|
||||||
|
# Properly install Azure Bicep based on current architecture
|
||||||
|
# The `az bicep install` command installs the linux-x64 binary even on arm64 devcontainers
|
||||||
|
# The `az bicep install --target-platform` could be a solution; however, linux-arm64 is not an allowed value for this argument yet
|
||||||
|
# Manually installing Bicep and moving to the appropriate directory where az expects it to be
|
||||||
|
|
||||||
|
if [ "${architecture}" = "arm64" ]; then
|
||||||
|
curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-arm64
|
||||||
|
else
|
||||||
|
curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x ./bicep
|
||||||
|
mv ./bicep /usr/local/bin/bicep
|
||||||
|
|
||||||
|
# Add a symlink so bicep can be accessed as a standalone executable or as part of az
|
||||||
|
mkdir -p ${_REMOTE_USER_HOME}/.azure/bin
|
||||||
|
chown -hR ${_REMOTE_USER}:${_REMOTE_USER} ${_REMOTE_USER_HOME}/.azure
|
||||||
|
ln -s /usr/local/bin/bicep ${_REMOTE_USER_HOME}/.azure/bin/bicep
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
|
@ -1,12 +1,26 @@
|
||||||
## Speeding up the command prompt in large repositories
|
## OS Support
|
||||||
|
|
||||||
This script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt since the required git status command can be slow. To resolve this, you can update a git setting to remove the git portion of the command prompt.
|
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, RockyLinux, and Alpine Linux.
|
||||||
|
|
||||||
To disable the prompt for the current folder's repository, enter the following in a terminal or add it to your `postCreateCommand` or dotfiles:
|
## Using with dev container images
|
||||||
|
|
||||||
|
This Feature is used in many of the [dev container images](https://github.com/search?q=repo%3Adevcontainers%2Fimages+%22ghcr.io%2Fdevcontainers%2Ffeatures%2Fcommon-utils%22&type=code), as a result
|
||||||
|
these images have already allocated UID & GID 1000. Attempting to add this Feature with UID 1000 and/or GID 1000 on top of such a dev container image will result in an error when building the dev container.
|
||||||
|
|
||||||
|
## Customizing the command prompt
|
||||||
|
|
||||||
|
By default, this script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt due to the performance of needed git operations.
|
||||||
|
|
||||||
|
For performance reasons, a "dirty" indicator that tells you whether or not there are uncommitted changes is disabled by default. You can opt to turn this on for smaller repositories by entering the following in a terminal or adding it to your `postCreateCommand`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git config codespaces-theme.hide-status 1
|
git config devcontainers-theme.show-dirty 1
|
||||||
```
|
```
|
||||||
|
|
||||||
This setting will survive a rebuild since it is applied to the repository rather than the container.
|
To completely disable the git portion of the prompt for the current folder's repository, you can use this configuration setting instead:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git config devcontainers-theme.hide-status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
For `zsh`, the default theme is a [standard Oh My Zsh! theme](https://ohmyz.sh/). You may pick a different one by modifying the `ZSH_THEME` variable in `~/.zshrc`.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
# Common Debian Utilities (common-utils)
|
# Common Utilities (common-utils)
|
||||||
|
|
||||||
Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.
|
Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.
|
||||||
|
|
||||||
|
@ -7,9 +7,7 @@ Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-r
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/common-utils:1": {
|
"ghcr.io/devcontainers/features/common-utils:2": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,25 +16,41 @@ Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-r
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| installZsh | Install ZSH? | boolean | true |
|
| installZsh | Install ZSH? | boolean | true |
|
||||||
|
| configureZshAsDefaultShell | Change default shell to ZSH? | boolean | false |
|
||||||
| installOhMyZsh | Install Oh My Zsh!? | boolean | true |
|
| installOhMyZsh | Install Oh My Zsh!? | boolean | true |
|
||||||
|
| installOhMyZshConfig | Allow installing the default dev container .zshrc templates? | boolean | true |
|
||||||
| upgradePackages | Upgrade OS packages? | boolean | true |
|
| upgradePackages | Upgrade OS packages? | boolean | true |
|
||||||
| username | Enter name of non-root user to configure or none to skip | string | automatic |
|
| username | Enter name of a non-root user to configure or none to skip | string | automatic |
|
||||||
| uid | Enter uid for non-root user | string | automatic |
|
| userUid | Enter UID for non-root user | string | automatic |
|
||||||
| gid | Enter gid for non-root user | string | automatic |
|
| userGid | Enter GID for non-root user | string | automatic |
|
||||||
| nonFreePackages | Add packages from non-free Debian repository? | boolean | - |
|
| nonFreePackages | Add packages from non-free Debian repository? (Debian only) | boolean | false |
|
||||||
|
|
||||||
## Speeding up the command prompt in large repositories
|
## OS Support
|
||||||
|
|
||||||
This script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt since the required git status command can be slow. To resolve this, you can update a git setting to remove the git portion of the command prompt.
|
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, RockyLinux, and Alpine Linux.
|
||||||
|
|
||||||
To disable the prompt for the current folder's repository, enter the following in a terminal or add it to your `postCreateCommand` or dotfiles:
|
## Using with dev container images
|
||||||
|
|
||||||
|
This Feature is used in many of the [dev container images](https://github.com/search?q=repo%3Adevcontainers%2Fimages+%22ghcr.io%2Fdevcontainers%2Ffeatures%2Fcommon-utils%22&type=code), as a result
|
||||||
|
these images have already allocated UID & GID 1000. Attempting to add this Feature with UID 1000 and/or GID 1000 on top of such a dev container image will result in an error when building the dev container.
|
||||||
|
|
||||||
|
## Customizing the command prompt
|
||||||
|
|
||||||
|
By default, this script provides a custom command prompt that includes information about the git repository for the current folder. However, with certain large repositories, this can result in a slow command prompt due to the performance of needed git operations.
|
||||||
|
|
||||||
|
For performance reasons, a "dirty" indicator that tells you whether or not there are uncommitted changes is disabled by default. You can opt to turn this on for smaller repositories by entering the following in a terminal or adding it to your `postCreateCommand`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git config codespaces-theme.hide-status 1
|
git config devcontainers-theme.show-dirty 1
|
||||||
```
|
```
|
||||||
|
|
||||||
This setting will survive a rebuild since it is applied to the repository rather than the container.
|
To completely disable the git portion of the prompt for the current folder's repository, you can use this configuration setting instead:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git config devcontainers-theme.hide-status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
For `zsh`, the default theme is a [standard Oh My Zsh! theme](https://ohmyz.sh/). You may pick a different one by modifying the `ZSH_THEME` variable in `~/.zshrc`.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
16
src/common-utils/bin/code
Executable file
16
src/common-utils/bin/code
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
get_in_path_except_current() {
|
||||||
|
which -a "$1" | grep -A1 "$0" | grep -v "$0"
|
||||||
|
}
|
||||||
|
|
||||||
|
code="$(get_in_path_except_current code)"
|
||||||
|
|
||||||
|
if [ -n "$code" ]; then
|
||||||
|
exec "$code" "$@"
|
||||||
|
elif [ "$(command -v code-insiders)" ]; then
|
||||||
|
exec code-insiders "$@"
|
||||||
|
else
|
||||||
|
echo "code or code-insiders is not installed" >&2
|
||||||
|
exit 127
|
||||||
|
fi
|
35
src/common-utils/bin/devcontainer-info
Executable file
35
src/common-utils/bin/devcontainer-info
Executable file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Load meta.env
|
||||||
|
if [ -f "/usr/local/etc/vscode-dev-containers/meta.env" ]; then
|
||||||
|
. /usr/local/etc/vscode-dev-containers/meta.env
|
||||||
|
fi
|
||||||
|
if [ -f "/usr/local/etc/dev-containers/meta.env" ]; then
|
||||||
|
. /usr/local/etc/dev-containers/meta.env
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Minimal output
|
||||||
|
if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then
|
||||||
|
echo "${VERSION}"
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" = "release" ]; then
|
||||||
|
echo "${GIT_REPOSITORY_RELEASE}"
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then
|
||||||
|
echo "${CONTENTS_URL}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Full output
|
||||||
|
echo
|
||||||
|
echo "Development container image information"
|
||||||
|
echo
|
||||||
|
if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi
|
||||||
|
if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi
|
||||||
|
if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi
|
||||||
|
if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi
|
||||||
|
if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi
|
||||||
|
if [ ! -z "${GIT_REPOSITORY_REVISION}" ]; then echo "- Source code revision: ${GIT_REPOSITORY_REVISION}"; fi
|
||||||
|
if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi
|
||||||
|
if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi
|
||||||
|
echo
|
7
src/common-utils/bin/systemctl
Executable file
7
src/common-utils/bin/systemctl
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
if [ -d "/run/systemd/system" ]; then
|
||||||
|
exec /bin/systemctl "$@"
|
||||||
|
else
|
||||||
|
echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all'
|
||||||
|
fi
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "common-utils",
|
"id": "common-utils",
|
||||||
"name": "Common Debian Utilities",
|
"version": "2.3.1",
|
||||||
"version": "1.0.1",
|
"name": "Common Utilities",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/common-utils",
|
||||||
"description": "Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.",
|
"description": "Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.",
|
||||||
"options": {
|
"options": {
|
||||||
"installZsh": {
|
"installZsh": {
|
||||||
|
@ -9,11 +10,21 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Install ZSH?"
|
"description": "Install ZSH?"
|
||||||
},
|
},
|
||||||
|
"configureZshAsDefaultShell": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Change default shell to ZSH?"
|
||||||
|
},
|
||||||
"installOhMyZsh": {
|
"installOhMyZsh": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Install Oh My Zsh!?"
|
"description": "Install Oh My Zsh!?"
|
||||||
},
|
},
|
||||||
|
"installOhMyZshConfig": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Allow installing the default dev container .zshrc templates?"
|
||||||
|
},
|
||||||
"upgradePackages": {
|
"upgradePackages": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
|
@ -22,39 +33,37 @@
|
||||||
"username": {
|
"username": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"proposals": [
|
"proposals": [
|
||||||
|
"devcontainer",
|
||||||
"vscode",
|
"vscode",
|
||||||
"codespace",
|
"codespace",
|
||||||
"none",
|
"none",
|
||||||
"automatic"
|
"automatic"
|
||||||
],
|
],
|
||||||
"default": "automatic",
|
"default": "automatic",
|
||||||
"description": "Enter name of non-root user to configure or none to skip"
|
"description": "Enter name of a non-root user to configure or none to skip"
|
||||||
},
|
},
|
||||||
"uid": {
|
"userUid": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"proposals": [
|
"proposals": [
|
||||||
"1000",
|
"1001",
|
||||||
"automatic"
|
"automatic"
|
||||||
],
|
],
|
||||||
"default": "automatic",
|
"default": "automatic",
|
||||||
"description": "Enter uid for non-root user"
|
"description": "Enter UID for non-root user"
|
||||||
},
|
},
|
||||||
"gid": {
|
"userGid": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"proposals": [
|
"proposals": [
|
||||||
"1000",
|
"1001",
|
||||||
"automatic"
|
"automatic"
|
||||||
],
|
],
|
||||||
"default": "automatic",
|
"default": "automatic",
|
||||||
"description": "Enter gid for non-root user"
|
"description": "Enter GID for non-root user"
|
||||||
},
|
},
|
||||||
"nonFreePackages": {
|
"nonFreePackages": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Add packages from non-free Debian repository?"
|
"description": "Add packages from non-free Debian repository? (Debian only)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"extensions": [
|
|
||||||
"ms-dotnettools.csharp"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,474 +1,36 @@
|
||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
#-------------------------------------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------------------------------------------------
|
||||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information.
|
||||||
#-------------------------------------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/common.md
|
# Docs: https://github.com/devcontainers/features/tree/main/src/common-utils
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
INSTALL_ZSH=${INSTALLZSH:-"true"}
|
INSTALL_ZSH="${INSTALLZSH:-"true"}"
|
||||||
INSTALL_OH_MY_ZSH=${INSTALLOHMYZSH:-"true"}
|
CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}"
|
||||||
UPGRADE_PACKAGES=${UPGRADEPACKAGES:-"true"}
|
INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}"
|
||||||
USER_UID=${UID:-"automatic"}
|
UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}"
|
||||||
USER_GID=${GID:-"automatic"}
|
USERNAME="${USERNAME:-"automatic"}"
|
||||||
ADD_NON_FREE_PACKAGES=${NONFREEPACKAGES:-"false"}
|
USER_UID="${UID:-"automatic"}"
|
||||||
|
USER_GID="${GID:-"automatic"}"
|
||||||
DEV_CONTAINERS_DIR="/usr/local/etc/vscode-dev-containers"
|
ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}"
|
||||||
MARKER_FILE="${DEV_CONTAINERS_DIR}/common"
|
|
||||||
|
|
||||||
|
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
|
# If we're using Alpine, install bash before executing
|
||||||
rm -f /etc/profile.d/00-restore-env.sh
|
. /etc/os-release
|
||||||
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
|
if [ "${ID}" = "alpine" ]; then
|
||||||
chmod +x /etc/profile.d/00-restore-env.sh
|
apk add --no-cache bash
|
||||||
|
|
||||||
# If in automatic mode, determine if a user already exists, if not use vscode
|
|
||||||
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
|
|
||||||
USERNAME=""
|
|
||||||
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
|
|
||||||
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
|
|
||||||
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
|
|
||||||
USERNAME=${CURRENT_USER}
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ "${USERNAME}" = "" ]; then
|
|
||||||
USERNAME=vscode
|
|
||||||
fi
|
|
||||||
elif [ "${USERNAME}" = "none" ]; then
|
|
||||||
USERNAME=root
|
|
||||||
USER_UID=0
|
|
||||||
USER_GID=0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Load markers to see which steps have already run
|
exec /bin/bash "$(dirname $0)/main.sh" "$@"
|
||||||
if [ -f "${MARKER_FILE}" ]; then
|
exit $?
|
||||||
echo "Marker file found:"
|
|
||||||
cat "${MARKER_FILE}"
|
|
||||||
source "${MARKER_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure apt is in non-interactive to avoid prompts
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
# Function to call apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
|
||||||
echo "Running apt-get update..."
|
|
||||||
apt-get update
|
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies
|
|
||||||
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
|
|
||||||
|
|
||||||
package_list="apt-utils \
|
|
||||||
openssh-client \
|
|
||||||
gnupg2 \
|
|
||||||
dirmngr \
|
|
||||||
iproute2 \
|
|
||||||
procps \
|
|
||||||
lsof \
|
|
||||||
htop \
|
|
||||||
net-tools \
|
|
||||||
psmisc \
|
|
||||||
curl \
|
|
||||||
tree \
|
|
||||||
wget \
|
|
||||||
rsync \
|
|
||||||
ca-certificates \
|
|
||||||
unzip \
|
|
||||||
zip \
|
|
||||||
nano \
|
|
||||||
vim-tiny \
|
|
||||||
less \
|
|
||||||
jq \
|
|
||||||
lsb-release \
|
|
||||||
apt-transport-https \
|
|
||||||
dialog \
|
|
||||||
libc6 \
|
|
||||||
libgcc1 \
|
|
||||||
libkrb5-3 \
|
|
||||||
libgssapi-krb5-2 \
|
|
||||||
libicu[0-9][0-9] \
|
|
||||||
liblttng-ust[0-9] \
|
|
||||||
libstdc++6 \
|
|
||||||
zlib1g \
|
|
||||||
locales \
|
|
||||||
sudo \
|
|
||||||
ncdu \
|
|
||||||
man-db \
|
|
||||||
strace \
|
|
||||||
manpages \
|
|
||||||
manpages-dev \
|
|
||||||
init-system-helpers"
|
|
||||||
|
|
||||||
# Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
|
|
||||||
if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
|
|
||||||
# Bring in variables from /etc/os-release like VERSION_CODENAME
|
|
||||||
. /etc/os-release
|
|
||||||
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
|
|
||||||
# Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html
|
|
||||||
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
|
|
||||||
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
|
|
||||||
echo "Running apt-get update..."
|
|
||||||
apt-get update
|
|
||||||
package_list="${package_list} manpages-posix manpages-posix-dev"
|
|
||||||
else
|
|
||||||
apt_get_update_if_needed
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install libssl1.1 if available
|
|
||||||
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
|
|
||||||
package_list="${package_list} libssl1.1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install appropriate version of libssl1.0.x if available
|
|
||||||
libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
|
|
||||||
if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
|
|
||||||
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
|
|
||||||
# Debian 9
|
|
||||||
package_list="${package_list} libssl1.0.2"
|
|
||||||
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
|
|
||||||
# Ubuntu 18.04, 16.04, earlier
|
|
||||||
package_list="${package_list} libssl1.0.0"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Packages to verify are installed: ${package_list}"
|
|
||||||
apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
|
|
||||||
|
|
||||||
# Install git if not already installed (may be more recent than distro version)
|
|
||||||
if ! type git > /dev/null 2>&1; then
|
|
||||||
apt-get -y install --no-install-recommends git
|
|
||||||
fi
|
|
||||||
|
|
||||||
PACKAGES_ALREADY_INSTALLED="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get to latest versions of all packages
|
|
||||||
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
|
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get -y upgrade --no-install-recommends
|
|
||||||
apt-get autoremove -y
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure at least the en_US.UTF-8 UTF-8 locale is available.
|
|
||||||
# Common need for both applications and things like the agnoster ZSH theme.
|
|
||||||
if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
|
|
||||||
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
|
|
||||||
locale-gen
|
|
||||||
LOCALE_ALREADY_SET="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create or update a non-root user to match UID/GID.
|
|
||||||
group_name="${USERNAME}"
|
|
||||||
if id -u ${USERNAME} > /dev/null 2>&1; then
|
|
||||||
# User exists, update if needed
|
|
||||||
if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then
|
|
||||||
group_name="$(id -gn $USERNAME)"
|
|
||||||
groupmod --gid $USER_GID ${group_name}
|
|
||||||
usermod --gid $USER_GID $USERNAME
|
|
||||||
fi
|
|
||||||
if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
|
|
||||||
usermod --uid $USER_UID $USERNAME
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Create user
|
|
||||||
if [ "${USER_GID}" = "automatic" ]; then
|
|
||||||
groupadd $USERNAME
|
|
||||||
else
|
|
||||||
groupadd --gid $USER_GID $USERNAME
|
|
||||||
fi
|
|
||||||
if [ "${USER_UID}" = "automatic" ]; then
|
|
||||||
useradd -s /bin/bash --gid $USERNAME -m $USERNAME
|
|
||||||
else
|
|
||||||
useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add add sudo support for non-root user
|
|
||||||
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
|
|
||||||
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
|
|
||||||
chmod 0440 /etc/sudoers.d/$USERNAME
|
|
||||||
EXISTING_NON_ROOT_USER="${USERNAME}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ** Shell customization section **
|
|
||||||
if [ "${USERNAME}" = "root" ]; then
|
|
||||||
user_rc_path="/root"
|
|
||||||
else
|
|
||||||
user_rc_path="/home/${USERNAME}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty
|
|
||||||
if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then
|
|
||||||
cp /etc/skel/.bashrc "${user_rc_path}/.bashrc"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore user .profile defaults from skeleton file if it doesn't exist or is empty
|
|
||||||
if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then
|
|
||||||
cp /etc/skel/.profile "${user_rc_path}/.profile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# .bashrc/.zshrc snippet
|
|
||||||
rc_snippet="$(cat << 'EOF'
|
|
||||||
|
|
||||||
if [ -z "${USER}" ]; then export USER=$(whoami); fi
|
|
||||||
if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
|
|
||||||
|
|
||||||
# Display optional first run image specific notice if configured and terminal is interactive
|
|
||||||
if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
|
|
||||||
if [ -f "${DEV_CONTAINERS_DIR}/first-run-notice.txt" ]; then
|
|
||||||
cat "${DEV_CONTAINERS_DIR}/first-run-notice.txt"
|
|
||||||
elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
|
|
||||||
cat "/workspaces/.codespaces/shared/first-run-notice.txt"
|
|
||||||
fi
|
|
||||||
mkdir -p "$HOME/.config/vscode-dev-containers"
|
|
||||||
# Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
|
|
||||||
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set the default git editor if not already set
|
|
||||||
if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
|
|
||||||
if [ "${TERM_PROGRAM}" = "vscode" ]; then
|
|
||||||
if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
|
|
||||||
export GIT_EDITOR="code-insiders --wait"
|
|
||||||
else
|
|
||||||
export GIT_EDITOR="code --wait"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
# code shim, it fallbacks to code-insiders if code is not available
|
|
||||||
cat << 'EOF' > /usr/local/bin/code
|
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
get_in_path_except_current() {
|
|
||||||
which -a "$1" | grep -A1 "$0" | grep -v "$0"
|
|
||||||
}
|
|
||||||
|
|
||||||
code="$(get_in_path_except_current code)"
|
|
||||||
|
|
||||||
if [ -n "$code" ]; then
|
|
||||||
exec "$code" "$@"
|
|
||||||
elif [ "$(command -v code-insiders)" ]; then
|
|
||||||
exec code-insiders "$@"
|
|
||||||
else
|
|
||||||
echo "code or code-insiders is not installed" >&2
|
|
||||||
exit 127
|
|
||||||
fi
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/code
|
|
||||||
|
|
||||||
# systemctl shim - tells people to use 'service' if systemd is not running
|
|
||||||
cat << 'EOF' > /usr/local/bin/systemctl
|
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
if [ -d "/run/systemd/system" ]; then
|
|
||||||
exec /bin/systemctl/systemctl "$@"
|
|
||||||
else
|
|
||||||
echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all'
|
|
||||||
fi
|
|
||||||
EOF
|
|
||||||
chmod +x /usr/local/bin/systemctl
|
|
||||||
|
|
||||||
# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
|
|
||||||
codespaces_bash="$(cat \
|
|
||||||
<<'EOF'
|
|
||||||
|
|
||||||
# Codespaces bash prompt theme
|
|
||||||
__bash_prompt() {
|
|
||||||
local userpart='`export XIT=$? \
|
|
||||||
&& [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
|
|
||||||
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
|
|
||||||
local gitbranch='`\
|
|
||||||
if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
|
|
||||||
export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \
|
|
||||||
if [ "${BRANCH}" != "" ]; then \
|
|
||||||
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
|
|
||||||
&& if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
|
|
||||||
echo -n " \[\033[1;33m\]✗"; \
|
|
||||||
fi \
|
|
||||||
&& echo -n "\[\033[0;36m\]) "; \
|
|
||||||
fi; \
|
|
||||||
fi`'
|
|
||||||
local lightblue='\[\033[1;34m\]'
|
|
||||||
local removecolor='\[\033[0m\]'
|
|
||||||
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
|
|
||||||
unset -f __bash_prompt
|
|
||||||
}
|
|
||||||
__bash_prompt
|
|
||||||
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
codespaces_zsh="$(cat \
|
|
||||||
<<'EOF'
|
|
||||||
# Codespaces zsh prompt theme
|
|
||||||
__zsh_prompt() {
|
|
||||||
local prompt_username
|
|
||||||
if [ ! -z "${GITHUB_USER}" ]; then
|
|
||||||
prompt_username="@${GITHUB_USER}"
|
|
||||||
else
|
|
||||||
prompt_username="%n"
|
|
||||||
fi
|
|
||||||
PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow
|
|
||||||
PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd
|
|
||||||
PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status
|
|
||||||
PROMPT+='%{$fg[white]%}$ %{$reset_color%}'
|
|
||||||
unset -f __zsh_prompt
|
|
||||||
}
|
|
||||||
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}"
|
|
||||||
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
|
|
||||||
ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})"
|
|
||||||
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})"
|
|
||||||
__zsh_prompt
|
|
||||||
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
# Add RC snippet and custom bash prompt
|
|
||||||
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
|
|
||||||
echo "${rc_snippet}" >> /etc/bash.bashrc
|
|
||||||
echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc"
|
|
||||||
echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc"
|
|
||||||
if [ "${USERNAME}" != "root" ]; then
|
|
||||||
echo "${codespaces_bash}" >> "/root/.bashrc"
|
|
||||||
echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc"
|
|
||||||
fi
|
|
||||||
chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc"
|
|
||||||
RC_SNIPPET_ALREADY_ADDED="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Optionally install and configure zsh and Oh My Zsh!
|
|
||||||
if [ "${INSTALL_ZSH}" = "true" ]; then
|
|
||||||
if ! type zsh > /dev/null 2>&1; then
|
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get install -y zsh
|
|
||||||
fi
|
|
||||||
if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
|
|
||||||
echo "${rc_snippet}" >> /etc/zsh/zshrc
|
|
||||||
ZSH_ALREADY_INSTALLED="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
|
|
||||||
# See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
|
|
||||||
oh_my_install_dir="${user_rc_path}/.oh-my-zsh"
|
|
||||||
if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MY_ZSH}" = "true" ]; then
|
|
||||||
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
|
|
||||||
user_rc_file="${user_rc_path}/.zshrc"
|
|
||||||
umask g-w,o-w
|
|
||||||
mkdir -p ${oh_my_install_dir}
|
|
||||||
git clone --depth=1 \
|
|
||||||
-c core.eol=lf \
|
|
||||||
-c core.autocrlf=false \
|
|
||||||
-c fsck.zeroPaddedFilemode=ignore \
|
|
||||||
-c fetch.fsck.zeroPaddedFilemode=ignore \
|
|
||||||
-c receive.fsck.zeroPaddedFilemode=ignore \
|
|
||||||
"https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
|
|
||||||
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
|
|
||||||
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file}
|
|
||||||
|
|
||||||
mkdir -p ${oh_my_install_dir}/custom/themes
|
|
||||||
echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
|
|
||||||
# Shrink git while still enabling updates
|
|
||||||
cd "${oh_my_install_dir}"
|
|
||||||
git repack -a -d -f --depth=1 --window=1
|
|
||||||
# Copy to non-root user if one is specified
|
|
||||||
if [ "${USERNAME}" != "root" ]; then
|
|
||||||
cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root
|
|
||||||
chown -R ${USERNAME}:${group_name} "${user_rc_path}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Persist image metadata info, script if meta.env found in same directory
|
|
||||||
meta_info_script="$(cat << 'EOF'
|
|
||||||
#!/bin/sh
|
|
||||||
. /usr/local/etc/vscode-dev-containers/meta.env
|
|
||||||
|
|
||||||
# Minimal output
|
|
||||||
if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then
|
|
||||||
echo "${VERSION}"
|
|
||||||
exit 0
|
|
||||||
elif [ "$1" = "release" ]; then
|
|
||||||
echo "${GIT_REPOSITORY_RELEASE}"
|
|
||||||
exit 0
|
|
||||||
elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then
|
|
||||||
echo "${CONTENTS_URL}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
#Full output
|
|
||||||
echo
|
|
||||||
echo "Development container image information"
|
|
||||||
echo
|
|
||||||
if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi
|
|
||||||
if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi
|
|
||||||
if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi
|
|
||||||
if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi
|
|
||||||
if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi
|
|
||||||
if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi
|
|
||||||
if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi
|
|
||||||
echo
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
if [ -f "${DEV_CONTAINERS_DIR}/meta.env" ]; then
|
|
||||||
echo "${meta_info_script}" > /usr/local/bin/devcontainer-info
|
|
||||||
chmod +x /usr/local/bin/devcontainer-info
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "${DEV_CONTAINERS_DIR}" ]; then
|
|
||||||
mkdir -p "$(dirname "${MARKER_FILE}")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Write marker file
|
|
||||||
echo -e "\
|
|
||||||
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
|
|
||||||
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
|
|
||||||
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
|
|
||||||
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
|
|
||||||
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
|
|
||||||
|
|
||||||
# Display a notice on conda when not running in GitHub Codespaces
|
|
||||||
cat << 'EOF' > ${DEV_CONTAINERS_DIR}/conda-notice.txt
|
|
||||||
When using "conda" from outside of GitHub Codespaces, note the Anaconda repository contains
|
|
||||||
restrictions on commercial use that may impact certain organizations. See https://aka.ms/ghcs-conda
|
|
||||||
|
|
||||||
EOF
|
|
||||||
|
|
||||||
notice_script="$(cat << 'EOF'
|
|
||||||
if [ -t 1 ] && [ "${IGNORE_NOTICE}" != "true" ] && [ "${TERM_PROGRAM}" = "vscode" ] && [ "${CODESPACES}" != "true" ] && [ ! -f "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed" ]; then
|
|
||||||
cat "${DEV_CONTAINERS_DIR}/conda-notice.txt"
|
|
||||||
mkdir -p "$HOME/.config/vscode-dev-containers"
|
|
||||||
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed") &)
|
|
||||||
fi
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
echo "${notice_script}" | tee -a /etc/bash.bashrc >> /etc/zsh/zshrc
|
|
||||||
|
|
||||||
echo "Done!"
|
|
||||||
|
|
573
src/common-utils/main.sh
Normal file
573
src/common-utils/main.sh
Normal file
|
@ -0,0 +1,573 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Docs: https://github.com/devcontainers/features/tree/main/src/common-utils
|
||||||
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
INSTALL_ZSH="${INSTALLZSH:-"true"}"
|
||||||
|
CONFIGURE_ZSH_AS_DEFAULT_SHELL="${CONFIGUREZSHASDEFAULTSHELL:-"false"}"
|
||||||
|
INSTALL_OH_MY_ZSH="${INSTALLOHMYZSH:-"true"}"
|
||||||
|
INSTALL_OH_MY_ZSH_CONFIG="${INSTALLOHMYZSHCONFIG:-"true"}"
|
||||||
|
UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}"
|
||||||
|
USERNAME="${USERNAME:-"automatic"}"
|
||||||
|
USER_UID="${USERUID:-"automatic"}"
|
||||||
|
USER_GID="${USERGID:-"automatic"}"
|
||||||
|
ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}"
|
||||||
|
|
||||||
|
MARKER_FILE="/usr/local/etc/vscode-dev-containers/common"
|
||||||
|
|
||||||
|
FEATURE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
# Debian / Ubuntu packages
|
||||||
|
install_debian_packages() {
|
||||||
|
# Ensure apt is in non-interactive to avoid prompts
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
local package_list=""
|
||||||
|
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
|
||||||
|
package_list="${package_list} \
|
||||||
|
apt-utils \
|
||||||
|
openssh-client \
|
||||||
|
gnupg2 \
|
||||||
|
dirmngr \
|
||||||
|
iproute2 \
|
||||||
|
procps \
|
||||||
|
lsof \
|
||||||
|
htop \
|
||||||
|
net-tools \
|
||||||
|
psmisc \
|
||||||
|
curl \
|
||||||
|
tree \
|
||||||
|
wget \
|
||||||
|
rsync \
|
||||||
|
ca-certificates \
|
||||||
|
unzip \
|
||||||
|
bzip2 \
|
||||||
|
zip \
|
||||||
|
nano \
|
||||||
|
vim-tiny \
|
||||||
|
less \
|
||||||
|
jq \
|
||||||
|
lsb-release \
|
||||||
|
apt-transport-https \
|
||||||
|
dialog \
|
||||||
|
libc6 \
|
||||||
|
libgcc1 \
|
||||||
|
libkrb5-3 \
|
||||||
|
libgssapi-krb5-2 \
|
||||||
|
libicu[0-9][0-9] \
|
||||||
|
liblttng-ust[0-9] \
|
||||||
|
libstdc++6 \
|
||||||
|
zlib1g \
|
||||||
|
locales \
|
||||||
|
sudo \
|
||||||
|
ncdu \
|
||||||
|
man-db \
|
||||||
|
strace \
|
||||||
|
manpages \
|
||||||
|
manpages-dev \
|
||||||
|
init-system-helpers"
|
||||||
|
|
||||||
|
# Include libssl1.1 if available
|
||||||
|
if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then
|
||||||
|
package_list="${package_list} libssl1.1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Include libssl3 if available
|
||||||
|
if [[ ! -z $(apt-cache --names-only search ^libssl3$) ]]; then
|
||||||
|
package_list="${package_list} libssl3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Include appropriate version of libssl1.0.x if available
|
||||||
|
local libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '')
|
||||||
|
if [ "$(echo "$libssl_package" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then
|
||||||
|
if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then
|
||||||
|
# Debian 9
|
||||||
|
package_list="${package_list} libssl1.0.2"
|
||||||
|
elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then
|
||||||
|
# Ubuntu 18.04
|
||||||
|
package_list="${package_list} libssl1.0.0"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Include git if not already installed (may be more recent than distro version)
|
||||||
|
if ! type git > /dev/null 2>&1; then
|
||||||
|
package_list="${package_list} git"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian
|
||||||
|
if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then
|
||||||
|
# Bring in variables from /etc/os-release like VERSION_CODENAME
|
||||||
|
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list
|
||||||
|
# Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html
|
||||||
|
sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
|
||||||
|
sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
package_list="${package_list} manpages-posix manpages-posix-dev"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install the list of packages
|
||||||
|
echo "Packages to verify are installed: ${package_list}"
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
apt-get update -y
|
||||||
|
apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 )
|
||||||
|
|
||||||
|
# Install zsh (and recommended packages) if needed
|
||||||
|
if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then
|
||||||
|
apt-get install -y zsh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get to latest versions of all packages
|
||||||
|
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
|
||||||
|
apt-get -y upgrade --no-install-recommends
|
||||||
|
apt-get autoremove -y
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure at least the en_US.UTF-8 UTF-8 locale is available = common need for both applications and things like the agnoster ZSH theme.
|
||||||
|
if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then
|
||||||
|
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
|
||||||
|
locale-gen
|
||||||
|
LOCALE_ALREADY_SET="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PACKAGES_ALREADY_INSTALLED="true"
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
apt-get -y clean
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
}
|
||||||
|
|
||||||
|
# RedHat / RockyLinux / CentOS / Fedora packages
|
||||||
|
install_redhat_packages() {
|
||||||
|
local package_list=""
|
||||||
|
local remove_epel="false"
|
||||||
|
local install_cmd=dnf
|
||||||
|
if ! type dnf > /dev/null 2>&1; then
|
||||||
|
install_cmd=yum
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
|
||||||
|
package_list="${package_list} \
|
||||||
|
gawk \
|
||||||
|
openssh-clients \
|
||||||
|
gnupg2 \
|
||||||
|
iproute \
|
||||||
|
procps \
|
||||||
|
lsof \
|
||||||
|
net-tools \
|
||||||
|
psmisc \
|
||||||
|
wget \
|
||||||
|
ca-certificates \
|
||||||
|
rsync \
|
||||||
|
unzip \
|
||||||
|
zip \
|
||||||
|
nano \
|
||||||
|
vim-minimal \
|
||||||
|
less \
|
||||||
|
jq \
|
||||||
|
openssl-libs \
|
||||||
|
krb5-libs \
|
||||||
|
libicu \
|
||||||
|
zlib \
|
||||||
|
sudo \
|
||||||
|
sed \
|
||||||
|
grep \
|
||||||
|
which \
|
||||||
|
man-db \
|
||||||
|
strace"
|
||||||
|
|
||||||
|
# rockylinux:9 installs 'curl-minimal' which clashes with 'curl'
|
||||||
|
# Install 'curl' for every OS except this rockylinux:9
|
||||||
|
if [[ "${ID}" = "rocky" ]] && [[ "${VERSION}" != *"9."* ]]; then
|
||||||
|
package_list="${package_list} curl"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install OpenSSL 1.0 compat if needed
|
||||||
|
if ${install_cmd} -q list compat-openssl10 >/dev/null 2>&1; then
|
||||||
|
package_list="${package_list} compat-openssl10"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install lsb_release if available
|
||||||
|
if ${install_cmd} -q list redhat-lsb-core >/dev/null 2>&1; then
|
||||||
|
package_list="${package_list} redhat-lsb-core"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install git if not already installed (may be more recent than distro version)
|
||||||
|
if ! type git > /dev/null 2>&1; then
|
||||||
|
package_list="${package_list} git"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install EPEL repository if needed (required to install 'jq' for CentOS)
|
||||||
|
if ! ${install_cmd} -q list jq >/dev/null 2>&1; then
|
||||||
|
${install_cmd} -y install epel-release
|
||||||
|
remove_epel="true"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install zsh if needed
|
||||||
|
if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then
|
||||||
|
package_list="${package_list} zsh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${package_list}" ]; then
|
||||||
|
${install_cmd} -y install ${package_list}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get to latest versions of all packages
|
||||||
|
if [ "${UPGRADE_PACKAGES}" = "true" ]; then
|
||||||
|
${install_cmd} upgrade -y
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${remove_epel}" = "true" ]]; then
|
||||||
|
${install_cmd} -y remove epel-release
|
||||||
|
fi
|
||||||
|
|
||||||
|
PACKAGES_ALREADY_INSTALLED="true"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Alpine Linux packages
|
||||||
|
install_alpine_packages() {
|
||||||
|
apk update
|
||||||
|
|
||||||
|
if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then
|
||||||
|
apk add --no-cache \
|
||||||
|
openssh-client \
|
||||||
|
gnupg \
|
||||||
|
procps \
|
||||||
|
lsof \
|
||||||
|
htop \
|
||||||
|
net-tools \
|
||||||
|
psmisc \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
rsync \
|
||||||
|
ca-certificates \
|
||||||
|
unzip \
|
||||||
|
zip \
|
||||||
|
nano \
|
||||||
|
vim \
|
||||||
|
less \
|
||||||
|
jq \
|
||||||
|
libgcc \
|
||||||
|
libstdc++ \
|
||||||
|
krb5-libs \
|
||||||
|
libintl \
|
||||||
|
libssl1.1 \
|
||||||
|
lttng-ust \
|
||||||
|
tzdata \
|
||||||
|
userspace-rcu \
|
||||||
|
zlib \
|
||||||
|
sudo \
|
||||||
|
coreutils \
|
||||||
|
sed \
|
||||||
|
grep \
|
||||||
|
which \
|
||||||
|
ncdu \
|
||||||
|
shadow \
|
||||||
|
strace
|
||||||
|
|
||||||
|
# Install man pages - package name varies between 3.12 and earlier versions
|
||||||
|
if apk info man > /dev/null 2>&1; then
|
||||||
|
apk add --no-cache man man-pages
|
||||||
|
else
|
||||||
|
apk add --no-cache mandoc man-pages
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install git if not already installed (may be more recent than distro version)
|
||||||
|
if ! type git > /dev/null 2>&1; then
|
||||||
|
apk add --no-cache git
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install zsh if needed
|
||||||
|
if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then
|
||||||
|
apk add --no-cache zsh
|
||||||
|
fi
|
||||||
|
|
||||||
|
PACKAGES_ALREADY_INSTALLED="true"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ******************
|
||||||
|
# ** Main section **
|
||||||
|
# ******************
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load markers to see which steps have already run
|
||||||
|
if [ -f "${MARKER_FILE}" ]; then
|
||||||
|
echo "Marker file found:"
|
||||||
|
cat "${MARKER_FILE}"
|
||||||
|
source "${MARKER_FILE}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
|
||||||
|
rm -f /etc/profile.d/00-restore-env.sh
|
||||||
|
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
|
||||||
|
chmod +x /etc/profile.d/00-restore-env.sh
|
||||||
|
|
||||||
|
# Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME
|
||||||
|
. /etc/os-release
|
||||||
|
# Get an adjusted ID independent of distro variants
|
||||||
|
if [ "${ID}" = "debian" ] || [ "${ID_LIKE}" = "debian" ]; then
|
||||||
|
ADJUSTED_ID="debian"
|
||||||
|
elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then
|
||||||
|
ADJUSTED_ID="rhel"
|
||||||
|
elif [ "${ID}" = "alpine" ]; then
|
||||||
|
ADJUSTED_ID="alpine"
|
||||||
|
else
|
||||||
|
echo "Linux distro ${ID} not supported."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install packages for appropriate OS
|
||||||
|
case "${ADJUSTED_ID}" in
|
||||||
|
"debian")
|
||||||
|
install_debian_packages
|
||||||
|
;;
|
||||||
|
"rhel")
|
||||||
|
install_redhat_packages
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
install_alpine_packages
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# If in automatic mode, determine if a user already exists, if not use vscode
|
||||||
|
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
|
||||||
|
if [ "${_REMOTE_USER}" != "root" ]; then
|
||||||
|
USERNAME="${_REMOTE_USER}"
|
||||||
|
else
|
||||||
|
USERNAME=""
|
||||||
|
POSSIBLE_USERS=("devcontainer" "vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
|
||||||
|
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
|
||||||
|
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
|
||||||
|
USERNAME=${CURRENT_USER}
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "${USERNAME}" = "" ]; then
|
||||||
|
USERNAME=vscode
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "${USERNAME}" = "none" ]; then
|
||||||
|
USERNAME=root
|
||||||
|
USER_UID=0
|
||||||
|
USER_GID=0
|
||||||
|
fi
|
||||||
|
# Create or update a non-root user to match UID/GID.
|
||||||
|
group_name="${USERNAME}"
|
||||||
|
if id -u ${USERNAME} > /dev/null 2>&1; then
|
||||||
|
# User exists, update if needed
|
||||||
|
if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then
|
||||||
|
group_name="$(id -gn $USERNAME)"
|
||||||
|
groupmod --gid $USER_GID ${group_name}
|
||||||
|
usermod --gid $USER_GID $USERNAME
|
||||||
|
fi
|
||||||
|
if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then
|
||||||
|
usermod --uid $USER_UID $USERNAME
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Create user
|
||||||
|
if [ "${USER_GID}" = "automatic" ]; then
|
||||||
|
groupadd $USERNAME
|
||||||
|
else
|
||||||
|
groupadd --gid $USER_GID $USERNAME
|
||||||
|
fi
|
||||||
|
if [ "${USER_UID}" = "automatic" ]; then
|
||||||
|
useradd -s /bin/bash --gid $USERNAME -m $USERNAME
|
||||||
|
else
|
||||||
|
useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add add sudo support for non-root user
|
||||||
|
if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then
|
||||||
|
echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME
|
||||||
|
chmod 0440 /etc/sudoers.d/$USERNAME
|
||||||
|
EXISTING_NON_ROOT_USER="${USERNAME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# *********************************
|
||||||
|
# ** Shell customization section **
|
||||||
|
# *********************************
|
||||||
|
|
||||||
|
if [ "${USERNAME}" = "root" ]; then
|
||||||
|
user_home="/root"
|
||||||
|
# Check if user already has a home directory other than /home/${USERNAME}
|
||||||
|
elif [ "/home/${USERNAME}" != $( getent passwd $USERNAME | cut -d: -f6 ) ]; then
|
||||||
|
user_home=$( getent passwd $USERNAME | cut -d: -f6 )
|
||||||
|
else
|
||||||
|
user_home="/home/${USERNAME}"
|
||||||
|
if [ ! -d "${user_home}" ]; then
|
||||||
|
mkdir -p "${user_home}"
|
||||||
|
chown ${USERNAME}:${group_name} "${user_home}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Restore user .bashrc / .profile / .zshrc defaults from skeleton file if it doesn't exist or is empty
|
||||||
|
possible_rc_files=( ".bashrc" ".profile" )
|
||||||
|
[ "$INSTALL_OH_MY_ZSH_CONFIG" == "true" ] && possible_rc_files+=('.zshrc')
|
||||||
|
[ "$INSTALL_ZSH" == "true" ] && possible_rc_files+=('.zprofile')
|
||||||
|
for rc_file in "${possible_rc_files[@]}"; do
|
||||||
|
if [ -f "/etc/skel/${rc_file}" ]; then
|
||||||
|
if [ ! -e "${user_home}/${rc_file}" ] || [ ! -s "${user_home}/${rc_file}" ]; then
|
||||||
|
cp "/etc/skel/${rc_file}" "${user_home}/${rc_file}"
|
||||||
|
chown ${USERNAME}:${group_name} "${user_home}/${rc_file}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add RC snippet and custom bash prompt
|
||||||
|
if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then
|
||||||
|
case "${ADJUSTED_ID}" in
|
||||||
|
"debian")
|
||||||
|
global_rc_path="/etc/bash.bashrc"
|
||||||
|
;;
|
||||||
|
"rhel")
|
||||||
|
global_rc_path="/etc/bashrc"
|
||||||
|
;;
|
||||||
|
"alpine")
|
||||||
|
global_rc_path="/etc/bash/bashrc"
|
||||||
|
# /etc/bash/bashrc does not exist in alpine 3.14 & 3.15
|
||||||
|
mkdir -p /etc/bash
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
cat "${FEATURE_DIR}/scripts/rc_snippet.sh" >> ${global_rc_path}
|
||||||
|
cat "${FEATURE_DIR}/scripts/bash_theme_snippet.sh" >> "${user_home}/.bashrc"
|
||||||
|
if [ "${USERNAME}" != "root" ]; then
|
||||||
|
cat "${FEATURE_DIR}/scripts/bash_theme_snippet.sh" >> "/root/.bashrc"
|
||||||
|
chown ${USERNAME}:${group_name} "${user_home}/.bashrc"
|
||||||
|
fi
|
||||||
|
RC_SNIPPET_ALREADY_ADDED="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally configure zsh and Oh My Zsh!
|
||||||
|
if [ "${INSTALL_ZSH}" = "true" ]; then
|
||||||
|
if [ ! -f "${user_home}/.zprofile" ]; then
|
||||||
|
touch "${user_home}/.zprofile"
|
||||||
|
echo 'source $HOME/.profile' >> "${user_home}/.zprofile" # TODO: Reconsider adding '.profile' to '.zprofile'
|
||||||
|
chown ${USERNAME}:${group_name} "${user_home}/.zprofile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then
|
||||||
|
if [ "${ADJUSTED_ID}" = "rhel" ]; then
|
||||||
|
global_rc_path="/etc/zshrc"
|
||||||
|
else
|
||||||
|
global_rc_path="/etc/zsh/zshrc"
|
||||||
|
fi
|
||||||
|
cat "${FEATURE_DIR}/scripts/rc_snippet.sh" >> ${global_rc_path}
|
||||||
|
ZSH_ALREADY_INSTALLED="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${CONFIGURE_ZSH_AS_DEFAULT_SHELL}" == "true" ]; then
|
||||||
|
# Fixing chsh always asking for a password on alpine linux
|
||||||
|
# ref: https://askubuntu.com/questions/812420/chsh-always-asking-a-password-and-get-pam-authentication-failure.
|
||||||
|
if [ ! -f "/etc/pam.d/chsh" ] || ! grep -Eq '^auth(.*)pam_rootok\.so$' /etc/pam.d/chsh; then
|
||||||
|
echo "auth sufficient pam_rootok.so" >> /etc/pam.d/chsh
|
||||||
|
elif [[ -n "$(awk '/^auth(.*)pam_rootok\.so$/ && !/^auth[[:blank:]]+sufficient[[:blank:]]+pam_rootok\.so$/' /etc/pam.d/chsh)" ]]; then
|
||||||
|
awk '/^auth(.*)pam_rootok\.so$/ { $2 = "sufficient" } { print }' /etc/pam.d/chsh > /tmp/chsh.tmp && mv /tmp/chsh.tmp /etc/pam.d/chsh
|
||||||
|
fi
|
||||||
|
|
||||||
|
chsh --shell /bin/zsh ${USERNAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme.
|
||||||
|
# See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script.
|
||||||
|
if [ "${INSTALL_OH_MY_ZSH}" = "true" ]; then
|
||||||
|
user_rc_file="${user_home}/.zshrc"
|
||||||
|
oh_my_install_dir="${user_home}/.oh-my-zsh"
|
||||||
|
template_path="${oh_my_install_dir}/templates/zshrc.zsh-template"
|
||||||
|
if [ ! -d "${oh_my_install_dir}" ]; then
|
||||||
|
umask g-w,o-w
|
||||||
|
mkdir -p ${oh_my_install_dir}
|
||||||
|
git clone --depth=1 \
|
||||||
|
-c core.eol=lf \
|
||||||
|
-c core.autocrlf=false \
|
||||||
|
-c fsck.zeroPaddedFilemode=ignore \
|
||||||
|
-c fetch.fsck.zeroPaddedFilemode=ignore \
|
||||||
|
-c receive.fsck.zeroPaddedFilemode=ignore \
|
||||||
|
"https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1
|
||||||
|
|
||||||
|
# Shrink git while still enabling updates
|
||||||
|
cd "${oh_my_install_dir}"
|
||||||
|
git repack -a -d -f --depth=1 --window=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add Dev Containers theme
|
||||||
|
mkdir -p ${oh_my_install_dir}/custom/themes
|
||||||
|
cp -f "${FEATURE_DIR}/scripts/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme"
|
||||||
|
ln -sf "${oh_my_install_dir}/custom/themes/devcontainers.zsh-theme" "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme"
|
||||||
|
|
||||||
|
# Add devcontainer .zshrc template
|
||||||
|
if [ "$INSTALL_OH_MY_ZSH_CONFIG" = "true" ]; then
|
||||||
|
echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file}
|
||||||
|
sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="devcontainers"/g' ${user_rc_file}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy to non-root user if one is specified
|
||||||
|
if [ "${USERNAME}" != "root" ]; then
|
||||||
|
copy_to_user_files=("${oh_my_install_dir}")
|
||||||
|
[ -f "$user_rc_file" ] && copy_to_user_files+=("$user_rc_file")
|
||||||
|
cp -rf "${copy_to_user_files[@]}" /root
|
||||||
|
chown -R ${USERNAME}:${group_name} "${copy_to_user_files[@]}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# *********************************
|
||||||
|
# ** Ensure config directory **
|
||||||
|
# *********************************
|
||||||
|
user_config_dir="${user_home}/.config"
|
||||||
|
if [ ! -d "${user_config_dir}" ]; then
|
||||||
|
mkdir -p "${user_config_dir}"
|
||||||
|
chown ${USERNAME}:${group_name} "${user_config_dir}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ****************************
|
||||||
|
# ** Utilities and commands **
|
||||||
|
# ****************************
|
||||||
|
|
||||||
|
# code shim, it fallbacks to code-insiders if code is not available
|
||||||
|
cp -f "${FEATURE_DIR}/bin/code" /usr/local/bin/
|
||||||
|
chmod +rx /usr/local/bin/code
|
||||||
|
|
||||||
|
# systemctl shim for Debian/Ubuntu - tells people to use 'service' if systemd is not running
|
||||||
|
if [ "${ADJUSTED_ID}" = "debian" ]; then
|
||||||
|
cp -f "${FEATURE_DIR}/bin/systemctl" /usr/local/bin/systemctl
|
||||||
|
chmod +rx /usr/local/bin/systemctl
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Persist image metadata info, script if meta.env found in same directory
|
||||||
|
if [ -f "/usr/local/etc/vscode-dev-containers/meta.env" ] || [ -f "/usr/local/etc/dev-containers/meta.env" ]; then
|
||||||
|
cp -f "${FEATURE_DIR}/bin/devcontainer-info" /usr/local/bin/devcontainer-info
|
||||||
|
chmod +rx /usr/local/bin/devcontainer-info
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Write marker file
|
||||||
|
if [ ! -d "/usr/local/etc/vscode-dev-containers" ]; then
|
||||||
|
mkdir -p "$(dirname "${MARKER_FILE}")"
|
||||||
|
fi
|
||||||
|
echo -e "\
|
||||||
|
PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\
|
||||||
|
LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\
|
||||||
|
EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\
|
||||||
|
RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\
|
||||||
|
ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}"
|
||||||
|
|
||||||
|
echo "Done!"
|
25
src/common-utils/scripts/bash_theme_snippet.sh
Normal file
25
src/common-utils/scripts/bash_theme_snippet.sh
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
# bash theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
|
||||||
|
__bash_prompt() {
|
||||||
|
local userpart='`export XIT=$? \
|
||||||
|
&& [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \
|
||||||
|
&& [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`'
|
||||||
|
local gitbranch='`\
|
||||||
|
if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
|
||||||
|
export BRANCH=$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null); \
|
||||||
|
if [ "${BRANCH}" != "" ]; then \
|
||||||
|
echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \
|
||||||
|
&& if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \
|
||||||
|
git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
|
||||||
|
echo -n " \[\033[1;33m\]✗"; \
|
||||||
|
fi \
|
||||||
|
&& echo -n "\[\033[0;36m\]) "; \
|
||||||
|
fi; \
|
||||||
|
fi`'
|
||||||
|
local lightblue='\[\033[1;34m\]'
|
||||||
|
local removecolor='\[\033[0m\]'
|
||||||
|
PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ "
|
||||||
|
unset -f __bash_prompt
|
||||||
|
}
|
||||||
|
__bash_prompt
|
||||||
|
export PROMPT_DIRTRIM=4
|
26
src/common-utils/scripts/devcontainers.zsh-theme
Normal file
26
src/common-utils/scripts/devcontainers.zsh-theme
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Oh My Zsh! theme - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme
|
||||||
|
__zsh_prompt() {
|
||||||
|
local prompt_username
|
||||||
|
if [ ! -z "${GITHUB_USER}" ]; then
|
||||||
|
prompt_username="@${GITHUB_USER}"
|
||||||
|
else
|
||||||
|
prompt_username="%n"
|
||||||
|
fi
|
||||||
|
PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow
|
||||||
|
PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd
|
||||||
|
PROMPT+='`\
|
||||||
|
if [ "$(git config --get devcontainers-theme.hide-status 2>/dev/null)" != 1 ] && [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \
|
||||||
|
export BRANCH=$(git --no-optional-locks symbolic-ref --short HEAD 2>/dev/null || git --no-optional-locks rev-parse --short HEAD 2>/dev/null); \
|
||||||
|
if [ "${BRANCH}" != "" ]; then \
|
||||||
|
echo -n "%{$fg_bold[cyan]%}(%{$fg_bold[red]%}${BRANCH}" \
|
||||||
|
&& if [ "$(git config --get devcontainers-theme.show-dirty 2>/dev/null)" = 1 ] && \
|
||||||
|
git --no-optional-locks ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \
|
||||||
|
echo -n " %{$fg_bold[yellow]%}✗"; \
|
||||||
|
fi \
|
||||||
|
&& echo -n "%{$fg_bold[cyan]%})%{$reset_color%} "; \
|
||||||
|
fi; \
|
||||||
|
fi`'
|
||||||
|
PROMPT+='%{$fg[white]%}$ %{$reset_color%}'
|
||||||
|
unset -f __zsh_prompt
|
||||||
|
}
|
||||||
|
__zsh_prompt
|
26
src/common-utils/scripts/rc_snippet.sh
Normal file
26
src/common-utils/scripts/rc_snippet.sh
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
if [ -z "${USER}" ]; then export USER=$(whoami); fi
|
||||||
|
if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi
|
||||||
|
|
||||||
|
# Display optional first run image specific notice if configured and terminal is interactive
|
||||||
|
if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then
|
||||||
|
if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then
|
||||||
|
cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt"
|
||||||
|
elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then
|
||||||
|
cat "/workspaces/.codespaces/shared/first-run-notice.txt"
|
||||||
|
fi
|
||||||
|
mkdir -p "$HOME/.config/vscode-dev-containers"
|
||||||
|
# Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it
|
||||||
|
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set the default git editor if not already set
|
||||||
|
if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then
|
||||||
|
if [ "${TERM_PROGRAM}" = "vscode" ]; then
|
||||||
|
if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then
|
||||||
|
export GIT_EDITOR="code-insiders --wait"
|
||||||
|
else
|
||||||
|
export GIT_EDITOR="code --wait"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
20
src/conda/NOTES.md
Normal file
20
src/conda/NOTES.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
## Using Conda
|
||||||
|
|
||||||
|
This Feature includes [the `conda` package manager](https://docs.conda.io/projects/conda/en/latest/index.html) which is a part of the [Anaconda Distribution](https://repo.anaconda.com). Additional packages installed using Conda will be downloaded from Anaconda or another repository if you configure one. To reconfigure Conda in this container to access an alternative repository, please see information on [configuring Conda channels here](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/channels.html ).
|
||||||
|
|
||||||
|
Access to the Anaconda repository is covered by the [Anaconda Terms of Service](https://legal.anaconda.com/policies/en/?name=terms-of-service), which may require some organizations to obtain a commercial license from Anaconda. **However**, when used with GitHub Codespaces or GitHub Actions, **all users are permitted** to use the Anaconda Repository through the service, including organizations normally required by Anaconda to obtain a paid license for commercial activities. Note that third-party packages may be licensed by their publishers in ways that impact your intellectual property, and are used at your own risk.
|
||||||
|
|
||||||
|
## Installing a different version of Python
|
||||||
|
|
||||||
|
As covered in the [user FAQ](https://docs.anaconda.com/anaconda/user-guide/faq) for Anaconda, you can install different versions of Python than the one in this image by running the following from a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda install python=3.7
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
45
src/conda/README.md
Normal file
45
src/conda/README.md
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
# Conda (conda)
|
||||||
|
|
||||||
|
A cross-platform, language-agnostic binary package manager
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```json
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/conda:1": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
| Options Id | Description | Type | Default Value |
|
||||||
|
|-----|-----|-----|-----|
|
||||||
|
| version | Select or enter a conda version. | string | latest |
|
||||||
|
| addCondaForge | Add conda-forge channel to the config? | boolean | false |
|
||||||
|
|
||||||
|
## Using Conda
|
||||||
|
|
||||||
|
This Feature includes [the `conda` package manager](https://docs.conda.io/projects/conda/en/latest/index.html) which is a part of the [Anaconda Distribution](https://repo.anaconda.com). Additional packages installed using Conda will be downloaded from Anaconda or another repository if you configure one. To reconfigure Conda in this container to access an alternative repository, please see information on [configuring Conda channels here](https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/channels.html ).
|
||||||
|
|
||||||
|
Access to the Anaconda repository is covered by the [Anaconda Terms of Service](https://legal.anaconda.com/policies/en/?name=terms-of-service), which may require some organizations to obtain a commercial license from Anaconda. **However**, when used with GitHub Codespaces or GitHub Actions, **all users are permitted** to use the Anaconda Repository through the service, including organizations normally required by Anaconda to obtain a paid license for commercial activities. Note that third-party packages may be licensed by their publishers in ways that impact your intellectual property, and are used at your own risk.
|
||||||
|
|
||||||
|
## Installing a different version of Python
|
||||||
|
|
||||||
|
As covered in the [user FAQ](https://docs.anaconda.com/anaconda/user-guide/faq) for Anaconda, you can install different versions of Python than the one in this image by running the following from a terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
conda install python=3.7
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/conda/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
32
src/conda/devcontainer-feature.json
Normal file
32
src/conda/devcontainer-feature.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"id": "conda",
|
||||||
|
"version": "1.0.9",
|
||||||
|
"name": "Conda",
|
||||||
|
"description": "A cross-platform, language-agnostic binary package manager",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/conda",
|
||||||
|
"options": {
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"proposals": [
|
||||||
|
"latest",
|
||||||
|
"4.11.0",
|
||||||
|
"4.12.0"
|
||||||
|
],
|
||||||
|
"default": "latest",
|
||||||
|
"description": "Select or enter a conda version."
|
||||||
|
},
|
||||||
|
"addCondaForge": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Add conda-forge channel to the config?"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"containerEnv": {
|
||||||
|
"CONDA_DIR": "/opt/conda",
|
||||||
|
"CONDA_SCRIPT":"/opt/conda/etc/profile.d/conda.sh",
|
||||||
|
"PATH": "/opt/conda/bin:${PATH}"
|
||||||
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
|
}
|
154
src/conda/install.sh
Normal file
154
src/conda/install.sh
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
VERSION=${VERSION:-"latest"}
|
||||||
|
ADD_CONDA_FORGE=$ADDCONDAFORGE
|
||||||
|
|
||||||
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
|
UPDATE_RC="true"
|
||||||
|
CONDA_DIR="/opt/conda"
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
|
||||||
|
rm -f /etc/profile.d/00-restore-env.sh
|
||||||
|
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
|
||||||
|
chmod +x /etc/profile.d/00-restore-env.sh
|
||||||
|
|
||||||
|
# Determine the appropriate non-root user
|
||||||
|
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
|
||||||
|
USERNAME=""
|
||||||
|
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
|
||||||
|
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
|
||||||
|
if id -u "${CURRENT_USER}" > /dev/null 2>&1; then
|
||||||
|
USERNAME="${CURRENT_USER}"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ "${USERNAME}" = "" ]; then
|
||||||
|
USERNAME=root
|
||||||
|
fi
|
||||||
|
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
|
||||||
|
USERNAME=root
|
||||||
|
fi
|
||||||
|
|
||||||
|
architecture="$(uname -m)"
|
||||||
|
if [ "${architecture}" != "x86_64" ]; then
|
||||||
|
echo "(!) Architecture $architecture unsupported"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Checks if packages are installed and installs them if not
|
||||||
|
check_packages() {
|
||||||
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
|
apt-get -y install --no-install-recommends "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo_if() {
|
||||||
|
COMMAND="$*"
|
||||||
|
if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
|
||||||
|
su - "$USERNAME" -c "$COMMAND"
|
||||||
|
else
|
||||||
|
$COMMAND
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_user_package() {
|
||||||
|
PACKAGE="$1"
|
||||||
|
sudo_if "${CONDA_DIR}/bin/python3" -m pip install --user --upgrade "$PACKAGE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Conda if it's missing
|
||||||
|
if ! conda --version &> /dev/null ; then
|
||||||
|
if ! cat /etc/group | grep -e "^conda:" > /dev/null 2>&1; then
|
||||||
|
groupadd -r conda
|
||||||
|
fi
|
||||||
|
usermod -a -G conda "${USERNAME}"
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
check_packages curl ca-certificates gnupg2
|
||||||
|
|
||||||
|
echo "Installing Conda..."
|
||||||
|
|
||||||
|
curl -sS https://repo.anaconda.com/pkgs/misc/gpgkeys/anaconda.asc | gpg --dearmor > /usr/share/keyrings/conda-archive-keyring.gpg
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/conda-archive-keyring.gpg] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main" > /etc/apt/sources.list.d/conda.list
|
||||||
|
apt-get update -y
|
||||||
|
|
||||||
|
CONDA_PKG="conda=${VERSION}-0"
|
||||||
|
if [ "${VERSION}" = "latest" ]; then
|
||||||
|
CONDA_PKG="conda"
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_packages $CONDA_PKG
|
||||||
|
|
||||||
|
CONDA_SCRIPT="/opt/conda/etc/profile.d/conda.sh"
|
||||||
|
. $CONDA_SCRIPT
|
||||||
|
|
||||||
|
if [ "${ADD_CONDA_FORGE}" = "true" ]; then
|
||||||
|
conda config --add channels conda-forge
|
||||||
|
fi
|
||||||
|
|
||||||
|
conda config --set channel_priority strict
|
||||||
|
conda config --set env_prompt '({name})'
|
||||||
|
echo "source ${CONDA_SCRIPT}" >> ~/.bashrc
|
||||||
|
|
||||||
|
chown -R "${USERNAME}:conda" "${CONDA_DIR}"
|
||||||
|
chmod -R g+r+w "${CONDA_DIR}"
|
||||||
|
|
||||||
|
find "${CONDA_DIR}" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
|
|
||||||
|
# Temporary fixes
|
||||||
|
# Due to https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23491
|
||||||
|
install_user_package certifi
|
||||||
|
# Due to https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0286 and https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23931
|
||||||
|
install_user_package cryptography
|
||||||
|
# Due to https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-40897
|
||||||
|
install_user_package setuptools
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display a notice on conda when not running in GitHub Codespaces
|
||||||
|
mkdir -p /usr/local/etc/vscode-dev-containers
|
||||||
|
cat << 'EOF' > /usr/local/etc/vscode-dev-containers/conda-notice.txt
|
||||||
|
When using "conda" from outside of GitHub Codespaces, note the Anaconda repository contains
|
||||||
|
restrictions on commercial use that may impact certain organizations. See https://aka.ms/ghcs-conda
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
notice_script="$(cat << 'EOF'
|
||||||
|
if [ -t 1 ] && [ "${IGNORE_NOTICE}" != "true" ] && [ "${TERM_PROGRAM}" = "vscode" ] && [ "${CODESPACES}" != "true" ] && [ ! -f "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed" ]; then
|
||||||
|
cat "/usr/local/etc/vscode-dev-containers/conda-notice.txt"
|
||||||
|
mkdir -p "$HOME/.config/vscode-dev-containers"
|
||||||
|
((sleep 10s; touch "$HOME/.config/vscode-dev-containers/conda-notice-already-displayed") &)
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -f "/etc/zsh/zshrc" ]; then
|
||||||
|
echo "${notice_script}" | tee -a /etc/zsh/zshrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/etc/bash.bashrc" ]; then
|
||||||
|
echo "${notice_script}" | tee -a /etc/bash.bashrc
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
echo "Done!"
|
|
@ -6,6 +6,16 @@ This feature provides two ways of connecting to the desktop environment it adds.
|
||||||
1. Open the ports view in your tool, select the noVNC port, and click the Globe icon.
|
1. Open the ports view in your tool, select the noVNC port, and click the Globe icon.
|
||||||
1. In the browser that appears, click the **Connect** button and enter the desktop password (`vscode` by default).
|
1. In the browser that appears, click the **Connect** button and enter the desktop password (`vscode` by default).
|
||||||
|
|
||||||
|
To set up the `6080` port from your `devcontainer.json` file, include the following:
|
||||||
|
```json
|
||||||
|
"forwardPorts": [6080],
|
||||||
|
"portsAttributes": {
|
||||||
|
"6080": {
|
||||||
|
"label": "desktop"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com/en/connect/download/viewer/). To do so:
|
You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com/en/connect/download/viewer/). To do so:
|
||||||
|
|
||||||
1. Connect to the environment from a desktop tool that supports the dev container spec (e.g., VS Code client).
|
1. Connect to the environment from a desktop tool that supports the dev container spec (e.g., VS Code client).
|
||||||
|
@ -15,7 +25,7 @@ You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com
|
||||||
|
|
||||||
## Customizing Fluxbox
|
## Customizing Fluxbox
|
||||||
|
|
||||||
The window manager is installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
|
The window manager installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
|
||||||
|
|
||||||
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).
|
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).
|
||||||
|
|
||||||
|
@ -27,19 +37,19 @@ See the [Fluxbox menu documentation](http://www.fluxbox.org/help/man-fluxbox-men
|
||||||
|
|
||||||
If you run into applications crashing, you may need to increase the size of the shared memory space allocated to your container. For example, this will bump it up to 1 GB in `devcontainer.json`:
|
If you run into applications crashing, you may need to increase the size of the shared memory space allocated to your container. For example, this will bump it up to 1 GB in `devcontainer.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"runArgs": ["--shm-size=1g"]
|
"runArgs": ["--shm-size=1g"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Or using Docker Compose:
|
Or using Docker Compose:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
your-service-here:
|
your-service-here:
|
||||||
# ...
|
# ...
|
||||||
shm_size: '1gb'
|
shm_size: '1gb'
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installing a browser
|
## Installing a browser
|
||||||
|
|
||||||
|
@ -59,6 +69,13 @@ If you want the full version of **Google Chrome** in the desktop:
|
||||||
&& apt-get -y install /tmp/chrome.deb
|
&& apt-get -y install /tmp/chrome.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Chrome sandbox support requires you set up and run as a non-root user. The [`debian-common.sh`](common.md) script can do this for you, or you [set one up yourself](https://aka.ms/vscode-remote/containers/non-root). Alternatively, you can start Chrome using `google-chrome --no-sandbox`
|
2. Chrome sandbox support requires you set up and run as a non-root user. The [`common-utils`](https://github.com/devcontainers/features/tree/main/src/common-utils) script can do this for you, or you [set one up yourself](https://aka.ms/vscode-remote/containers/non-root). Alternatively, you can start Chrome using `google-chrome --no-sandbox`
|
||||||
|
|
||||||
That's it!
|
That's it!
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
|
@ -7,9 +7,7 @@ Adds a lightweight Fluxbox based desktop to the container that can be accessed u
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/desktop-lite:1": {
|
"ghcr.io/devcontainers/features/desktop-lite:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -31,6 +29,16 @@ This feature provides two ways of connecting to the desktop environment it adds.
|
||||||
1. Open the ports view in your tool, select the noVNC port, and click the Globe icon.
|
1. Open the ports view in your tool, select the noVNC port, and click the Globe icon.
|
||||||
1. In the browser that appears, click the **Connect** button and enter the desktop password (`vscode` by default).
|
1. In the browser that appears, click the **Connect** button and enter the desktop password (`vscode` by default).
|
||||||
|
|
||||||
|
To set up the `6080` port from your `devcontainer.json` file, include the following:
|
||||||
|
```json
|
||||||
|
"forwardPorts": [6080],
|
||||||
|
"portsAttributes": {
|
||||||
|
"6080": {
|
||||||
|
"label": "desktop"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com/en/connect/download/viewer/). To do so:
|
You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com/en/connect/download/viewer/). To do so:
|
||||||
|
|
||||||
1. Connect to the environment from a desktop tool that supports the dev container spec (e.g., VS Code client).
|
1. Connect to the environment from a desktop tool that supports the dev container spec (e.g., VS Code client).
|
||||||
|
@ -40,7 +48,7 @@ You can also connect to the desktop using a [VNC viewer](https://www.realvnc.com
|
||||||
|
|
||||||
## Customizing Fluxbox
|
## Customizing Fluxbox
|
||||||
|
|
||||||
The window manager is installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
|
The window manager installed is [Fluxbox](http://fluxbox.org/). **Right-click** to see the application menu. In addition, any UI-based commands you execute inside the dev container will automatically appear on the desktop.
|
||||||
|
|
||||||
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).
|
You can customize the desktop using Fluxbox configuration files. The configuration files are located in the `.fluxbox` folder of the home directory of the user you using to connect to the dev container (`$HOME/.fluxbox`).
|
||||||
|
|
||||||
|
@ -52,19 +60,19 @@ See the [Fluxbox menu documentation](http://www.fluxbox.org/help/man-fluxbox-men
|
||||||
|
|
||||||
If you run into applications crashing, you may need to increase the size of the shared memory space allocated to your container. For example, this will bump it up to 1 GB in `devcontainer.json`:
|
If you run into applications crashing, you may need to increase the size of the shared memory space allocated to your container. For example, this will bump it up to 1 GB in `devcontainer.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"runArgs": ["--shm-size=1g"]
|
"runArgs": ["--shm-size=1g"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Or using Docker Compose:
|
Or using Docker Compose:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
your-service-here:
|
your-service-here:
|
||||||
# ...
|
# ...
|
||||||
shm_size: '1gb'
|
shm_size: '1gb'
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installing a browser
|
## Installing a browser
|
||||||
|
|
||||||
|
@ -84,11 +92,18 @@ If you want the full version of **Google Chrome** in the desktop:
|
||||||
&& apt-get -y install /tmp/chrome.deb
|
&& apt-get -y install /tmp/chrome.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Chrome sandbox support requires you set up and run as a non-root user. The [`debian-common.sh`](common.md) script can do this for you, or you [set one up yourself](https://aka.ms/vscode-remote/containers/non-root). Alternatively, you can start Chrome using `google-chrome --no-sandbox`
|
2. Chrome sandbox support requires you set up and run as a non-root user. The [`common-utils`](https://github.com/devcontainers/features/tree/main/src/common-utils) script can do this for you, or you [set one up yourself](https://aka.ms/vscode-remote/containers/non-root). Alternatively, you can start Chrome using `google-chrome --no-sandbox`
|
||||||
|
|
||||||
That's it!
|
That's it!
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/desktop-lite/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/desktop-lite/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "desktop-lite",
|
"id": "desktop-lite",
|
||||||
"version": "1.0.1",
|
"version": "1.0.8",
|
||||||
"name": "Light-weight Desktop",
|
"name": "Light-weight Desktop",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/desktop-lite",
|
||||||
"description": "Adds a lightweight Fluxbox based desktop to the container that can be accessed using a VNC viewer or the web. GUI-based commands executed from the built-in VS code terminal will open on the desktop automatically.",
|
"description": "Adds a lightweight Fluxbox based desktop to the container that can be accessed using a VNC viewer or the web. GUI-based commands executed from the built-in VS code terminal will open on the desktop automatically.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -51,5 +52,8 @@
|
||||||
"entrypoint": "/usr/local/share/desktop-init.sh",
|
"entrypoint": "/usr/local/share/desktop-init.sh",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"DISPLAY": ":1"
|
"DISPLAY": ":1"
|
||||||
}
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,13 @@
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/desktop-lite.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/desktop-lite.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
NOVNC_VERSION=${NOVNCVERSION:-"1.2.0"} # TODO: Add in a 'latest' auto-detect and swap name to 'version'
|
NOVNC_VERSION="${NOVNCVERSION:-"1.2.0"}" # TODO: Add in a 'latest' auto-detect and swap name to 'version'
|
||||||
VNC_PASSWORD=${PASSWORD:-"vscode"}
|
VNC_PASSWORD=${PASSWORD:-"vscode"}
|
||||||
NOVNC_PORT="${WEBPORT:-6080}"
|
NOVNC_PORT="${WEBPORT:-6080}"
|
||||||
VNC_PORT="${VNCPORT:-5901}"
|
VNC_PORT="${VNCPORT:-5901}"
|
||||||
|
|
||||||
INSTALL_NOVNC=${INSTALL_NOVNC:-"true"}
|
INSTALL_NOVNC="${INSTALL_NOVNC:-"true"}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
|
|
||||||
|
|
||||||
WEBSOCKETIFY_VERSION=0.10.0
|
WEBSOCKETIFY_VERSION=0.10.0
|
||||||
|
|
||||||
|
@ -63,6 +62,9 @@ package_list_additional="
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -149,22 +151,18 @@ copy_fluxbox_config() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apt_get_update()
|
||||||
# Function to run apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -176,13 +174,13 @@ check_packages() {
|
||||||
# Ensure apt is in non-interactive to avoid prompts
|
# Ensure apt is in non-interactive to avoid prompts
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
|
|
||||||
# On older Ubuntu, Tilix is in a PPA. on Debian strech its in backports.
|
# On older Ubuntu, Tilix is in a PPA. on Debian stretch its in backports.
|
||||||
if [[ -z $(apt-cache --names-only search ^tilix$) ]]; then
|
if [[ -z $(apt-cache --names-only search ^tilix$) ]]; then
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
if [ "${ID}" = "ubuntu" ]; then
|
if [ "${ID}" = "ubuntu" ]; then
|
||||||
apt-get install -y --no-install-recommends apt-transport-https software-properties-common
|
check_packages apt-transport-https software-properties-common
|
||||||
add-apt-repository -y ppa:webupd8team/terminix
|
add-apt-repository -y ppa:webupd8team/terminix
|
||||||
elif [ "${VERSION_CODENAME}" = "stretch" ]; then
|
elif [ "${VERSION_CODENAME}" = "stretch" ]; then
|
||||||
echo "deb http://deb.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/stretch-backports.list
|
echo "deb http://deb.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/stretch-backports.list
|
||||||
|
@ -238,9 +236,7 @@ if [ "${INSTALL_NOVNC}" = "true" ] && [ ! -d "/usr/local/novnc" ]; then
|
||||||
rm -f /tmp/websockify-install.zip /tmp/novnc-install.zip
|
rm -f /tmp/websockify-install.zip /tmp/novnc-install.zip
|
||||||
|
|
||||||
# Install noVNC dependencies and use them.
|
# Install noVNC dependencies and use them.
|
||||||
if ! dpkg -s python3-minimal python3-numpy > /dev/null 2>&1; then
|
check_packages python3-minimal python3-numpy
|
||||||
apt-get -y install --no-install-recommends python3-minimal python3-numpy
|
|
||||||
fi
|
|
||||||
sed -i -E 's/^python /python3 /' /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION}/run
|
sed -i -E 's/^python /python3 /' /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION}/run
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -303,9 +299,9 @@ startInBackgroundIfNotRunning()
|
||||||
{
|
{
|
||||||
log "Starting \$1."
|
log "Starting \$1."
|
||||||
echo -e "\n** \$(date) **" | sudoIf tee -a /tmp/\$1.log > /dev/null
|
echo -e "\n** \$(date) **" | sudoIf tee -a /tmp/\$1.log > /dev/null
|
||||||
if ! pidof \$1 > /dev/null; then
|
if ! pgrep -x \$1 > /dev/null; then
|
||||||
keepRunningInBackground "\$@"
|
keepRunningInBackground "\$@"
|
||||||
while ! pidof \$1 > /dev/null; do
|
while ! pgrep -x \$1 > /dev/null; do
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
log "\$1 started."
|
log "\$1 started."
|
||||||
|
@ -351,16 +347,16 @@ log "** SCRIPT START **"
|
||||||
|
|
||||||
# Start dbus.
|
# Start dbus.
|
||||||
log 'Running "/etc/init.d/dbus start".'
|
log 'Running "/etc/init.d/dbus start".'
|
||||||
if [ -f "/var/run/dbus/pid" ] && ! pidof dbus-daemon > /dev/null; then
|
if [ -f "/var/run/dbus/pid" ] && ! pgrep -x dbus-daemon > /dev/null; then
|
||||||
sudoIf rm -f /var/run/dbus/pid
|
sudoIf rm -f /var/run/dbus/pid
|
||||||
fi
|
fi
|
||||||
sudoIf /etc/init.d/dbus start 2>&1 | sudoIf tee -a /tmp/dbus-daemon-system.log > /dev/null
|
sudoIf /etc/init.d/dbus start 2>&1 | sudoIf tee -a /tmp/dbus-daemon-system.log > /dev/null
|
||||||
while ! pidof dbus-daemon > /dev/null; do
|
while ! pgrep -x dbus-daemon > /dev/null; do
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|
||||||
# Startup tigervnc server and fluxbox
|
# Startup tigervnc server and fluxbox
|
||||||
sudo rm -rf /tmp/.X11-unix /tmp/.X*-lock
|
sudoIf rm -rf /tmp/.X11-unix /tmp/.X*-lock
|
||||||
mkdir -p /tmp/.X11-unix
|
mkdir -p /tmp/.X11-unix
|
||||||
sudoIf chmod 1777 /tmp/.X11-unix
|
sudoIf chmod 1777 /tmp/.X11-unix
|
||||||
sudoIf chown root:\${group_name} /tmp/.X11-unix
|
sudoIf chown root:\${group_name} /tmp/.X11-unix
|
||||||
|
@ -369,7 +365,7 @@ screen_geometry="\${VNC_RESOLUTION%*x*}"
|
||||||
screen_depth="\${VNC_RESOLUTION##*x}"
|
screen_depth="\${VNC_RESOLUTION##*x}"
|
||||||
startInBackgroundIfNotRunning "Xtigervnc" sudoUserIf "tigervncserver \${DISPLAY} -geometry \${screen_geometry} -depth \${screen_depth} -rfbport ${VNC_PORT} -dpi \${VNC_DPI:-96} -localhost -desktop fluxbox -fg -passwd /usr/local/etc/vscode-dev-containers/vnc-passwd"
|
startInBackgroundIfNotRunning "Xtigervnc" sudoUserIf "tigervncserver \${DISPLAY} -geometry \${screen_geometry} -depth \${screen_depth} -rfbport ${VNC_PORT} -dpi \${VNC_DPI:-96} -localhost -desktop fluxbox -fg -passwd /usr/local/etc/vscode-dev-containers/vnc-passwd"
|
||||||
|
|
||||||
# Spin up noVNC if installed and not runnning.
|
# Spin up noVNC if installed and not running.
|
||||||
if [ -d "/usr/local/novnc" ] && [ "\$(ps -ef | grep /usr/local/novnc/noVNC*/utils/launch.sh | grep -v grep)" = "" ]; then
|
if [ -d "/usr/local/novnc" ] && [ "\$(ps -ef | grep /usr/local/novnc/noVNC*/utils/launch.sh | grep -v grep)" = "" ]; then
|
||||||
keepRunningInBackground "noVNC" sudoIf "/usr/local/novnc/noVNC*/utils/launch.sh --listen ${NOVNC_PORT} --vnc localhost:${VNC_PORT}"
|
keepRunningInBackground "noVNC" sudoIf "/usr/local/novnc/noVNC*/utils/launch.sh --listen ${NOVNC_PORT} --vnc localhost:${VNC_PORT}"
|
||||||
log "noVNC started."
|
log "noVNC started."
|
||||||
|
@ -393,6 +389,9 @@ if [ "${USERNAME}" != "root" ]; then
|
||||||
chown -R ${USERNAME} /home/${USERNAME}/.Xmodmap /home/${USERNAME}/.fluxbox
|
chown -R ${USERNAME} /home/${USERNAME}/.Xmodmap /home/${USERNAME}/.fluxbox
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
## Supporting bind mounts from the workspace folder
|
|
||||||
|
|
||||||
A common question that comes up is how you can use `bind` mounts from the Docker CLI from within the a dev container using this Feature (e.g. via `-v`). The trick is that, since you're actually using the Docker engine sitting outside of the container, the filesystem paths will be different than those in the container. You need to use the **host**'s paths instead.
|
|
||||||
|
|
||||||
> **Note:** The docker-from-docker approach does not currently enable bind mounting locations outside of the workspace folder.
|
|
||||||
|
|
||||||
### GitHub Codespaces
|
|
||||||
|
|
||||||
In GitHub Codespaces, the workspace folder should work with bind mounts by default, so no further action is required.
|
|
||||||
|
|
||||||
### Remote - Containers
|
|
||||||
|
|
||||||
A simple way to do this is to put `${localWorkspaceFolder}` in an environment variable that you then use when doing bind mounts inside the container.
|
|
||||||
|
|
||||||
Add the following to `devcontainer.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }
|
|
||||||
```
|
|
||||||
|
|
||||||
Then reference the env var when running Docker commands from the terminal inside the container.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -it --rm -v ${LOCAL_WORKSPACE_FOLDER}:/workspace debian bash
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note:** There is no `${localWorkspaceFolder}` when using the **Clone Repository in Container Volume** command ([info](https://github.com/microsoft/vscode-remote-release/issues/6160#issuecomment-1014701007)).
|
|
|
@ -1,54 +0,0 @@
|
||||||
|
|
||||||
# Docker (Docker-from-Docker) (docker-from-docker)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```json
|
|
||||||
"features": {
|
|
||||||
"ghcr.io/devcontainers/features/docker-from-docker:1": {
|
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
| Options Id | Description | Type | Default Value |
|
|
||||||
|-----|-----|-----|-----|
|
|
||||||
| version | Select or enter a Docker/Moby CLI version. (Availability can vary by OS version.) | string | latest |
|
|
||||||
| moby | Install OSS Moby build instead of Docker CE | boolean | true |
|
|
||||||
| dockerDashComposeVersion | Compose version to use for docker-compose (v1 or v2) | string | v1 |
|
|
||||||
|
|
||||||
## Supporting bind mounts from the workspace folder
|
|
||||||
|
|
||||||
A common question that comes up is how you can use `bind` mounts from the Docker CLI from within the a dev container using this Feature (e.g. via `-v`). The trick is that, since you're actually using the Docker engine sitting outside of the container, the filesystem paths will be different than those in the container. You need to use the **host**'s paths instead.
|
|
||||||
|
|
||||||
> **Note:** The docker-from-docker approach does not currently enable bind mounting locations outside of the workspace folder.
|
|
||||||
|
|
||||||
### GitHub Codespaces
|
|
||||||
|
|
||||||
In GitHub Codespaces, the workspace folder should work with bind mounts by default, so no further action is required.
|
|
||||||
|
|
||||||
### Remote - Containers
|
|
||||||
|
|
||||||
A simple way to do this is to put `${localWorkspaceFolder}` in an environment variable that you then use when doing bind mounts inside the container.
|
|
||||||
|
|
||||||
Add the following to `devcontainer.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }
|
|
||||||
```
|
|
||||||
|
|
||||||
Then reference the env var when running Docker commands from the terminal inside the container.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -it --rm -v ${LOCAL_WORKSPACE_FOLDER}:/workspace debian bash
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note:** There is no `${localWorkspaceFolder}` when using the **Clone Repository in Container Volume** command ([info](https://github.com/microsoft/vscode-remote-release/issues/6160#issuecomment-1014701007)).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/docker-from-docker/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
|
16
src/docker-in-docker/NOTES.md
Normal file
16
src/docker-in-docker/NOTES.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind:
|
||||||
|
* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them.
|
||||||
|
* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example:
|
||||||
|
```
|
||||||
|
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16
|
||||||
|
```
|
||||||
|
See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details.
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Create child containers *inside* a container, independent from the host's docker
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker:1": {
|
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -19,8 +17,33 @@ Create child containers *inside* a container, independent from the host's docker
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.) | string | latest |
|
| version | Select or enter a Docker/Moby Engine version. (Availability can vary by OS version.) | string | latest |
|
||||||
| moby | Install OSS Moby build instead of Docker CE | boolean | true |
|
| moby | Install OSS Moby build instead of Docker CE | boolean | true |
|
||||||
| dockerDashComposeVersion | Default version of Docker Compose (v1 or v2) | string | v1 |
|
| dockerDashComposeVersion | Default version of Docker Compose (v1 or v2 or none) | string | v1 |
|
||||||
|
| azureDnsAutoDetection | Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure | boolean | true |
|
||||||
|
| dockerDefaultAddressPool | Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24 | string | - |
|
||||||
|
| installDockerBuildx | Install Docker Buildx | boolean | true |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `ms-azuretools.vscode-docker`
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
This docker-in-docker Dev Container Feature is roughly based on the [official docker-in-docker wrapper script](https://github.com/moby/moby/blob/master/hack/dind) that is part of the [Moby project](https://mobyproject.org/). With this in mind:
|
||||||
|
* As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them.
|
||||||
|
* The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, like in this example:
|
||||||
|
```
|
||||||
|
FROM --platform=linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:16
|
||||||
|
```
|
||||||
|
See [Issue #219](https://github.com/devcontainers/features/issues/219) for more details.
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "docker-in-docker",
|
"id": "docker-in-docker",
|
||||||
"version": "1.0.1",
|
"version": "2.7.1",
|
||||||
"name": "Docker (Docker-in-Docker)",
|
"name": "Docker (Docker-in-Docker)",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-in-docker",
|
||||||
"description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.",
|
"description": "Create child containers *inside* a container, independent from the host's docker instance. Installs Docker extension in the container along with needed CLIs.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -22,11 +23,28 @@
|
||||||
"dockerDashComposeVersion": {
|
"dockerDashComposeVersion": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
"none",
|
||||||
"v1",
|
"v1",
|
||||||
"v2"
|
"v2"
|
||||||
],
|
],
|
||||||
"default": "v1",
|
"default": "v1",
|
||||||
"description": "Default version of Docker Compose (v1 or v2)"
|
"description": "Default version of Docker Compose (v1 or v2 or none)"
|
||||||
|
},
|
||||||
|
"azureDnsAutoDetection": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Allow automatically setting the dockerd DNS server when the installation script detects it is running in Azure"
|
||||||
|
},
|
||||||
|
"dockerDefaultAddressPool": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"proposals": [],
|
||||||
|
"description": "Define default address pools for Docker networks. e.g. base=192.168.0.0/16,size=24"
|
||||||
|
},
|
||||||
|
"installDockerBuildx": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Install Docker Buildx"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entrypoint": "/usr/local/share/docker-init.sh",
|
"entrypoint": "/usr/local/share/docker-init.sh",
|
||||||
|
@ -34,14 +52,21 @@
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"DOCKER_BUILDKIT": "1"
|
"DOCKER_BUILDKIT": "1"
|
||||||
},
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-azuretools.vscode-docker"
|
"ms-azuretools.vscode-docker"
|
||||||
],
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"mounts": [
|
"mounts": [
|
||||||
{
|
{
|
||||||
"source": "dind-var-lib-docker",
|
"source": "dind-var-lib-docker-${devcontainerId}",
|
||||||
"target": "/var/lib/docker",
|
"target": "/var/lib/docker",
|
||||||
"type": "volume"
|
"type": "volume"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,26 @@
|
||||||
#-------------------------------------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker-in-docker.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
|
||||||
|
|
||||||
DOCKER_VERSION=${VERSION:-"latest"} # The Docker/Moby Engine + CLI should match in version
|
DOCKER_VERSION="${VERSION:-"latest"}" # The Docker/Moby Engine + CLI should match in version
|
||||||
USE_MOBY=${MOBY:-"true"}
|
USE_MOBY="${MOBY:-"true"}"
|
||||||
DOCKER_DASH_COMPOSE_VERSION=${DOCKERDASHCOMPOSEVERSION:-"v1"} # v1 or v2
|
DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"v1"}" # v1 or v2 or none
|
||||||
|
AZURE_DNS_AUTO_DETECTION="${AZUREDNSAUTODETECTION:-"true"}"
|
||||||
ENABLE_NONROOT_DOCKER=${ENABLE_NONROOT_DOCKER:-"true"}
|
DOCKER_DEFAULT_ADDRESS_POOL="${DOCKERDEFAULTADDRESSPOOL}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
|
INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}"
|
||||||
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
||||||
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal jammy"
|
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy"
|
||||||
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute impish jammy"
|
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy"
|
||||||
|
|
||||||
# Default: Exit on any failure.
|
# Default: Exit on any failure.
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Setup STDERR.
|
# Setup STDERR.
|
||||||
err() {
|
err() {
|
||||||
echo "(!) $*" >&2
|
echo "(!) $*" >&2
|
||||||
|
@ -54,36 +57,18 @@ elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
|
||||||
USERNAME=root
|
USERNAME=root
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
apt_get_update()
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -135,10 +120,8 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
# Fetch host/container arch.
|
# Fetch host/container arch.
|
||||||
architecture="$(dpkg --print-architecture)"
|
architecture="$(dpkg --print-architecture)"
|
||||||
|
|
||||||
# Check if distro is suppported
|
# Check if distro is supported
|
||||||
if [ "${USE_MOBY}" = "true" ]; then
|
if [ "${USE_MOBY}" = "true" ]; then
|
||||||
# 'get_common_setting' allows attribute to be updated remotely
|
|
||||||
get_common_setting DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES
|
|
||||||
if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
||||||
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution"
|
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution"
|
||||||
err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}"
|
err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}"
|
||||||
|
@ -146,7 +129,6 @@ if [ "${USE_MOBY}" = "true" ]; then
|
||||||
fi
|
fi
|
||||||
echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'"
|
echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'"
|
||||||
else
|
else
|
||||||
get_common_setting DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES
|
|
||||||
if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
||||||
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution"
|
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution"
|
||||||
err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}"
|
err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}"
|
||||||
|
@ -156,10 +138,9 @@ else
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr
|
check_packages apt-transport-https curl ca-certificates pigz iptables gnupg2 dirmngr wget
|
||||||
if ! type git > /dev/null 2>&1; then
|
if ! type git > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
check_packages git
|
||||||
apt-get -y install git
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Swap to legacy iptables for compatibility
|
# Swap to legacy iptables for compatibility
|
||||||
|
@ -178,7 +159,6 @@ if [ "${USE_MOBY}" = "true" ]; then
|
||||||
cli_package_name="moby-cli"
|
cli_package_name="moby-cli"
|
||||||
|
|
||||||
# Import key safely and import Microsoft apt repo
|
# Import key safely and import Microsoft apt repo
|
||||||
get_common_setting MICROSOFT_GPG_KEYS_URI
|
|
||||||
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
||||||
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
|
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
|
||||||
else
|
else
|
||||||
|
@ -243,20 +223,19 @@ fi
|
||||||
|
|
||||||
echo "Finished installing docker / moby!"
|
echo "Finished installing docker / moby!"
|
||||||
|
|
||||||
# Install Docker Compose if not already installed and is on a supported architecture
|
# If 'docker-compose' command is to be included
|
||||||
if type docker-compose > /dev/null 2>&1; then
|
if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then
|
||||||
|
# Install Docker Compose if not already installed and is on a supported architecture
|
||||||
|
if type docker-compose > /dev/null 2>&1; then
|
||||||
echo "Docker Compose v1 already installed."
|
echo "Docker Compose v1 already installed."
|
||||||
else
|
else
|
||||||
target_compose_arch="${architecture}"
|
target_compose_arch="${architecture}"
|
||||||
if [ "${target_compose_arch}" = "amd64" ]; then
|
if [ "${target_compose_arch}" = "amd64" ]; then
|
||||||
target_compose_arch="x86_64"
|
target_compose_arch="x86_64"
|
||||||
fi
|
fi
|
||||||
if [ "${target_compose_arch}" != "x86_64" ]; then
|
if [ "${target_compose_arch}" != "x86_64" ]; then
|
||||||
# Use pip to get a version that runs on this architecture
|
# Use pip to get a version that runs on this architecture
|
||||||
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
|
check_packages python3-minimal python3-pip libffi-dev python3-venv
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
|
|
||||||
fi
|
|
||||||
export PIPX_HOME=/usr/local/pipx
|
export PIPX_HOME=/usr/local/pipx
|
||||||
mkdir -p ${PIPX_HOME}
|
mkdir -p ${PIPX_HOME}
|
||||||
export PIPX_BIN_DIR=/usr/local/bin
|
export PIPX_BIN_DIR=/usr/local/bin
|
||||||
|
@ -267,7 +246,21 @@ else
|
||||||
pip3 install --disable-pip-version-check --no-cache-dir --user pipx
|
pip3 install --disable-pip-version-check --no-cache-dir --user pipx
|
||||||
pipx_bin=/tmp/pip-tmp/bin/pipx
|
pipx_bin=/tmp/pip-tmp/bin/pipx
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set +e
|
||||||
${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' docker-compose
|
${pipx_bin} install --pip-args '--no-cache-dir --force-reinstall' docker-compose
|
||||||
|
exit_code=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ${exit_code} -ne 0 ]; then
|
||||||
|
# Temporary: https://github.com/devcontainers/features/issues/616
|
||||||
|
# See https://github.com/yaml/pyyaml/issues/601
|
||||||
|
echo "(*) Failed to install docker-compose via pipx. Trying via pip3..."
|
||||||
|
|
||||||
|
export PYTHONUSERBASE=/usr/local
|
||||||
|
pip3 install --disable-pip-version-check --no-cache-dir --user "Cython<3.0" pyyaml wheel docker-compose --no-build-isolation
|
||||||
|
fi
|
||||||
|
|
||||||
rm -rf /tmp/pip-tmp
|
rm -rf /tmp/pip-tmp
|
||||||
else
|
else
|
||||||
compose_v1_version="1"
|
compose_v1_version="1"
|
||||||
|
@ -276,12 +269,12 @@ else
|
||||||
curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
|
curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
|
||||||
chmod +x /usr/local/bin/docker-compose
|
chmod +x /usr/local/bin/docker-compose
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation
|
# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation
|
||||||
current_v1_compose_path="$(which docker-compose)"
|
current_v1_compose_path="$(which docker-compose)"
|
||||||
target_v1_compose_path="$(dirname "${current_v1_compose_path}")/docker-compose-v1"
|
target_v1_compose_path="$(dirname "${current_v1_compose_path}")/docker-compose-v1"
|
||||||
if ! type compose-switch > /dev/null 2>&1; then
|
if ! type compose-switch > /dev/null 2>&1; then
|
||||||
echo "(*) Installing compose-switch..."
|
echo "(*) Installing compose-switch..."
|
||||||
compose_switch_version="latest"
|
compose_switch_version="latest"
|
||||||
find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch"
|
find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch"
|
||||||
|
@ -293,31 +286,48 @@ if ! type compose-switch > /dev/null 2>&1; then
|
||||||
mv "${current_v1_compose_path}" "${target_v1_compose_path}"
|
mv "${current_v1_compose_path}" "${target_v1_compose_path}"
|
||||||
update-alternatives --install /usr/local/bin/docker-compose docker-compose /usr/local/bin/compose-switch 99
|
update-alternatives --install /usr/local/bin/docker-compose docker-compose /usr/local/bin/compose-switch 99
|
||||||
update-alternatives --install /usr/local/bin/docker-compose docker-compose "${target_v1_compose_path}" 1
|
update-alternatives --install /usr/local/bin/docker-compose docker-compose "${target_v1_compose_path}" 1
|
||||||
fi
|
fi
|
||||||
if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then
|
if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then
|
||||||
update-alternatives --set docker-compose "${target_v1_compose_path}"
|
update-alternatives --set docker-compose "${target_v1_compose_path}"
|
||||||
else
|
else
|
||||||
update-alternatives --set docker-compose /usr/local/bin/compose-switch
|
update-alternatives --set docker-compose /usr/local/bin/compose-switch
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If init file already exists, exit
|
# If init file already exists, exit
|
||||||
if [ -f "/usr/local/share/docker-init.sh" ]; then
|
if [ -f "/usr/local/share/docker-init.sh" ]; then
|
||||||
echo "/usr/local/share/docker-init.sh already exists, so exiting."
|
echo "/usr/local/share/docker-init.sh already exists, so exiting."
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "docker-init doesnt exist, adding..."
|
echo "docker-init doesn't exist, adding..."
|
||||||
|
|
||||||
# Add user to the docker group
|
if ! cat /etc/group | grep -e "^docker:" > /dev/null 2>&1; then
|
||||||
if [ "${ENABLE_NONROOT_DOCKER}" = "true" ]; then
|
groupadd -r docker
|
||||||
if ! getent group docker > /dev/null 2>&1; then
|
fi
|
||||||
groupadd docker
|
|
||||||
fi
|
|
||||||
|
|
||||||
usermod -aG docker ${USERNAME}
|
usermod -aG docker ${USERNAME}
|
||||||
|
|
||||||
|
if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then
|
||||||
|
buildx_version="latest"
|
||||||
|
find_version_from_git_tags buildx_version "https://github.com/docker/buildx" "refs/tags/v"
|
||||||
|
|
||||||
|
echo "(*) Installing buildx ${buildx_version}..."
|
||||||
|
buildx_file_name="buildx-v${buildx_version}.linux-${architecture}"
|
||||||
|
cd /tmp && wget "https://github.com/docker/buildx/releases/download/v${buildx_version}/${buildx_file_name}"
|
||||||
|
|
||||||
|
mkdir -p ${_REMOTE_USER_HOME}/.docker/cli-plugins
|
||||||
|
mv ${buildx_file_name} ${_REMOTE_USER_HOME}/.docker/cli-plugins/docker-buildx
|
||||||
|
chmod +x ${_REMOTE_USER_HOME}/.docker/cli-plugins/docker-buildx
|
||||||
|
|
||||||
|
chown -R "${USERNAME}:docker" "${_REMOTE_USER_HOME}/.docker"
|
||||||
|
chmod -R g+r+w "${_REMOTE_USER_HOME}/.docker"
|
||||||
|
find "${_REMOTE_USER_HOME}/.docker" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tee /usr/local/share/docker-init.sh > /dev/null \
|
tee /usr/local/share/docker-init.sh > /dev/null \
|
||||||
<< 'EOF'
|
<< EOF
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#-------------------------------------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
@ -326,13 +336,18 @@ tee /usr/local/share/docker-init.sh > /dev/null \
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
dockerd_start="$(cat << 'INNEREOF'
|
AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION}
|
||||||
|
DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tee -a /usr/local/share/docker-init.sh > /dev/null \
|
||||||
|
<< 'EOF'
|
||||||
|
dockerd_start="AZURE_DNS_AUTO_DETECTION=${AZURE_DNS_AUTO_DETECTION} DOCKER_DEFAULT_ADDRESS_POOL=${DOCKER_DEFAULT_ADDRESS_POOL} $(cat << 'INNEREOF'
|
||||||
# explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly
|
# explicitly remove dockerd and containerd PID file to ensure that it can start properly if it was stopped uncleanly
|
||||||
# ie: docker kill <ID>
|
|
||||||
find /run /var/run -iname 'docker*.pid' -delete || :
|
find /run /var/run -iname 'docker*.pid' -delete || :
|
||||||
find /run /var/run -iname 'container*.pid' -delete || :
|
find /run /var/run -iname 'container*.pid' -delete || :
|
||||||
|
|
||||||
## Dind wrapper script from docker team, adapted to a function
|
# -- Start: dind wrapper script --
|
||||||
# Maintained: https://github.com/moby/moby/blob/master/hack/dind
|
# Maintained: https://github.com/moby/moby/blob/master/hack/dind
|
||||||
|
|
||||||
export container=docker
|
export container=docker
|
||||||
|
@ -349,6 +364,8 @@ dockerd_start="$(cat << 'INNEREOF'
|
||||||
mount -t tmpfs none /tmp
|
mount -t tmpfs none /tmp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set_cgroup_nesting()
|
||||||
|
{
|
||||||
# cgroup v2: enable nesting
|
# cgroup v2: enable nesting
|
||||||
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
|
if [ -f /sys/fs/cgroup/cgroup.controllers ]; then
|
||||||
# move the processes from the root group to the /init group,
|
# move the processes from the root group to the /init group,
|
||||||
|
@ -360,12 +377,32 @@ dockerd_start="$(cat << 'INNEREOF'
|
||||||
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
|
sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \
|
||||||
> /sys/fs/cgroup/cgroup.subtree_control
|
> /sys/fs/cgroup/cgroup.subtree_control
|
||||||
fi
|
fi
|
||||||
## Dind wrapper over.
|
}
|
||||||
|
|
||||||
|
# Set cgroup nesting, retrying if necessary
|
||||||
|
retry_cgroup_nesting=0
|
||||||
|
|
||||||
|
until [ "${retry_cgroup_nesting}" -eq "5" ];
|
||||||
|
do
|
||||||
|
set +e
|
||||||
|
set_cgroup_nesting
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "(*) cgroup v2: Failed to enable nesting, retrying..."
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
retry_cgroup_nesting=`expr $retry_cgroup_nesting + 1`
|
||||||
|
set -e
|
||||||
|
done
|
||||||
|
|
||||||
|
# -- End: dind wrapper script --
|
||||||
|
|
||||||
# Handle DNS
|
# Handle DNS
|
||||||
set +e
|
set +e
|
||||||
cat /etc/resolv.conf | grep -i 'internal.cloudapp.net'
|
cat /etc/resolv.conf | grep -i 'internal.cloudapp.net' > /dev/null 2>&1
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ] && [ "${AZURE_DNS_AUTO_DETECTION}" = "true" ]
|
||||||
then
|
then
|
||||||
echo "Setting dockerd Azure DNS."
|
echo "Setting dockerd Azure DNS."
|
||||||
CUSTOMDNS="--dns 168.63.129.16"
|
CUSTOMDNS="--dns 168.63.129.16"
|
||||||
|
@ -375,19 +412,61 @@ dockerd_start="$(cat << 'INNEREOF'
|
||||||
fi
|
fi
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$DOCKER_DEFAULT_ADDRESS_POOL" ]
|
||||||
|
then
|
||||||
|
DEFAULT_ADDRESS_POOL=""
|
||||||
|
else
|
||||||
|
DEFAULT_ADDRESS_POOL="--default-address-pool $DOCKER_DEFAULT_ADDRESS_POOL"
|
||||||
|
fi
|
||||||
|
|
||||||
# Start docker/moby engine
|
# Start docker/moby engine
|
||||||
( dockerd $CUSTOMDNS > /tmp/dockerd.log 2>&1 ) &
|
( dockerd $CUSTOMDNS $DEFAULT_ADDRESS_POOL > /tmp/dockerd.log 2>&1 ) &
|
||||||
INNEREOF
|
INNEREOF
|
||||||
)"
|
)"
|
||||||
|
|
||||||
# Start using sudo if not invoked as root
|
sudo_if() {
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
COMMAND="$*"
|
||||||
sudo /bin/sh -c "${dockerd_start}"
|
|
||||||
else
|
|
||||||
eval "${dockerd_start}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
sudo $COMMAND
|
||||||
|
else
|
||||||
|
$COMMAND
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
retry_docker_start_count=0
|
||||||
|
docker_ok="false"
|
||||||
|
|
||||||
|
until [ "${docker_ok}" = "true" ] || [ "${retry_docker_start_count}" -eq "5" ];
|
||||||
|
do
|
||||||
|
# Start using sudo if not invoked as root
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
sudo /bin/sh -c "${dockerd_start}"
|
||||||
|
else
|
||||||
|
eval "${dockerd_start}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
retry_count=0
|
||||||
|
until [ "${docker_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
|
||||||
|
do
|
||||||
|
sleep 1s
|
||||||
|
set +e
|
||||||
|
docker info > /dev/null 2>&1 && docker_ok="true"
|
||||||
|
set -e
|
||||||
|
|
||||||
|
retry_count=`expr $retry_count + 1`
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${docker_ok}" != "true" ] && [ "${retry_docker_start_count}" != "4" ]; then
|
||||||
|
echo "(*) Failed to start docker, retrying..."
|
||||||
|
set +e
|
||||||
|
sudo_if pkill dockerd
|
||||||
|
sudo_if pkill containerd
|
||||||
|
set -e
|
||||||
|
fi
|
||||||
|
|
||||||
|
retry_docker_start_count=`expr $retry_docker_start_count + 1`
|
||||||
|
done
|
||||||
|
|
||||||
# Execute whatever commands were passed in (if any). This allows us
|
# Execute whatever commands were passed in (if any). This allows us
|
||||||
# to set this script to ENTRYPOINT while still executing the default CMD.
|
# to set this script to ENTRYPOINT while still executing the default CMD.
|
||||||
|
@ -397,4 +476,7 @@ EOF
|
||||||
chmod +x /usr/local/share/docker-init.sh
|
chmod +x /usr/local/share/docker-init.sh
|
||||||
chown ${USERNAME}:root /usr/local/share/docker-init.sh
|
chown ${USERNAME}:root /usr/local/share/docker-init.sh
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo 'docker-in-docker-debian script has completed!'
|
echo 'docker-in-docker-debian script has completed!'
|
||||||
|
|
61
src/docker-outside-of-docker/NOTES.md
Normal file
61
src/docker-outside-of-docker/NOTES.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them.
|
||||||
|
- The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, for example.
|
||||||
|
- This approach does not currently enable bind mounting the workspace folder by default, and cannot support folders outside of the workspace folder. Consider whether the [Docker-in-Docker Feature](../docker-in-docker) would better meet your needs given it does not have this limitation.
|
||||||
|
|
||||||
|
## Supporting bind mounts from the workspace folder
|
||||||
|
|
||||||
|
A common question that comes up is how you can use `bind` mounts from the Docker CLI from within the a dev container using this Feature (e.g. via `-v`). If you cannot use the [Docker-in-Docker Feature](../docker-in-docker), the only way to work around this is to use the **host**'s folder paths instead of the container's paths. There are 2 ways to do this
|
||||||
|
|
||||||
|
### 1. Use the `${localWorkspaceFolder}` as environment variable in your code
|
||||||
|
|
||||||
|
1. Add the following to `devcontainer.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Usage with Docker commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --rm -v ${LOCAL_WORKSPACE_FOLDER}:/workspace debian bash
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Usage with Docker-compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
debian:
|
||||||
|
image: debian
|
||||||
|
volumes:
|
||||||
|
- ${LOCAL_WORKSPACE_FOLDER:-./}:/workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
- The defaults value `./` is added so that the `docker-compose.yaml` file can work when it is run outside of the container
|
||||||
|
|
||||||
|
### Change the workspace to `${localWorkspaceFolder}`
|
||||||
|
|
||||||
|
- This is useful if we don't want to edit the `docker-compose.yaml` file
|
||||||
|
|
||||||
|
1. Add the following to `devcontainer.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
"workspaceFolder": "${localWorkspaceFolder}",
|
||||||
|
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Rebuild the container.
|
||||||
|
3. When the container first started with this settings, select the Workspace with the absolute path to the working directory inside the container
|
||||||
|
4. Docker commands with bind mount should work as they did outside of the devcontainer
|
||||||
|
|
||||||
|
> **Note:** There is no `${localWorkspaceFolder}` when using the **Clone Repository in Container Volume** command in the VS Code Dev Containers extension ([info](https://github.com/microsoft/vscode-remote-release/issues/6160#issuecomment-1014701007)).
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
96
src/docker-outside-of-docker/README.md
Normal file
96
src/docker-outside-of-docker/README.md
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
### **IMPORTANT NOTE**
|
||||||
|
- **Ids used to publish this Feature in the past - 'docker-from-docker'**
|
||||||
|
|
||||||
|
# Docker (docker-outside-of-docker) (docker-outside-of-docker)
|
||||||
|
|
||||||
|
Re-use the host docker socket, adding the Docker CLI to a container. Feature invokes a script to enable using a forwarded Docker socket within a container to run Docker commands.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```json
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
| Options Id | Description | Type | Default Value |
|
||||||
|
|-----|-----|-----|-----|
|
||||||
|
| version | Select or enter a Docker/Moby CLI version. (Availability can vary by OS version.) | string | latest |
|
||||||
|
| moby | Install OSS Moby build instead of Docker CE | boolean | true |
|
||||||
|
| dockerDashComposeVersion | Compose version to use for docker-compose (v1 or v2 or none) | string | v2 |
|
||||||
|
| installDockerBuildx | Install Docker Buildx | boolean | true |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `ms-azuretools.vscode-docker`
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- As the name implies, the Feature is expected to work when the host is running Docker (or the OSS Moby container engine it is built on). It may be possible to get running in other container engines, but it has not been tested with them.
|
||||||
|
- The host and the container must be running on the same chip architecture. You will not be able to use it with an emulated x86 image with Docker Desktop on an Apple Silicon Mac, for example.
|
||||||
|
- This approach does not currently enable bind mounting the workspace folder by default, and cannot support folders outside of the workspace folder. Consider whether the [Docker-in-Docker Feature](../docker-in-docker) would better meet your needs given it does not have this limitation.
|
||||||
|
|
||||||
|
## Supporting bind mounts from the workspace folder
|
||||||
|
|
||||||
|
A common question that comes up is how you can use `bind` mounts from the Docker CLI from within the a dev container using this Feature (e.g. via `-v`). If you cannot use the [Docker-in-Docker Feature](../docker-in-docker), the only way to work around this is to use the **host**'s folder paths instead of the container's paths. There are 2 ways to do this
|
||||||
|
|
||||||
|
### 1. Use the `${localWorkspaceFolder}` as environment variable in your code
|
||||||
|
|
||||||
|
1. Add the following to `devcontainer.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"remoteEnv": { "LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}" }
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Usage with Docker commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -it --rm -v ${LOCAL_WORKSPACE_FOLDER}:/workspace debian bash
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Usage with Docker-compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
debian:
|
||||||
|
image: debian
|
||||||
|
volumes:
|
||||||
|
- ${LOCAL_WORKSPACE_FOLDER:-./}:/workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
- The defaults value `./` is added so that the `docker-compose.yaml` file can work when it is run outside of the container
|
||||||
|
|
||||||
|
### Change the workspace to `${localWorkspaceFolder}`
|
||||||
|
|
||||||
|
- This is useful if we don't want to edit the `docker-compose.yaml` file
|
||||||
|
|
||||||
|
1. Add the following to `devcontainer.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
"workspaceFolder": "${localWorkspaceFolder}",
|
||||||
|
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Rebuild the container.
|
||||||
|
3. When the container first started with this settings, select the Workspace with the absolute path to the working directory inside the container
|
||||||
|
4. Docker commands with bind mount should work as they did outside of the devcontainer
|
||||||
|
|
||||||
|
> **Note:** There is no `${localWorkspaceFolder}` when using the **Clone Repository in Container Volume** command in the VS Code Dev Containers extension ([info](https://github.com/microsoft/vscode-remote-release/issues/6160#issuecomment-1014701007)).
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/docker-outside-of-docker/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
|
@ -1,8 +1,9 @@
|
||||||
{
|
{
|
||||||
"id": "docker-from-docker",
|
"id": "docker-outside-of-docker",
|
||||||
"version": "1.0.1",
|
"version": "1.3.1",
|
||||||
"name": "Docker (Docker-from-Docker)",
|
"name": "Docker (docker-outside-of-docker)",
|
||||||
"descripton": "Re-use the host docker socket, adding the Docker CLI to a container. Feature invokes a script to enable using a forwarded Docker socket within a container to run Docker commands.",
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/docker-outside-of-docker",
|
||||||
|
"description": "Re-use the host docker socket, adding the Docker CLI to a container. Feature invokes a script to enable using a forwarded Docker socket within a container to run Docker commands.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -22,25 +23,38 @@
|
||||||
"dockerDashComposeVersion": {
|
"dockerDashComposeVersion": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
"none",
|
||||||
"v1",
|
"v1",
|
||||||
"v2"
|
"v2"
|
||||||
],
|
],
|
||||||
"default": "v1",
|
"default": "v2",
|
||||||
"description": "Compose version to use for docker-compose (v1 or v2)"
|
"description": "Compose version to use for docker-compose (v1 or v2 or none)"
|
||||||
|
},
|
||||||
|
"installDockerBuildx": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Install Docker Buildx"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entrypoint": "/usr/local/share/docker-init.sh",
|
"entrypoint": "/usr/local/share/docker-init.sh",
|
||||||
"containerEnv": {
|
"customizations": {
|
||||||
"DOCKER_BUILDKIT": "1"
|
"vscode": {
|
||||||
},
|
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-azuretools.vscode-docker"
|
"ms-azuretools.vscode-docker"
|
||||||
],
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"mounts": [
|
"mounts": [
|
||||||
{
|
{
|
||||||
"source": "/var/run/docker.sock",
|
"source": "/var/run/docker.sock",
|
||||||
"target": "/var/run/docker-host.sock",
|
"target": "/var/run/docker-host.sock",
|
||||||
"type": "bind"
|
"type": "bind"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
],
|
||||||
|
"legacyIds": [
|
||||||
|
"docker-from-docker"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -7,21 +7,25 @@
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/docker.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
DOCKER_VERSION=${VERSION:-"latest"}
|
DOCKER_VERSION="${VERSION:-"latest"}"
|
||||||
USE_MOBY=${MOBY:-"true"}
|
USE_MOBY="${MOBY:-"true"}"
|
||||||
DOCKER_DASH_COMPOSE_VERSION=${DOCKERDASHCOMPOSEVERSION:-"v1"} # v1 or v2
|
DOCKER_DASH_COMPOSE_VERSION="${DOCKERDASHCOMPOSEVERSION:-"v1"}" # v1 or v2 or none
|
||||||
|
|
||||||
ENABLE_NONROOT_DOCKER=${ENABLE_NONROOT_DOCKER:-"true"}
|
ENABLE_NONROOT_DOCKER="${ENABLE_NONROOT_DOCKER:-"true"}"
|
||||||
SOURCE_SOCKET=${SOURCE_SOCKET:-"/var/run/docker-host.sock"}
|
SOURCE_SOCKET="${SOURCE_SOCKET:-"/var/run/docker-host.sock"}"
|
||||||
TARGET_SOCKET=${TARGET_SOCKET:-"/var/run/docker.sock"}
|
TARGET_SOCKET="${TARGET_SOCKET:-"/var/run/docker.sock"}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
|
INSTALL_DOCKER_BUILDX="${INSTALLDOCKERBUILDX:-"true"}"
|
||||||
|
|
||||||
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
||||||
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal jammy"
|
DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal jammy"
|
||||||
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute impish jammy"
|
DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES="bookworm buster bullseye bionic focal hirsute impish jammy"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -44,36 +48,18 @@ elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
|
||||||
USERNAME=root
|
USERNAME=root
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
apt_get_update()
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -116,10 +102,9 @@ find_version_from_git_tags() {
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
|
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr wget
|
||||||
if ! type git > /dev/null 2>&1; then
|
if ! type git > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
check_packages git
|
||||||
apt-get -y install git
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Source /etc/os-release to get OS info
|
# Source /etc/os-release to get OS info
|
||||||
|
@ -127,10 +112,8 @@ fi
|
||||||
# Fetch host/container arch.
|
# Fetch host/container arch.
|
||||||
architecture="$(dpkg --print-architecture)"
|
architecture="$(dpkg --print-architecture)"
|
||||||
|
|
||||||
# Check if distro is suppported
|
# Check if distro is supported
|
||||||
if [ "${USE_MOBY}" = "true" ]; then
|
if [ "${USE_MOBY}" = "true" ]; then
|
||||||
# 'get_common_setting' allows attribute to be updated remotely
|
|
||||||
get_common_setting DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES
|
|
||||||
if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
if [[ "${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
||||||
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution"
|
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, either: (1) set feature option '\"moby\": false' , or (2) choose a compatible OS distribution"
|
||||||
err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}"
|
err "Support distributions include: ${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}"
|
||||||
|
@ -138,7 +121,6 @@ if [ "${USE_MOBY}" = "true" ]; then
|
||||||
fi
|
fi
|
||||||
echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'"
|
echo "Distro codename '${VERSION_CODENAME}' matched filter '${DOCKER_MOBY_ARCHIVE_VERSION_CODENAMES}'"
|
||||||
else
|
else
|
||||||
get_common_setting DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES
|
|
||||||
if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
if [[ "${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}" != *"${VERSION_CODENAME}"* ]]; then
|
||||||
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution"
|
err "Unsupported distribution version '${VERSION_CODENAME}'. To resolve, please choose a compatible OS distribution"
|
||||||
err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}"
|
err "Support distributions include: ${DOCKER_LICENSED_ARCHIVE_VERSION_CODENAMES}"
|
||||||
|
@ -153,7 +135,6 @@ if [ "${USE_MOBY}" = "true" ]; then
|
||||||
cli_package_name="moby-cli"
|
cli_package_name="moby-cli"
|
||||||
|
|
||||||
# Import key safely and import Microsoft apt repo
|
# Import key safely and import Microsoft apt repo
|
||||||
get_common_setting MICROSOFT_GPG_KEYS_URI
|
|
||||||
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
||||||
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
|
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
|
||||||
else
|
else
|
||||||
|
@ -194,27 +175,41 @@ if type docker > /dev/null 2>&1; then
|
||||||
echo "Docker / Moby CLI already installed."
|
echo "Docker / Moby CLI already installed."
|
||||||
else
|
else
|
||||||
if [ "${USE_MOBY}" = "true" ]; then
|
if [ "${USE_MOBY}" = "true" ]; then
|
||||||
apt-get -y install --no-install-recommends moby-cli${cli_version_suffix} moby-buildx
|
buildx=()
|
||||||
|
if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then
|
||||||
|
buildx=(moby-buildx)
|
||||||
|
fi
|
||||||
|
apt-get -y install --no-install-recommends ${cli_package_name}${cli_version_suffix} "${buildx[@]}"
|
||||||
apt-get -y install --no-install-recommends moby-compose || echo "(*) Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping."
|
apt-get -y install --no-install-recommends moby-compose || echo "(*) Package moby-compose (Docker Compose v2) not available for OS ${ID} ${VERSION_CODENAME} (${architecture}). Skipping."
|
||||||
else
|
else
|
||||||
apt-get -y install --no-install-recommends docker-ce-cli${cli_version_suffix}
|
buildx=()
|
||||||
|
if [ "${INSTALL_DOCKER_BUILDX}" = "true" ]; then
|
||||||
|
buildx=(docker-buildx-plugin)
|
||||||
fi
|
fi
|
||||||
|
apt-get -y install --no-install-recommends ${cli_package_name}${cli_version_suffix} "${buildx[@]}" docker-compose-plugin
|
||||||
|
buildx_path="/usr/libexec/docker/cli-plugins/docker-buildx"
|
||||||
|
# Older versions of Docker CE installs buildx as part of the CLI package
|
||||||
|
if [ "${INSTALL_DOCKER_BUILDX}" = "false" ] && [ -f "${buildx_path}" ]; then
|
||||||
|
echo "(*) Removing docker-buildx installed from docker-ce-cli since installDockerBuildx is disabled..."
|
||||||
|
rm -f "${buildx_path}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
unset buildx buildx_path
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install Docker Compose if not already installed and is on a supported architecture
|
# If 'docker-compose' command is to be included
|
||||||
if type docker-compose > /dev/null 2>&1; then
|
if [ "${DOCKER_DASH_COMPOSE_VERSION}" != "none" ]; then
|
||||||
|
# Install Docker Compose if not already installed and is on a supported architecture
|
||||||
|
if type docker-compose > /dev/null 2>&1; then
|
||||||
echo "Docker Compose already installed."
|
echo "Docker Compose already installed."
|
||||||
else
|
elif [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then
|
||||||
TARGET_COMPOSE_ARCH="$(uname -m)"
|
TARGET_COMPOSE_ARCH="$(uname -m)"
|
||||||
if [ "${TARGET_COMPOSE_ARCH}" = "amd64" ]; then
|
if [ "${TARGET_COMPOSE_ARCH}" = "amd64" ]; then
|
||||||
TARGET_COMPOSE_ARCH="x86_64"
|
TARGET_COMPOSE_ARCH="x86_64"
|
||||||
fi
|
fi
|
||||||
if [ "${TARGET_COMPOSE_ARCH}" != "x86_64" ]; then
|
if [ "${TARGET_COMPOSE_ARCH}" != "x86_64" ]; then
|
||||||
# Use pip to get a version that runns on this architecture
|
# Use pip to get a version that runs on this architecture
|
||||||
if ! dpkg -s python3-minimal python3-pip libffi-dev python3-venv > /dev/null 2>&1; then
|
check_packages python3-minimal python3-pip libffi-dev python3-venv
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get -y install python3-minimal python3-pip libffi-dev python3-venv
|
|
||||||
fi
|
|
||||||
export PIPX_HOME=/usr/local/pipx
|
export PIPX_HOME=/usr/local/pipx
|
||||||
mkdir -p ${PIPX_HOME}
|
mkdir -p ${PIPX_HOME}
|
||||||
export PIPX_BIN_DIR=/usr/local/bin
|
export PIPX_BIN_DIR=/usr/local/bin
|
||||||
|
@ -234,35 +229,39 @@ else
|
||||||
curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
|
curl -fsSL "https://github.com/docker/compose/releases/download/${compose_v1_version}/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
|
||||||
chmod +x /usr/local/bin/docker-compose
|
chmod +x /usr/local/bin/docker-compose
|
||||||
fi
|
fi
|
||||||
fi
|
else
|
||||||
|
echo "(*) Installing compose-switch as docker-compose..."
|
||||||
# Install docker-compose switch if not already installed - https://github.com/docker/compose-switch#manual-installation
|
|
||||||
current_v1_compose_path="$(which docker-compose)"
|
|
||||||
target_v1_compose_path="$(dirname "${current_v1_compose_path}")/docker-compose-v1"
|
|
||||||
if ! type compose-switch > /dev/null 2>&1; then
|
|
||||||
echo "(*) Installing compose-switch..."
|
|
||||||
compose_switch_version="latest"
|
compose_switch_version="latest"
|
||||||
find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch"
|
find_version_from_git_tags compose_switch_version "https://github.com/docker/compose-switch"
|
||||||
curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/compose-switch
|
curl -fsSL "https://github.com/docker/compose-switch/releases/download/v${compose_switch_version}/docker-compose-linux-${architecture}" -o /usr/local/bin/docker-compose
|
||||||
chmod +x /usr/local/bin/compose-switch
|
chmod +x /usr/local/bin/docker-compose
|
||||||
# TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11
|
# TODO: Verify checksum once available: https://github.com/docker/compose-switch/issues/11
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Setup v1 CLI as alternative in addition to compose-switch (which maps to v2)
|
# Setup a docker group in the event the docker socket's group is not root
|
||||||
mv "${current_v1_compose_path}" "${target_v1_compose_path}"
|
if ! grep -qE '^docker:' /etc/group; then
|
||||||
update-alternatives --install /usr/local/bin/docker-compose docker-compose /usr/local/bin/compose-switch 99
|
echo "(*) Creating missing docker group..."
|
||||||
update-alternatives --install /usr/local/bin/docker-compose docker-compose "${target_v1_compose_path}" 1
|
groupadd --system docker
|
||||||
fi
|
|
||||||
if [ "${DOCKER_DASH_COMPOSE_VERSION}" = "v1" ]; then
|
|
||||||
update-alternatives --set docker-compose "${target_v1_compose_path}"
|
|
||||||
else
|
|
||||||
update-alternatives --set docker-compose /usr/local/bin/compose-switch
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Remarking this out to restore functionality in Azure VMs. ID 999 is a reserved group ID
|
||||||
|
# Ensure docker group gid is 999
|
||||||
|
# if [ "$(getent group docker | cut -d: -f3)" != "999" ]; then
|
||||||
|
# echo "(*) Updating docker group gid to 999..."
|
||||||
|
# groupmod -g 999 docker
|
||||||
|
# fi
|
||||||
|
|
||||||
|
|
||||||
|
usermod -aG docker "${USERNAME}"
|
||||||
|
|
||||||
# If init file already exists, exit
|
# If init file already exists, exit
|
||||||
if [ -f "/usr/local/share/docker-init.sh" ]; then
|
if [ -f "/usr/local/share/docker-init.sh" ]; then
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "docker-init doesnt exist, adding..."
|
echo "docker-init doesn't exist, adding..."
|
||||||
|
|
||||||
# By default, make the source and target sockets the same
|
# By default, make the source and target sockets the same
|
||||||
if [ "${SOURCE_SOCKET}" != "${TARGET_SOCKET}" ]; then
|
if [ "${SOURCE_SOCKET}" != "${TARGET_SOCKET}" ]; then
|
||||||
|
@ -274,22 +273,16 @@ fi
|
||||||
if [ "${ENABLE_NONROOT_DOCKER}" = "false" ] || [ "${USERNAME}" = "root" ]; then
|
if [ "${ENABLE_NONROOT_DOCKER}" = "false" ] || [ "${USERNAME}" = "root" ]; then
|
||||||
echo -e '#!/usr/bin/env bash\nexec "$@"' > /usr/local/share/docker-init.sh
|
echo -e '#!/usr/bin/env bash\nexec "$@"' > /usr/local/share/docker-init.sh
|
||||||
chmod +x /usr/local/share/docker-init.sh
|
chmod +x /usr/local/share/docker-init.sh
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Setup a docker group in the event the docker socket's group is not root
|
|
||||||
if ! grep -qE '^docker:' /etc/group; then
|
|
||||||
groupadd --system docker
|
|
||||||
fi
|
|
||||||
usermod -aG docker "${USERNAME}"
|
|
||||||
DOCKER_GID="$(grep -oP '^docker:x:\K[^:]+' /etc/group)"
|
DOCKER_GID="$(grep -oP '^docker:x:\K[^:]+' /etc/group)"
|
||||||
|
|
||||||
# If enabling non-root access and specified user is found, setup socat and add script
|
# If enabling non-root access and specified user is found, setup socat and add script
|
||||||
chown -h "${USERNAME}":root "${TARGET_SOCKET}"
|
chown -h "${USERNAME}":root "${TARGET_SOCKET}"
|
||||||
if ! dpkg -s socat > /dev/null 2>&1; then
|
check_packages socat
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get -y install socat
|
|
||||||
fi
|
|
||||||
tee /usr/local/share/docker-init.sh > /dev/null \
|
tee /usr/local/share/docker-init.sh > /dev/null \
|
||||||
<< EOF
|
<< EOF
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
@ -351,4 +344,8 @@ exec "\$@"
|
||||||
EOF
|
EOF
|
||||||
chmod +x /usr/local/share/docker-init.sh
|
chmod +x /usr/local/share/docker-init.sh
|
||||||
chown ${USERNAME}:root /usr/local/share/docker-init.sh
|
chown ${USERNAME}:root /usr/local/share/docker-init.sh
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
74
src/dotnet/NOTES.md
Normal file
74
src/dotnet/NOTES.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
## Configuration examples
|
||||||
|
|
||||||
|
Installing only the latest .NET SDK version (the default).
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": "latest" // or "" or {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing an additional SDK version. Multiple versions can be specified as comma-separated values.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"additionalVersions": "lts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing specific SDK versions.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0",
|
||||||
|
"additionalVersions": "7.0, 8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing a specific SDK feature band.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0.4xx",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing a specific SDK patch version.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0.412",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes all runtimes so this configuration is only useful if you need to run .NET apps without building them from source.)
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "none",
|
||||||
|
"dotnetRuntimeVersions": "latest, lts",
|
||||||
|
"aspnetCoreRuntimeVersions": "latest, lts",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -1,15 +1,13 @@
|
||||||
|
|
||||||
# Dotnet CLI (dotnet)
|
# Dotnet CLI (dotnet)
|
||||||
|
|
||||||
Installs the .NET CLI. Provides option of installing sdk or runtime, and option of versions to install. Uses latest version of .NET sdk as defaults to install.
|
This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/dotnet:1": {
|
"ghcr.io/devcontainers/features/dotnet:2": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -17,10 +15,91 @@ Installs the .NET CLI. Provides option of installing sdk or runtime, and option
|
||||||
|
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter a dotnet CLI version. (Available versions may vary by Linux distribution.) | string | latest |
|
| version | Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | latest |
|
||||||
| runtimeOnly | Install just the dotnet runtime if true, and sdk if false. | boolean | - |
|
| additionalVersions | Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
|
||||||
| installUsingApt | If true, it installs using apt instead of the release URL | boolean | true |
|
| dotnetRuntimeVersions | Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
|
||||||
|
| aspNetCoreRuntimeVersions | Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version. | string | - |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `ms-dotnettools.csharp`
|
||||||
|
|
||||||
|
## Configuration examples
|
||||||
|
|
||||||
|
Installing only the latest .NET SDK version (the default).
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": "latest" // or "" or {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing an additional SDK version. Multiple versions can be specified as comma-separated values.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"additionalVersions": "lts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing specific SDK versions.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0",
|
||||||
|
"additionalVersions": "7.0, 8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing a specific SDK feature band.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0.4xx",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing a specific SDK patch version.
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "6.0.412",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Installing only the .NET Runtime or the ASP.NET Core Runtime. (The SDK includes all runtimes so this configuration is only useful if you need to run .NET apps without building them from source.)
|
||||||
|
|
||||||
|
``` json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"ghcr.io/devcontainers/features/dotnet:2": {
|
||||||
|
"version": "none",
|
||||||
|
"dotnetRuntimeVersions": "latest, lts",
|
||||||
|
"aspnetCoreRuntimeVersions": "latest, lts",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,36 +1,53 @@
|
||||||
{
|
{
|
||||||
"id": "dotnet",
|
"id": "dotnet",
|
||||||
"version": "1.0.1",
|
"version": "2.0.2",
|
||||||
"name": "Dotnet CLI",
|
"name": "Dotnet CLI",
|
||||||
"description": "Installs the .NET CLI. Provides option of installing sdk or runtime, and option of versions to install. Uses latest version of .NET sdk as defaults to install.",
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet",
|
||||||
|
"description": "This Feature installs the latest .NET SDK, which includes the .NET CLI and the shared runtime. Options are provided to choose a different version or additional versions.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"proposals": [
|
"proposals": [
|
||||||
"latest",
|
"latest",
|
||||||
"6",
|
"lts",
|
||||||
"5",
|
"none",
|
||||||
"3.1"
|
"8.0",
|
||||||
|
"7.0",
|
||||||
|
"6.0"
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select or enter a dotnet CLI version. (Available versions may vary by Linux distribution.)"
|
"description": "Select or enter a .NET SDK version. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
},
|
},
|
||||||
"runtimeOnly": {
|
"additionalVersions": {
|
||||||
"type": "boolean",
|
"type": "string",
|
||||||
"default": false,
|
"default": "",
|
||||||
"description": "Install just the dotnet runtime if true, and sdk if false."
|
"description": "Enter additional .NET SDK versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
},
|
},
|
||||||
"installUsingApt": {
|
"dotnetRuntimeVersions": {
|
||||||
"type": "boolean",
|
"type": "string",
|
||||||
"default": "true",
|
"default": "",
|
||||||
"description": "If true, it installs using apt instead of the release URL"
|
"description": "Enter additional .NET runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
|
},
|
||||||
|
"aspNetCoreRuntimeVersions": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "Enter additional ASP.NET Core runtime versions, separated by commas. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"DOTNET_ROOT": "/usr/local/dotnet/current",
|
"DOTNET_ROOT": "/usr/share/dotnet",
|
||||||
"PATH": "${PATH}:${DOTNET_ROOT}"
|
"PATH": "$PATH:$DOTNET_ROOT:~/.dotnet/tools",
|
||||||
|
"DOTNET_RUNNING_IN_CONTAINER": "true",
|
||||||
|
"DOTNET_USE_POLLING_FILE_WATCHER": "true"
|
||||||
},
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-dotnettools.csharp"
|
"ms-dotnettools.csharp"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
506
src/dotnet/install.sh
Executable file → Normal file
506
src/dotnet/install.sh
Executable file → Normal file
|
@ -4,467 +4,115 @@
|
||||||
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
#-------------------------------------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/dotnet.md
|
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
DOTNET_VERSION="${VERSION:-"latest"}"
|
||||||
|
ADDITIONAL_VERSIONS="${ADDITIONALVERSIONS}"
|
||||||
|
DOTNET_RUNTIME_VERSIONS="${DOTNETRUNTIMEVERSIONS}"
|
||||||
|
ASPNETCORE_RUNTIME_VERSIONS="${ASPNETCORERUNTIMEVERSIONS}"
|
||||||
|
|
||||||
DOTNET_VERSION=${VERSION:-"latest"}
|
set -e
|
||||||
DOTNET_RUNTIME_ONLY=${RUNTIMEONLY:-"false"}
|
|
||||||
OVERRIDE_DEFAULT_VERSION=${OVERRIDEDEFAULTVERSION:-"true"}
|
|
||||||
INSTALL_USING_APT=${INSTALLUSINGAPT:-"true"}
|
|
||||||
|
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
# Import trim_whitespace and split_csv
|
||||||
UPDATE_RC=${UPDATE_RC:-"true"}
|
source "scripts/string-helpers.sh"
|
||||||
TARGET_DOTNET_ROOT=${TARGET_DOTNET_ROOT:-"/usr/local/dotnet"}
|
|
||||||
ACCESS_GROUP=${ACCESS_GROUP:-"dotnet"}
|
|
||||||
|
|
||||||
MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc"
|
# Import install_sdk and install_runtime
|
||||||
DOTNET_ARCHIVE_ARCHITECTURES="amd64"
|
source "scripts/dotnet-helpers.sh"
|
||||||
DOTNET_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute jammy"
|
|
||||||
# Feed URI sourced from the official dotnet-install.sh
|
|
||||||
# https://github.com/dotnet/install-scripts/blob/1b98b94a6f6d81cc4845eb88e0195fac67caa0a6/src/dotnet-install.sh#L1342-L1343
|
|
||||||
DOTNET_CDN_FEED_URI="https://dotnetcli.azureedge.net"
|
|
||||||
# Ubuntu 22.04 and on do not ship with libssl1.1, which is required for versions of .NET < 6.0
|
|
||||||
DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1="buster bullseye bionic focal hirsute"
|
|
||||||
|
|
||||||
# Comma-separated list of dotnet versions to be installed
|
# Clean up
|
||||||
# alongside DOTNET_VERSION, but not set as default.
|
rm -rf /var/lib/apt/lists/*
|
||||||
ADDITIONAL_VERSIONS=${ADDITIONALVERSIONS:-""}
|
|
||||||
|
|
||||||
# Setup STDERR.
|
# Setup STDERR.
|
||||||
err() {
|
err() {
|
||||||
echo "(!) $*" >&2
|
echo "(!) $*" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure the appropriate root user is running the script.
|
apt_get_update() {
|
||||||
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if packages are installed and installs them if not
|
||||||
|
check_packages() {
|
||||||
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
|
apt_get_update
|
||||||
|
apt-get -y install --no-install-recommends "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
|
# For our own convenience, combine DOTNET_VERSION and ADDITIONAL_VERSIONS into a single 'versions' array
|
||||||
rm -f /etc/profile.d/00-restore-env.sh
|
versions=()
|
||||||
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
|
|
||||||
chmod +x /etc/profile.d/00-restore-env.sh
|
|
||||||
|
|
||||||
# Determine the appropriate non-root user.
|
# The version can be set to 'none' for runtime-only installations, then the array will just remain empty
|
||||||
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
|
# Ensure there are no leading or trailing spaces that can break regex pattern matching
|
||||||
USERNAME=""
|
if [ "$DOTNET_VERSION" != "none" ]; then
|
||||||
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
|
versions+=("$(trim_whitespace "$DOTNET_VERSION")")
|
||||||
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
|
for additional_version in $(split_csv "$ADDITIONAL_VERSIONS"); do
|
||||||
if id -u "${CURRENT_USER}" > /dev/null 2>&1; then
|
versions+=("$additional_version")
|
||||||
USERNAME="${CURRENT_USER}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
if [ "${USERNAME}" = "" ]; then
|
|
||||||
USERNAME=root
|
|
||||||
fi
|
|
||||||
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
|
|
||||||
USERNAME=root
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
###################
|
dotnetRuntimeVersions=()
|
||||||
# Helper Functions
|
for dotnetRuntimeVersion in $(split_csv "$DOTNET_RUNTIME_VERSIONS"); do
|
||||||
###################
|
dotnetRuntimeVersions+=("$dotnetRuntimeVersion")
|
||||||
|
done
|
||||||
|
|
||||||
# Cleanup temporary directory and associated files when exiting the script.
|
aspNetCoreRuntimeVersions=()
|
||||||
cleanup() {
|
for aspNetCoreRuntimeVersion in $(split_csv "$ASPNETCORE_RUNTIME_VERSIONS"); do
|
||||||
EXIT_CODE=$?
|
aspNetCoreRuntimeVersions+=("$aspNetCoreRuntimeVersion")
|
||||||
set +e
|
done
|
||||||
if [[ -n "${TMP_DIR}" ]]; then
|
|
||||||
echo "Executing cleanup of tmp files"
|
|
||||||
rm -Rf "${TMP_DIR}"
|
|
||||||
fi
|
|
||||||
exit $EXIT_CODE
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
# Get central common setting
|
# Fail fast in case of bad input to avoid unneccesary work
|
||||||
get_common_setting() {
|
# v1 of the .NET feature allowed specifying only a major version 'X' like '3'
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
# v2 removed this ability
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
# - because install-dotnet.sh does not support it directly
|
||||||
common_settings_file_loaded=true
|
# - because the previous behavior installed an old version like '3.0.103', not the newest version '3.1.426', which was counterintuitive
|
||||||
fi
|
for version in "${versions[@]}"; do
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
if [[ "$version" =~ ^[0-9]+$ ]]; then
|
||||||
local multi_line=""
|
err "Unsupported .NET SDK version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add dotnet directory to PATH in bashrc/zshrc files if OVERRIDE_DEFAULT_VERSION=true.
|
|
||||||
updaterc() {
|
|
||||||
if [ "${UPDATE_RC}" = "true" ]; then
|
|
||||||
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
|
|
||||||
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
|
|
||||||
echo -e "$1" >> /etc/bash.bashrc
|
|
||||||
fi
|
|
||||||
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
|
|
||||||
echo -e "$1" >> /etc/zsh/zshrc
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run apt-get if needed.
|
|
||||||
apt_get_update_if_needed() {
|
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
|
||||||
echo "Running apt-get update..."
|
|
||||||
apt-get update
|
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if packages are installed and installs them if not.
|
|
||||||
check_packages() {
|
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
|
||||||
apt_get_update_if_needed
|
|
||||||
apt-get -y install --no-install-recommends "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get appropriate architecture name for .NET binaries for the target OS
|
|
||||||
get_architecture_name_for_target_os() {
|
|
||||||
local architecture
|
|
||||||
architecture="$(uname -m)"
|
|
||||||
case $architecture in
|
|
||||||
x86_64) architecture="x64";;
|
|
||||||
aarch64 | armv8*) architecture="arm64";;
|
|
||||||
*) err "Architecture ${architecture} unsupported"; exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "${architecture}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Soft version matching that resolves a version for a given package in the *current apt-cache*
|
|
||||||
# Return value is stored in first argument (the unprocessed version)
|
|
||||||
apt_cache_package_and_version_soft_match() {
|
|
||||||
# Version
|
|
||||||
local version_variable_name="$1"
|
|
||||||
local requested_version=${!version_variable_name}
|
|
||||||
# Package Name
|
|
||||||
local package_variable_name="$2"
|
|
||||||
local partial_package_name=${!package_variable_name}
|
|
||||||
local package_name
|
|
||||||
# Exit on no match?
|
|
||||||
local exit_on_no_match="${3:-true}"
|
|
||||||
local major_minor_version
|
|
||||||
|
|
||||||
# Ensure we've exported useful variables
|
|
||||||
. /etc/os-release
|
|
||||||
local architecture="$(dpkg --print-architecture)"
|
|
||||||
|
|
||||||
major_minor_version="$(echo "${requested_version}" | cut -d "." --field=1,2)"
|
|
||||||
package_name="$(apt-cache search "${partial_package_name}-[0-9].[0-9]" | awk -F" - " '{print $1}' | grep -m 1 "${partial_package_name}-${major_minor_version}")"
|
|
||||||
|
|
||||||
dot_escaped="${requested_version//./\\.}"
|
|
||||||
dot_plus_escaped="${dot_escaped//+/\\+}"
|
|
||||||
# Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/
|
|
||||||
version_regex="^(.+:)?${dot_plus_escaped}([\\.\\+ ~:-]|$)"
|
|
||||||
set +e # Don't exit if finding version fails - handle gracefully
|
|
||||||
fuzzy_version="$(apt-cache madison ${package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${version_regex}")"
|
|
||||||
set -e
|
|
||||||
if [ -z "${fuzzy_version}" ]; then
|
|
||||||
echo "(!) No full or partial for package \"${partial_package_name}\" (resolved: \"${package_name}\") match found in apt-cache for \"${requested_version}\" on OS ${ID} ${VERSION_CODENAME} (${architecture})."
|
|
||||||
|
|
||||||
if $exit_on_no_match; then
|
|
||||||
echo "Available versions:"
|
|
||||||
apt-cache madison ${package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+'
|
|
||||||
exit 1 # Fail entire script
|
|
||||||
else
|
|
||||||
echo "Continuing to fallback method if available"
|
|
||||||
return 1;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Globally assign fuzzy_version to this value
|
|
||||||
# Use this value as the return value of this function
|
|
||||||
declare -g ${version_variable_name}="=${fuzzy_version}"
|
|
||||||
echo "${version_variable_name} ${!version_variable_name}"
|
|
||||||
|
|
||||||
# Globally assign package to this value
|
|
||||||
# Use this value as the return value of this function
|
|
||||||
declare -g ${package_variable_name}="${package_name}"
|
|
||||||
echo "${package_variable_name} ${!package_variable_name}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install .NET CLI using apt-get package installer
|
|
||||||
install_using_apt_from_microsoft_repo() {
|
|
||||||
local sdk_or_runtime="$1"
|
|
||||||
local dotnet_major_minor_version
|
|
||||||
export DOTNET_PACKAGE="dotnet-${sdk_or_runtime}"
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr
|
|
||||||
|
|
||||||
# Import key safely and import Microsoft apt repo
|
|
||||||
get_common_setting MICROSOFT_GPG_KEYS_URI
|
|
||||||
curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg
|
|
||||||
echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list
|
|
||||||
apt-get update -y
|
|
||||||
|
|
||||||
if [ "${DOTNET_VERSION}" = "latest" ] || [ "${DOTNET_VERSION}" = "lts" ]; then
|
|
||||||
DOTNET_VERSION=""
|
|
||||||
DOTNET_PACKAGE="${DOTNET_PACKAGE}-6.0"
|
|
||||||
else
|
|
||||||
# Sets DOTNET_VERSION and DOTNET_PACKAGE if matches found.
|
|
||||||
apt_cache_package_and_version_soft_match DOTNET_VERSION DOTNET_PACKAGE false
|
|
||||||
if [ "$?" != 0 ]; then
|
|
||||||
echo "Failed to find requested version."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $(dotnet --version) == *"${DOTNET_VERSION}"* ]] ; then
|
|
||||||
echo "Dotnet version ${DOTNET_VERSION} is already installed"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Installing '${DOTNET_PACKAGE}${DOTNET_VERSION}'..."
|
|
||||||
apt-get install -yq ${DOTNET_PACKAGE}${DOTNET_VERSION}
|
|
||||||
if [ "$?" != 0 ]; then
|
|
||||||
echo "Failed to complete apt install of ${DOTNET_PACKAGE}${DOTNET_VERSION}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
install_using_default_apt_repo() {
|
|
||||||
DOTNET_PACKAGE="dotnet6"
|
|
||||||
|
|
||||||
apt_get_update_if_needed
|
|
||||||
|
|
||||||
if [[ "${DOTNET_VERSION}" = "latest" ]] || [[ "${DOTNET_VERSION}" = "lts" ]] || [[ ${DOTNET_VERSION} = "6"* ]]; then
|
|
||||||
if ! (apt-get install -yq ${DOTNET_PACKAGE}); then
|
|
||||||
echo "Failed to install 'dotnet6' package from default apt repo."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "The provided dotnet version is not distributed in this distro's default apt repo."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find and extract .NET binary download details based on user-requested version
|
|
||||||
# args:
|
|
||||||
# sdk_or_runtime $1
|
|
||||||
# exports:
|
|
||||||
# DOTNET_DOWNLOAD_URL
|
|
||||||
# DOTNET_DOWNLOAD_HASH
|
|
||||||
# DOTNET_DOWNLOAD_NAME
|
|
||||||
get_full_version_details() {
|
|
||||||
local sdk_or_runtime="$1"
|
|
||||||
local VERSION="$2"
|
|
||||||
local architecture
|
|
||||||
local dotnet_channel_version
|
|
||||||
local dotnet_releases_url
|
|
||||||
local dotnet_releases_json
|
|
||||||
local dotnet_latest_version
|
|
||||||
local dotnet_download_details
|
|
||||||
|
|
||||||
export DOTNET_DOWNLOAD_URL
|
|
||||||
export DOTNET_DOWNLOAD_HASH
|
|
||||||
export DOTNET_DOWNLOAD_NAME
|
|
||||||
|
|
||||||
# Set architecture variable to current user's architecture (x64 or ARM64).
|
|
||||||
architecture="$(get_architecture_name_for_target_os)"
|
|
||||||
|
|
||||||
# Set VERSION to empty string to ensure jq includes all .NET versions in reverse sort below
|
|
||||||
if [ "${VERSION}" = "latest" ]; then
|
|
||||||
VERSION=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
dotnet_patchless_version="$(echo "${VERSION}" | cut -d "." --field=1,2)"
|
|
||||||
|
|
||||||
set +e
|
|
||||||
dotnet_channel_version="$(curl -s "${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/releases-index.json" | jq -r --arg channel_version "${dotnet_patchless_version}" '[."releases-index"[]] | sort_by(."channel-version") | reverse | map( select(."channel-version" | startswith($channel_version))) | first | ."channel-version"')"
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Construct the releases URL using the official channel-version if one was found. Otherwise make a best-effort using the user input.
|
|
||||||
if [ -n "${dotnet_channel_version}" ] && [ "${dotnet_channel_version}" != "null" ]; then
|
|
||||||
dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_channel_version}/releases.json"
|
|
||||||
else
|
|
||||||
dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_patchless_version}/releases.json"
|
|
||||||
fi
|
|
||||||
|
|
||||||
set +e
|
|
||||||
dotnet_releases_json="$(curl -s "${dotnet_releases_url}")"
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -n "${dotnet_releases_json}" ] && [[ ! "${dotnet_releases_json}" = *"Error"* ]]; then
|
|
||||||
dotnet_latest_version="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" '."latest-\($sdk_or_runtime)"')"
|
|
||||||
# If user-specified version has 2 or more dots, use it as is. Otherwise use latest version.
|
|
||||||
if [ "$(echo "${VERSION}" | grep -o "\." | wc -l)" -lt "2" ]; then
|
|
||||||
VERSION="${dotnet_latest_version}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
dotnet_download_details="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" --arg dotnet_version "${VERSION}" --arg arch "${architecture}" '.releases[]."\($sdk_or_runtime)" | select(.version==$dotnet_version) | .files[] | select(.name=="dotnet-\($sdk_or_runtime)-linux-\($arch).tar.gz")')"
|
|
||||||
if [ -n "${dotnet_download_details}" ]; then
|
|
||||||
echo "Found .NET binary version ${VERSION}"
|
|
||||||
DOTNET_DOWNLOAD_URL="$(echo "${dotnet_download_details}" | jq -r '.url')"
|
|
||||||
DOTNET_DOWNLOAD_HASH="$(echo "${dotnet_download_details}" | jq -r '.hash')"
|
|
||||||
DOTNET_DOWNLOAD_NAME="$(echo "${dotnet_download_details}" | jq -r '.name')"
|
|
||||||
else
|
|
||||||
err "Unable to find .NET binary for version ${VERSION}"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
done
|
||||||
err "Unable to find .NET release details for version ${VERSION} at ${dotnet_releases_url}"
|
|
||||||
|
for version in "${dotnetRuntimeVersions[@]}"; do
|
||||||
|
if [[ "$version" =~ ^[0-9]+$ ]]; then
|
||||||
|
err "Unsupported .NET Runtime version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
done
|
||||||
|
|
||||||
# Install .NET CLI using the .NET releases url
|
for version in "${aspNetCoreRuntimeVersions[@]}"; do
|
||||||
install_using_dotnet_releases_url() {
|
if [[ "$version" =~ ^[0-9]+$ ]]; then
|
||||||
local sdk_or_runtime="$1"
|
err "Unsupported ASP.NET Core Runtime version '${version}'. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' or 'X.Y.Z' for a specific version."
|
||||||
local VERSION="$2"
|
|
||||||
|
|
||||||
# Check listed package dependecies and install them if they are not already installed.
|
|
||||||
# NOTE: icu-devtools is a small package with similar dependecies to .NET.
|
|
||||||
# It will install the appropriate dependencies based on the OS:
|
|
||||||
# - libgcc-s1 OR libgcc1 depending on OS
|
|
||||||
# - the latest libicuXX depending on OS (eg libicu57 for stretch)
|
|
||||||
# - also installs libc6 and libstdc++6 which are required by .NET
|
|
||||||
check_packages curl ca-certificates tar jq icu-devtools libgssapi-krb5-2 zlib1g
|
|
||||||
|
|
||||||
# Starting with Ubuntu 22.04 (jammy), libssl1.1 does not ship with the OS anymore.
|
|
||||||
if [[ "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then
|
|
||||||
check_packages libssl1.1
|
|
||||||
else
|
|
||||||
check_packages libssl3.0
|
|
||||||
fi
|
|
||||||
|
|
||||||
get_full_version_details "${sdk_or_runtime}" "${VERSION}"
|
|
||||||
|
|
||||||
DOTNET_INSTALL_PATH="${TARGET_DOTNET_ROOT}/${VERSION}"
|
|
||||||
if [ -d "${DOTNET_INSTALL_PATH}" ]; then
|
|
||||||
echo "(!) Dotnet version ${VERSION} already exists."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# exports DOTNET_DOWNLOAD_URL, DOTNET_DOWNLOAD_HASH, DOTNET_DOWNLOAD_NAME
|
done
|
||||||
echo "DOWNLOAD LINK: ${DOTNET_DOWNLOAD_URL}"
|
|
||||||
|
|
||||||
# Setup the access group and add the user to it.
|
# Install .NET versions and dependencies
|
||||||
umask 0002
|
# icu-devtools includes dependencies for .NET
|
||||||
if ! cat /etc/group | grep -e "^${ACCESS_GROUP}:" > /dev/null 2>&1; then
|
check_packages wget ca-certificates icu-devtools
|
||||||
groupadd -r "${ACCESS_GROUP}"
|
|
||||||
fi
|
|
||||||
usermod -a -G "${ACCESS_GROUP}" "${USERNAME}"
|
|
||||||
|
|
||||||
# Download the .NET binaries.
|
for version in "${versions[@]}"; do
|
||||||
echo "DOWNLOADING BINARY..."
|
install_sdk "$version"
|
||||||
TMP_DIR="/tmp/dotnetinstall"
|
done
|
||||||
mkdir -p "${TMP_DIR}"
|
|
||||||
curl -sSL "${DOTNET_DOWNLOAD_URL}" -o "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}"
|
|
||||||
|
|
||||||
# Get checksum from .NET CLI blob storage using the runtime version and
|
for version in "${dotnetRuntimeVersions[@]}"; do
|
||||||
# run validation (sha512sum) of checksum against the expected checksum hash.
|
install_runtime "dotnet" "$version"
|
||||||
echo "VERIFY CHECKSUM"
|
done
|
||||||
cd "${TMP_DIR}"
|
|
||||||
echo "${DOTNET_DOWNLOAD_HASH} *${DOTNET_DOWNLOAD_NAME}" | sha512sum -c -
|
|
||||||
|
|
||||||
# Extract binaries and add to path.
|
for version in "${aspNetCoreRuntimeVersions[@]}"; do
|
||||||
mkdir -p "${DOTNET_INSTALL_PATH}"
|
install_runtime "aspnetcore" "$version"
|
||||||
echo "Extract Binary to ${DOTNET_INSTALL_PATH}"
|
done
|
||||||
tar -xzf "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}" -C "${DOTNET_INSTALL_PATH}" --strip-components=1
|
|
||||||
|
|
||||||
CURRENT_DIR="${TARGET_DOTNET_ROOT}/current"
|
# Clean up
|
||||||
if [[ ! -d "${CURRENT_DIR}" ]]; then
|
rm -rf /var/lib/apt/lists/*
|
||||||
ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}"
|
rm -rf scripts
|
||||||
fi
|
|
||||||
|
|
||||||
# Give write permissions to the user.
|
|
||||||
chown -R "${USERNAME}:${USERNAME}" "${CURRENT_DIR}"
|
|
||||||
chmod g+r+w+s "${CURRENT_DIR}"
|
|
||||||
chmod -R g+r+w "${CURRENT_DIR}"
|
|
||||||
|
|
||||||
if [[ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]]; then
|
|
||||||
if [[ $(ls -l ${CURRENT_DIR}) != *"-> ${DOTNET_INSTALL_PATH}"* ]] ; then
|
|
||||||
rm "${CURRENT_DIR}"
|
|
||||||
ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_DIR}\"* ]]; then export PATH=${CURRENT_DIR}:\${PATH}; fi"
|
|
||||||
}
|
|
||||||
|
|
||||||
###########################
|
|
||||||
# Start .NET installation
|
|
||||||
###########################
|
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
. /etc/os-release
|
|
||||||
architecture="$(dpkg --print-architecture)"
|
|
||||||
|
|
||||||
# Dotnet 3.1 and 5 are not supported on Ubuntu 22.04 (jammy)+,
|
|
||||||
# due to lack of libssl3.0 support.
|
|
||||||
# See: https://github.com/microsoft/vscode-dev-containers/issues/1458#issuecomment-1135077775
|
|
||||||
# NOTE: This will only guard against installation of the dotnet versions we propose via 'features'.
|
|
||||||
# The user can attempt to install any other version at their own risk.
|
|
||||||
if [[ "${DOTNET_VERSION}" = "3"* ]] || [[ "${DOTNET_VERSION}" = "5"* ]]; then
|
|
||||||
if [[ ! "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then
|
|
||||||
err "Dotnet ${DOTNET_VERSION} is not supported on Ubuntu ${VERSION_CODENAME} due to a change in the 'libssl' dependency across distributions.\n Please upgrade your version of dotnet, or downgrade your OS version."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine if the user wants to download .NET Runtime only, or .NET SDK & Runtime
|
|
||||||
# and set the appropriate variables.
|
|
||||||
if [ "${DOTNET_RUNTIME_ONLY}" = "true" ]; then
|
|
||||||
DOTNET_SDK_OR_RUNTIME="runtime"
|
|
||||||
elif [ "${DOTNET_RUNTIME_ONLY}" = "false" ]; then
|
|
||||||
DOTNET_SDK_OR_RUNTIME="sdk"
|
|
||||||
else
|
|
||||||
err "Expected true for installing dotnet Runtime only or false for installing SDK and Runtime. Received ${DOTNET_RUNTIME_ONLY}."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install the .NET CLI
|
|
||||||
echo "(*) Installing .NET CLI..."
|
|
||||||
|
|
||||||
CHANGE_OWNERSHIP="false"
|
|
||||||
if [[ "${DOTNET_ARCHIVE_ARCHITECTURES}" = *"${architecture}"* ]] && [[ "${DOTNET_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]] && [[ "${INSTALL_USING_APT}" = "true" ]]; then
|
|
||||||
echo "Detected ${VERSION_CODENAME} on ${architecture}. Attempting to install dotnet from apt"
|
|
||||||
|
|
||||||
install_using_default_apt_repo || install_using_apt_from_microsoft_repo "${DOTNET_SDK_OR_RUNTIME}"
|
|
||||||
if [ "$?" != 0 ]; then
|
|
||||||
echo "Could not install requested version from apt on current distribution."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [[ "${INSTALL_USING_APT}" = "false" ]]; then
|
|
||||||
echo "Installing dotnet from releases url"
|
|
||||||
else
|
|
||||||
echo "Attempting to install dotnet from releases url"
|
|
||||||
fi
|
|
||||||
install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}"
|
|
||||||
CHANGE_OWNERSHIP="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Additional dotnet versions to be installed but not be set as default.
|
|
||||||
if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
|
|
||||||
OLDIFS=$IFS
|
|
||||||
IFS=","
|
|
||||||
read -a additional_versions <<< "$ADDITIONAL_VERSIONS"
|
|
||||||
for version in "${additional_versions[@]}"; do
|
|
||||||
OVERRIDE_DEFAULT_VERSION="false"
|
|
||||||
install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${version}"
|
|
||||||
done
|
|
||||||
IFS=$OLDIFS
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${CHANGE_OWNERSHIP}" = "true" ]; then
|
|
||||||
if ! cat /etc/group | grep -e "^dotnet:" > /dev/null 2>&1; then
|
|
||||||
groupadd -r dotnet
|
|
||||||
fi
|
|
||||||
usermod -a -G dotnet "${USERNAME}"
|
|
||||||
|
|
||||||
chown -R "${USERNAME}:dotnet" "${TARGET_DOTNET_ROOT}"
|
|
||||||
chmod -R g+r+w "${TARGET_DOTNET_ROOT}"
|
|
||||||
find "${TARGET_DOTNET_ROOT}" -type d | xargs -n 1 chmod g+s
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
119
src/dotnet/scripts/dotnet-helpers.sh
Normal file
119
src/dotnet/scripts/dotnet-helpers.sh
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
|
||||||
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
|
||||||
|
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
|
||||||
|
DOTNET_INSTALL_DIR='/usr/share/dotnet'
|
||||||
|
|
||||||
|
# Prints the latest dotnet version in the specified channel
|
||||||
|
# Usage: fetch_latest_version_in_channel <channel> [<runtime>]
|
||||||
|
# Example: fetch_latest_version_in_channel "LTS"
|
||||||
|
# Example: fetch_latest_version_in_channel "6.0" "dotnet"
|
||||||
|
# Example: fetch_latest_version_in_channel "6.0" "aspnetcore"
|
||||||
|
fetch_latest_version_in_channel() {
|
||||||
|
local channel="$1"
|
||||||
|
local runtime="$2"
|
||||||
|
if [ "$runtime" = "dotnet" ]; then
|
||||||
|
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Runtime/$channel/latest.version"
|
||||||
|
elif [ "$runtime" = "aspnetcore" ]; then
|
||||||
|
wget -qO- "https://dotnetcli.azureedge.net/dotnet/aspnetcore/Runtime/$channel/latest.version"
|
||||||
|
else
|
||||||
|
wget -qO- "https://dotnetcli.azureedge.net/dotnet/Sdk/$channel/latest.version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prints the latest dotnet version
|
||||||
|
# Usage: fetch_latest_version [<runtime>]
|
||||||
|
# Example: fetch_latest_version
|
||||||
|
# Example: fetch_latest_version "dotnet"
|
||||||
|
# Example: fetch_latest_version "aspnetcore"
|
||||||
|
fetch_latest_version() {
|
||||||
|
local runtime="$1"
|
||||||
|
local sts_version
|
||||||
|
local lts_version
|
||||||
|
sts_version=$(fetch_latest_version_in_channel "STS" "$runtime")
|
||||||
|
lts_version=$(fetch_latest_version_in_channel "LTS" "$runtime")
|
||||||
|
if [[ "$sts_version" > "$lts_version" ]]; then
|
||||||
|
echo "$sts_version"
|
||||||
|
else
|
||||||
|
echo "$lts_version"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Installs a version of the .NET SDK
|
||||||
|
# Usage: install_sdk <version>
|
||||||
|
install_sdk() {
|
||||||
|
local inputVersion="$1"
|
||||||
|
local version=""
|
||||||
|
local channel=""
|
||||||
|
if [[ "$inputVersion" == "latest" ]]; then
|
||||||
|
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
|
||||||
|
version=$(fetch_latest_version)
|
||||||
|
elif [[ "$inputVersion" == "lts" ]]; then
|
||||||
|
# When user input is 'lts'
|
||||||
|
# Then version=latest, channel=LTS
|
||||||
|
version="latest"
|
||||||
|
channel="LTS"
|
||||||
|
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
# When user input is form 'A.B' like '3.1'
|
||||||
|
# Then version=latest, channel=3.1
|
||||||
|
version="latest"
|
||||||
|
channel="$inputVersion"
|
||||||
|
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+\.[0-9]xx$ ]]; then
|
||||||
|
# When user input is form 'A.B.Cxx' like '6.0.4xx'
|
||||||
|
# Then version=latest, channel=6.0.4xx
|
||||||
|
version="latest"
|
||||||
|
channel="$inputVersion"
|
||||||
|
else
|
||||||
|
# Assume version is an exact version string like '6.0.413' or '8.0.100-rc.2.23425.18'
|
||||||
|
version="$inputVersion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Currently this script does not make it possible to qualify the version, 'GA' is always implied
|
||||||
|
echo "Executing $DOTNET_INSTALL_SCRIPT --version $version --channel $channel --install-dir $DOTNET_INSTALL_DIR --no-path"
|
||||||
|
"$DOTNET_INSTALL_SCRIPT" \
|
||||||
|
--version "$version" \
|
||||||
|
--channel "$channel" \
|
||||||
|
--install-dir "$DOTNET_INSTALL_DIR" \
|
||||||
|
--no-path
|
||||||
|
}
|
||||||
|
|
||||||
|
# Installs a version of the .NET Runtime
|
||||||
|
# Usage: install_runtime <runtime> <version>
|
||||||
|
install_runtime() {
|
||||||
|
local runtime="$1"
|
||||||
|
local inputVersion="$2"
|
||||||
|
local version=""
|
||||||
|
local channel=""
|
||||||
|
if [[ "$inputVersion" == "latest" ]]; then
|
||||||
|
# Fetch the latest version manually, because dotnet-install.sh does not support it directly
|
||||||
|
version=$(fetch_latest_version "$runtime")
|
||||||
|
elif [[ "$inputVersion" == "lts" ]]; then
|
||||||
|
# When user input is 'lts'
|
||||||
|
# Then version=latest, channel=LTS
|
||||||
|
version="latest"
|
||||||
|
channel="LTS"
|
||||||
|
elif [[ "$inputVersion" =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
# When user input is form 'A.B' like '3.1'
|
||||||
|
# Then version=latest, channel=3.1
|
||||||
|
version="latest"
|
||||||
|
channel="$inputVersion"
|
||||||
|
else
|
||||||
|
# Assume version is an exact version string like '6.0.21' or '8.0.0-preview.7.23375.6'
|
||||||
|
version="$inputVersion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Executing $DOTNET_INSTALL_SCRIPT --runtime $runtime --version $version --channel $channel --install-dir $DOTNET_INSTALL_DIR --no-path"
|
||||||
|
"$DOTNET_INSTALL_SCRIPT" \
|
||||||
|
--runtime "$runtime" \
|
||||||
|
--version "$version" \
|
||||||
|
--channel "$channel" \
|
||||||
|
--install-dir "$DOTNET_INSTALL_DIR" \
|
||||||
|
--no-path
|
||||||
|
}
|
16
src/dotnet/scripts/fetch-latest-dotnet-install.sh
Executable file
16
src/dotnet/scripts/fetch-latest-dotnet-install.sh
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
|
||||||
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
#
|
||||||
|
# Run this script to replace dotnet-install.sh with the latest and greatest available version
|
||||||
|
#
|
||||||
|
DOTNET_SCRIPTS=$(dirname "${BASH_SOURCE[0]}")
|
||||||
|
DOTNET_INSTALL_SCRIPT="$DOTNET_SCRIPTS/vendor/dotnet-install.sh"
|
||||||
|
|
||||||
|
wget https://dot.net/v1/dotnet-install.sh -O "$DOTNET_INSTALL_SCRIPT"
|
||||||
|
chmod +x "$DOTNET_INSTALL_SCRIPT"
|
42
src/dotnet/scripts/string-helpers.sh
Normal file
42
src/dotnet/scripts/string-helpers.sh
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
|
||||||
|
#-------------------------------------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet
|
||||||
|
# Maintainer: The Dev Container spec maintainers
|
||||||
|
|
||||||
|
# Removes leading and trailing whitespace from an input string
|
||||||
|
# Usage: trim_whitespace <text>
|
||||||
|
trim_whitespace() {
|
||||||
|
text="$1"
|
||||||
|
|
||||||
|
# Remove leading spaces
|
||||||
|
while [ "${text:0:1}" == " " ]; do
|
||||||
|
text="${text:1}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Remove trailing spaces
|
||||||
|
while [ "${text: -1}" == " " ]; do
|
||||||
|
text="${text:0:-1}"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$text"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Splits comma-separated values into an array while ignoring empty entries
|
||||||
|
# Usage: split_csv <comma-separated-values>
|
||||||
|
split_csv() {
|
||||||
|
local -a values=()
|
||||||
|
while IFS="," read -ra entries; do
|
||||||
|
for entry in "${entries[@]}"; do
|
||||||
|
entry="$(trim_whitespace "$entry")"
|
||||||
|
if [ -n "$entry" ]; then
|
||||||
|
values+=("$entry")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done <<< "$1"
|
||||||
|
|
||||||
|
echo "${values[@]}"
|
||||||
|
}
|
27
src/dotnet/scripts/vendor/README.md
vendored
Normal file
27
src/dotnet/scripts/vendor/README.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
### **IMPORTANT NOTE**
|
||||||
|
|
||||||
|
Scripts in this directory are sourced externally and not maintained by the Dev Container spec maintainers. Do not make changes directly as they might be overwritten at any moment.
|
||||||
|
|
||||||
|
## dotnet-install.sh
|
||||||
|
|
||||||
|
`dotnet-install.sh` is a copy of <https://dot.net/v1/dotnet-install.sh>. ([Script reference](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script))
|
||||||
|
|
||||||
|
Quick options reminder for `dotnet-install.sh`:
|
||||||
|
|
||||||
|
- `--version`: `"latest"` (default) or an exact version in the form A.B.C like `"6.0.413"`
|
||||||
|
- `--channel`: `"LTS"` (default), `"STS"`, a two-part version in the form A.B like `"6.0"` or three-part form A.B.Cxx like `"6.0.1xx"`
|
||||||
|
- `--quality`: `"daily"`, `"preview"` or `"GA"`
|
||||||
|
- The channel option is only used when version is 'latest' because an exact version overrides the channel option
|
||||||
|
- The quality option is only used when channel is 'A.B' or 'A.B.Cxx' because it can't be used with STS or LTS
|
||||||
|
|
||||||
|
Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
dotnet-install.sh [--version latest] [--channel LTS]
|
||||||
|
dotnet-install.sh [--version latest] --channel STS
|
||||||
|
dotnet-install.sh [--version latest] --channel 6.0 [--quality GA]
|
||||||
|
dotnet-install.sh [--version latest] --channel 6.0.4xx [--quality GA]
|
||||||
|
dotnet-install.sh [--version latest] --channel 8.0 --quality preview
|
||||||
|
dotnet-install.sh [--version latest] --channel 8.0 --quality daily
|
||||||
|
dotnet-install.sh --version 6.0.413
|
||||||
|
```
|
1835
src/dotnet/scripts/vendor/dotnet-install.sh
vendored
Executable file
1835
src/dotnet/scripts/vendor/dotnet-install.sh
vendored
Executable file
File diff suppressed because it is too large
Load diff
7
src/git-lfs/NOTES.md
Normal file
7
src/git-lfs/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Installs Git Large File Support (Git LFS) along with needed dependencies. Useful
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/git-lfs:1": {
|
"ghcr.io/devcontainers/features/git-lfs:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,9 +16,17 @@ Installs Git Large File Support (Git LFS) along with needed dependencies. Useful
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select version of Git LFS to install | string | latest |
|
| version | Select version of Git LFS to install | string | latest |
|
||||||
|
| autoPull | Automatically pull LFS files when creating the container. When false, running 'git lfs pull' in the container will have the same effect. | boolean | true |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/git-lfs/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/git-lfs/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
{
|
{
|
||||||
"id": "git-lfs",
|
"id": "git-lfs",
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"name": "Git Large File Support (LFS)",
|
"name": "Git Large File Support (LFS)",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/git-lfs",
|
||||||
"description": "Installs Git Large File Support (Git LFS) along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like git and curl.",
|
"description": "Installs Git Large File Support (Git LFS) along with needed dependencies. Useful for base Dockerfiles that often are missing required install dependencies like git and curl.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"proposals": [
|
||||||
"latest",
|
"latest",
|
||||||
"none"
|
"none"
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select version of Git LFS to install"
|
"description": "Select version of Git LFS to install"
|
||||||
|
},
|
||||||
|
"autoPull": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Automatically pull LFS files when creating the container. When false, running 'git lfs pull' in the container will have the same effect."
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"postCreateCommand": "/usr/local/share/pull-git-lfs-artifacts.sh",
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,37 +8,27 @@
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
GIT_LFS_VERSION=${VERSION:-"latest"}
|
GIT_LFS_VERSION=${VERSION:-"latest"}
|
||||||
|
AUTO_PULL=${AUTOPULL:="true"}
|
||||||
|
|
||||||
GIT_LFS_ARCHIVE_GPG_KEY_URI="https://packagecloud.io/github/git-lfs/gpgkey"
|
GIT_LFS_ARCHIVE_GPG_KEY_URI="https://packagecloud.io/github/git-lfs/gpgkey"
|
||||||
GIT_LFS_ARCHIVE_ARCHITECTURES="amd64 arm64"
|
GIT_LFS_ARCHIVE_ARCHITECTURES="amd64 arm64"
|
||||||
GIT_LFS_ARCHIVE_VERSION_CODENAMES="stretch buster bullseye bionic focal jammy"
|
GIT_LFS_ARCHIVE_VERSION_CODENAMES="stretch buster bullseye bionic focal jammy"
|
||||||
GIT_LFS_CHECKSUM_GPG_KEYS="0x88ace9b29196305ba9947552f1ba225c0223b187 0x86cd3297749375bcf8206715f54fe648088335a9 0xaa3b3450295830d2de6db90caba67be5a5795889"
|
GIT_LFS_CHECKSUM_GPG_KEYS="0x88ace9b29196305ba9947552f1ba225c0223b187 0x86cd3297749375bcf8206715f54fe648088335a9 0xaa3b3450295830d2de6db90caba67be5a5795889"
|
||||||
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
|
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com
|
||||||
|
keyserver hkp://keyserver.ubuntu.com:80
|
||||||
keyserver hkps://keys.openpgp.org
|
keyserver hkps://keys.openpgp.org
|
||||||
keyserver hkp://keyserver.pgp.com"
|
keyserver hkp://keyserver.pgp.com"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Figure out correct version of a three part version number is not passed
|
# Figure out correct version of a three part version number is not passed
|
||||||
find_version_from_git_tags() {
|
find_version_from_git_tags() {
|
||||||
local variable_name=$1
|
local variable_name=$1
|
||||||
|
@ -75,11 +65,9 @@ find_version_from_git_tags() {
|
||||||
|
|
||||||
# Import the specified key in a variable name passed in as
|
# Import the specified key in a variable name passed in as
|
||||||
receive_gpg_keys() {
|
receive_gpg_keys() {
|
||||||
get_common_setting $1
|
|
||||||
local keys=${!1}
|
local keys=${!1}
|
||||||
get_common_setting GPG_KEY_SERVERS true
|
|
||||||
|
|
||||||
# Use a temporary locaiton for gpg keys to avoid polluting image
|
# Use a temporary location for gpg keys to avoid polluting image
|
||||||
export GNUPGHOME="/tmp/tmp-gnupg"
|
export GNUPGHOME="/tmp/tmp-gnupg"
|
||||||
mkdir -p ${GNUPGHOME}
|
mkdir -p ${GNUPGHOME}
|
||||||
chmod 700 ${GNUPGHOME}
|
chmod 700 ${GNUPGHOME}
|
||||||
|
@ -105,21 +93,18 @@ receive_gpg_keys() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
apt_get_update()
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -133,7 +118,6 @@ install_using_apt() {
|
||||||
version_suffix=""
|
version_suffix=""
|
||||||
fi
|
fi
|
||||||
# Install
|
# Install
|
||||||
get_common_setting GIT_LFS_ARCHIVE_GPG_KEY_URI
|
|
||||||
curl -sSL "${GIT_LFS_ARCHIVE_GPG_KEY_URI}" | gpg --dearmor > /usr/share/keyrings/gitlfs-archive-keyring.gpg
|
curl -sSL "${GIT_LFS_ARCHIVE_GPG_KEY_URI}" | gpg --dearmor > /usr/share/keyrings/gitlfs-archive-keyring.gpg
|
||||||
echo -e "deb [arch=${architecture} signed-by=/usr/share/keyrings/gitlfs-archive-keyring.gpg] https://packagecloud.io/github/git-lfs/${ID} ${VERSION_CODENAME} main\ndeb-src [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gitlfs-archive-keyring.gpg] https://packagecloud.io/github/git-lfs/${ID} ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/git-lfs.list
|
echo -e "deb [arch=${architecture} signed-by=/usr/share/keyrings/gitlfs-archive-keyring.gpg] https://packagecloud.io/github/git-lfs/${ID} ${VERSION_CODENAME} main\ndeb-src [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gitlfs-archive-keyring.gpg] https://packagecloud.io/github/git-lfs/${ID} ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/git-lfs.list
|
||||||
|
|
||||||
|
@ -183,8 +167,7 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
check_packages curl ca-certificates gnupg2 dirmngr apt-transport-https
|
check_packages curl ca-certificates gnupg2 dirmngr apt-transport-https
|
||||||
if ! type git > /dev/null 2>&1; then
|
if ! type git > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
check_packages git
|
||||||
apt-get -y install --no-install-recommends git
|
|
||||||
fi
|
fi
|
||||||
if [ "${ID}" = "debian" ]; then
|
if [ "${ID}" = "debian" ]; then
|
||||||
check_packages debian-archive-keyring
|
check_packages debian-archive-keyring
|
||||||
|
@ -204,4 +187,38 @@ if [ "${use_github}" = "true" ]; then
|
||||||
install_using_github
|
install_using_github
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --- Generate a 'pull-git-lfs-artifacts.sh' script to be executed by the 'postCreateCommand' lifecycle hook
|
||||||
|
PULL_GIT_LFS_SCRIPT_PATH="/usr/local/share/pull-git-lfs-artifacts.sh"
|
||||||
|
|
||||||
|
tee "$PULL_GIT_LFS_SCRIPT_PATH" > /dev/null \
|
||||||
|
<< EOF
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
AUTO_PULL=${AUTO_PULL}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
tee -a "$PULL_GIT_LFS_SCRIPT_PATH" > /dev/null \
|
||||||
|
<< 'EOF'
|
||||||
|
|
||||||
|
echo "Fetching git lfs artifacts..."
|
||||||
|
|
||||||
|
if [ "${AUTO_PULL}" != "true" ]; then
|
||||||
|
echo "(!) Skipping 'git lfs pull' because 'autoPull' is not set to 'true'"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if repo is a git lfs repo.
|
||||||
|
if ! git lfs ls-files > /dev/null 2>&1; then
|
||||||
|
echo "(!) Skipping automatic 'git lfs pull' because no git lfs files were detected"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
git lfs pull
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 755 "$PULL_GIT_LFS_SCRIPT_PATH"
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
7
src/git/NOTES.md
Normal file
7
src/git/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Install an up-to-date version of Git, built from source as needed. Useful for wh
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/git:1": {
|
"ghcr.io/devcontainers/features/git:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -22,6 +20,13 @@ Install an up-to-date version of Git, built from source as needed. Useful for wh
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/git/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/git/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "git",
|
"id": "git",
|
||||||
"version": "1.0.0",
|
"version": "1.1.6",
|
||||||
"name": "Git (from source)",
|
"name": "Git (from source)",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/git",
|
||||||
"description": "Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.",
|
"description": "Install an up-to-date version of Git, built from source as needed. Useful for when you want the latest and greatest features. Auto-detects latest stable version and installs needed dependencies.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -18,5 +19,8 @@
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Install from PPA if available"
|
"description": "Install from PPA if available"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,48 +7,35 @@
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/git-from-src.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/git-from-src.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
GIT_VERSION=${VERSION:-"latest"} # 'system' checks the base image first, else installs 'latest'
|
GIT_VERSION=${VERSION} # 'system' checks the base image first, else installs 'latest'
|
||||||
USE_PPA_IF_AVAILABLE=${PPA:-"false"}
|
USE_PPA_IF_AVAILABLE=${PPA}
|
||||||
|
|
||||||
GIT_CORE_PPA_ARCHIVE_GPG_KEY=E1DD270288B4E6030699E45FA1715D88E1DF1F24
|
GIT_CORE_PPA_ARCHIVE_GPG_KEY=E1DD270288B4E6030699E45FA1715D88E1DF1F24
|
||||||
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
|
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com
|
||||||
|
keyserver hkp://keyserver.ubuntu.com:80
|
||||||
keyserver hkps://keys.openpgp.org
|
keyserver hkps://keys.openpgp.org
|
||||||
keyserver hkp://keyserver.pgp.com"
|
keyserver hkp://keyserver.pgp.com"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Import the specified key in a variable name passed in as
|
# Import the specified key in a variable name passed in as
|
||||||
receive_gpg_keys() {
|
receive_gpg_keys() {
|
||||||
get_common_setting $1
|
|
||||||
local keys=${!1}
|
local keys=${!1}
|
||||||
get_common_setting GPG_KEY_SERVERS true
|
|
||||||
local keyring_args=""
|
local keyring_args=""
|
||||||
if [ ! -z "$2" ]; then
|
if [ ! -z "$2" ]; then
|
||||||
mkdir -p "$(dirname \"$2\")"
|
mkdir -p "$(dirname \"$2\")"
|
||||||
keyring_args="--no-default-keyring --keyring $2"
|
keyring_args="--no-default-keyring --keyring $2"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use a temporary locaiton for gpg keys to avoid polluting image
|
# Use a temporary location for gpg keys to avoid polluting image
|
||||||
export GNUPGHOME="/tmp/tmp-gnupg"
|
export GNUPGHOME="/tmp/tmp-gnupg"
|
||||||
mkdir -p ${GNUPGHOME}
|
mkdir -p ${GNUPGHOME}
|
||||||
chmod 700 ${GNUPGHOME}
|
chmod 700 ${GNUPGHOME}
|
||||||
|
@ -74,21 +61,18 @@ receive_gpg_keys() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
apt_get_update()
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -102,11 +86,15 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
if [ ${GIT_VERSION} = "os-provided" ] || [ ${GIT_VERSION} = "system" ]; then
|
if [ ${GIT_VERSION} = "os-provided" ] || [ ${GIT_VERSION} = "system" ]; then
|
||||||
if type git > /dev/null 2>&1; then
|
if type git > /dev/null 2>&1; then
|
||||||
echo "Detected existing system install: $(git version)"
|
echo "Detected existing system install: $(git version)"
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing git from OS apt repository"
|
echo "Installing git from OS apt repository"
|
||||||
check_packages git
|
check_packages git
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -119,6 +107,7 @@ if ([ "${GIT_VERSION}" = "latest" ] || [ "${GIT_VERSION}" = "lts" ] || [ "${GIT_
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y install --no-install-recommends git
|
apt-get -y install --no-install-recommends git
|
||||||
rm -rf "/tmp/tmp-gnupg"
|
rm -rf "/tmp/tmp-gnupg"
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -142,10 +131,21 @@ if [ "$(echo "${GIT_VERSION}" | grep -o '\.' | wc -l)" != "2" ]; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
check_packages libpcre2-dev
|
||||||
|
|
||||||
|
if [ "${VERSION_CODENAME}" = "focal" ] || [ "${VERSION_CODENAME}" = "bullseye" ]; then
|
||||||
|
check_packages libpcre2-posix2
|
||||||
|
elif [ "${VERSION_CODENAME}" = "bionic" ] || [ "${VERSION_CODENAME}" = "buster" ]; then
|
||||||
|
check_packages libpcre2-posix0
|
||||||
|
else
|
||||||
|
check_packages libpcre2-posix3
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Downloading source for ${GIT_VERSION}..."
|
echo "Downloading source for ${GIT_VERSION}..."
|
||||||
curl -sL https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz | tar -xzC /tmp 2>&1
|
curl -sL https://github.com/git/git/archive/v${GIT_VERSION}.tar.gz | tar -xzC /tmp 2>&1
|
||||||
echo "Building..."
|
echo "Building..."
|
||||||
cd /tmp/git-${GIT_VERSION}
|
cd /tmp/git-${GIT_VERSION}
|
||||||
make -s prefix=/usr/local all && make -s prefix=/usr/local install 2>&1
|
make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc all && make -s USE_LIBPCRE=YesPlease prefix=/usr/local sysconfdir=/etc install 2>&1
|
||||||
rm -rf /tmp/git-${GIT_VERSION}
|
rm -rf /tmp/git-${GIT_VERSION}
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
7
src/github-cli/NOTES.md
Normal file
7
src/github-cli/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Installs the GitHub CLI. Auto-detects latest version and installs needed depende
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/github-cli:1": {
|
"ghcr.io/devcontainers/features/github-cli:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,9 +16,17 @@ Installs the GitHub CLI. Auto-detects latest version and installs needed depende
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select version of the GitHub CLI, if not latest. | string | latest |
|
| version | Select version of the GitHub CLI, if not latest. | string | latest |
|
||||||
|
| installDirectlyFromGitHubRelease | - | boolean | true |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/github-cli/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/github-cli/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "github-cli",
|
"id": "github-cli",
|
||||||
"version": "1.0.0",
|
"version": "1.0.11",
|
||||||
"name": "GitHub CLI",
|
"name": "GitHub CLI",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/github-cli",
|
||||||
"description": "Installs the GitHub CLI. Auto-detects latest version and installs needed dependencies.",
|
"description": "Installs the GitHub CLI. Auto-detects latest version and installs needed dependencies.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -12,6 +13,15 @@
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select version of the GitHub CLI, if not latest."
|
"description": "Select version of the GitHub CLI, if not latest."
|
||||||
|
},
|
||||||
|
"installDirectlyFromGitHubRelease": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils",
|
||||||
|
"ghcr.io/devcontainers/features/git"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,41 +8,34 @@
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
CLI_VERSION=${VERSION:-"latest"}
|
CLI_VERSION=${VERSION:-"latest"}
|
||||||
|
INSTALL_DIRECTLY_FROM_GITHUB_RELEASE=${INSTALLDIRECTLYFROMGITHUBRELEASE:-"true"}
|
||||||
|
|
||||||
GITHUB_CLI_ARCHIVE_GPG_KEY=C99B11DEB97541F0
|
GITHUB_CLI_ARCHIVE_GPG_KEY=23F3D4EA75716059
|
||||||
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
|
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com
|
||||||
|
keyserver hkp://keyserver.ubuntu.com:80
|
||||||
keyserver hkps://keys.openpgp.org
|
keyserver hkps://keys.openpgp.org
|
||||||
keyserver hkp://keyserver.pgp.com"
|
keyserver hkp://keyserver.pgp.com"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get central common setting
|
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Import the specified key in a variable name passed in as
|
# Import the specified key in a variable name passed in as
|
||||||
receive_gpg_keys() {
|
receive_gpg_keys() {
|
||||||
get_common_setting $1
|
|
||||||
local keys=${!1}
|
local keys=${!1}
|
||||||
get_common_setting GPG_KEY_SERVERS true
|
local keyring_args=""
|
||||||
|
if [ ! -z "$2" ]; then
|
||||||
|
keyring_args="--no-default-keyring --keyring $2"
|
||||||
|
fi
|
||||||
|
|
||||||
# Use a temporary locaiton for gpg keys to avoid polluting image
|
# Use a temporary location for gpg keys to avoid polluting image
|
||||||
export GNUPGHOME="/tmp/tmp-gnupg"
|
export GNUPGHOME="/tmp/tmp-gnupg"
|
||||||
mkdir -p ${GNUPGHOME}
|
mkdir -p ${GNUPGHOME}
|
||||||
chmod 700 ${GNUPGHOME}
|
chmod 700 ${GNUPGHOME}
|
||||||
|
@ -54,7 +47,7 @@ receive_gpg_keys() {
|
||||||
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
|
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
|
||||||
do
|
do
|
||||||
echo "(*) Downloading GPG key..."
|
echo "(*) Downloading GPG key..."
|
||||||
( echo "${keys}" | xargs -n 1 gpg --recv-keys) 2>&1 && gpg_ok="true"
|
( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true"
|
||||||
if [ "${gpg_ok}" != "true" ]; then
|
if [ "${gpg_ok}" != "true" ]; then
|
||||||
echo "(*) Failed getting key, retring in 10s..."
|
echo "(*) Failed getting key, retring in 10s..."
|
||||||
(( retry_count++ ))
|
(( retry_count++ ))
|
||||||
|
@ -68,6 +61,22 @@ receive_gpg_keys() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apt_get_update()
|
||||||
|
{
|
||||||
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
|
echo "Running apt-get update..."
|
||||||
|
apt-get update -y
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks if packages are installed and installs them if not
|
||||||
|
check_packages() {
|
||||||
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
|
apt_get_update
|
||||||
|
apt-get -y install --no-install-recommends "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Figure out correct version of a three part version number is not passed
|
# Figure out correct version of a three part version number is not passed
|
||||||
find_version_from_git_tags() {
|
find_version_from_git_tags() {
|
||||||
local variable_name=$1
|
local variable_name=$1
|
||||||
|
@ -102,59 +111,71 @@ find_version_from_git_tags() {
|
||||||
echo "${variable_name}=${!variable_name}"
|
echo "${variable_name}=${!variable_name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Import the specified key in a variable name passed in as
|
# Use semver logic to decrement a version number then look for the closest match
|
||||||
receive_gpg_keys() {
|
find_prev_version_from_git_tags() {
|
||||||
get_common_setting $1
|
local variable_name=$1
|
||||||
local keys=${!1}
|
local current_version=${!variable_name}
|
||||||
get_common_setting GPG_KEY_SERVERS true
|
local repository=$2
|
||||||
local keyring_args=""
|
# Normally a "v" is used before the version number, but support alternate cases
|
||||||
if [ ! -z "$2" ]; then
|
local prefix=${3:-"tags/v"}
|
||||||
keyring_args="--no-default-keyring --keyring $2"
|
# Some repositories use "_" instead of "." for version number part separation, support that
|
||||||
fi
|
local separator=${4:-"."}
|
||||||
|
# Some tools release versions that omit the last digit (e.g. go)
|
||||||
# Use a temporary locaiton for gpg keys to avoid polluting image
|
local last_part_optional=${5:-"false"}
|
||||||
export GNUPGHOME="/tmp/tmp-gnupg"
|
# Some repositories may have tags that include a suffix (e.g. actions/node-versions)
|
||||||
mkdir -p ${GNUPGHOME}
|
local version_suffix_regex=$6
|
||||||
chmod 700 ${GNUPGHOME}
|
# Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios.
|
||||||
echo -e "disable-ipv6\n${GPG_KEY_SERVERS}" > ${GNUPGHOME}/dirmngr.conf
|
|
||||||
# GPG key download sometimes fails for some reason and retrying fixes it.
|
|
||||||
local retry_count=0
|
|
||||||
local gpg_ok="false"
|
|
||||||
set +e
|
set +e
|
||||||
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
|
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
|
||||||
do
|
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
|
||||||
echo "(*) Downloading GPG key..."
|
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
|
||||||
( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true"
|
|
||||||
if [ "${gpg_ok}" != "true" ]; then
|
|
||||||
echo "(*) Failed getting key, retring in 10s..."
|
|
||||||
(( retry_count++ ))
|
|
||||||
sleep 10s
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
set -e
|
|
||||||
if [ "${gpg_ok}" = "false" ]; then
|
|
||||||
echo "(!) Failed to get gpg key."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
|
||||||
apt_get_update_if_needed()
|
((major=major-1))
|
||||||
{
|
declare -g ${variable_name}="${major}"
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
# Look for latest version from previous major release
|
||||||
echo "Running apt-get update..."
|
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
|
||||||
apt-get update
|
# Handle situations like Go's odd version pattern where "0" releases omit the last part
|
||||||
|
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
|
||||||
|
((minor=minor-1))
|
||||||
|
declare -g ${variable_name}="${major}.${minor}"
|
||||||
|
# Look for latest version from previous minor release
|
||||||
|
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
|
||||||
else
|
else
|
||||||
echo "Skipping apt-get update."
|
((breakfix=breakfix-1))
|
||||||
|
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
|
||||||
|
declare -g ${variable_name}="${major}.${minor}"
|
||||||
|
else
|
||||||
|
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Fall back on direct download if no apt package exists
|
||||||
check_packages() {
|
# Fetches .deb file to be installed with dpkg
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
install_deb_using_github() {
|
||||||
apt_get_update_if_needed
|
check_packages wget
|
||||||
apt-get -y install --no-install-recommends "$@"
|
arch=$(dpkg --print-architecture)
|
||||||
|
|
||||||
|
find_version_from_git_tags CLI_VERSION https://github.com/cli/cli
|
||||||
|
cli_filename="gh_${CLI_VERSION}_linux_${arch}.deb"
|
||||||
|
|
||||||
|
mkdir -p /tmp/ghcli
|
||||||
|
pushd /tmp/ghcli
|
||||||
|
wget https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename}
|
||||||
|
exit_code=$?
|
||||||
|
set -e
|
||||||
|
if [ "$exit_code" != "0" ]; then
|
||||||
|
# Handle situation where git tags are ahead of what was is available to actually download
|
||||||
|
echo "(!) github-cli version ${CLI_VERSION} failed to download. Attempting to fall back one version to retry..."
|
||||||
|
find_prev_version_from_git_tags CLI_VERSION https://github.com/cli/cli
|
||||||
|
wget https://github.com/cli/cli/releases/download/v${CLI_VERSION}/${cli_filename}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
dpkg -i /tmp/ghcli/${cli_filename}
|
||||||
|
popd
|
||||||
|
rm -rf /tmp/ghcli
|
||||||
}
|
}
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
@ -162,8 +183,7 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
# Install curl, apt-transport-https, curl, gpg, or dirmngr, git if missing
|
# Install curl, apt-transport-https, curl, gpg, or dirmngr, git if missing
|
||||||
check_packages curl ca-certificates apt-transport-https dirmngr gnupg2
|
check_packages curl ca-certificates apt-transport-https dirmngr gnupg2
|
||||||
if ! type git > /dev/null 2>&1; then
|
if ! type git > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
check_packages git
|
||||||
apt-get -y install --no-install-recommends git
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Soft version matching
|
# Soft version matching
|
||||||
|
@ -176,11 +196,19 @@ fi
|
||||||
|
|
||||||
# Install the GitHub CLI
|
# Install the GitHub CLI
|
||||||
echo "Downloading github CLI..."
|
echo "Downloading github CLI..."
|
||||||
# Import key safely (new method rather than deprecated apt-key approach) and install
|
|
||||||
. /etc/os-release
|
if [ "${INSTALL_DIRECTLY_FROM_GITHUB_RELEASE}" = "true" ]; then
|
||||||
receive_gpg_keys GITHUB_CLI_ARCHIVE_GPG_KEY /usr/share/keyrings/githubcli-archive-keyring.gpg
|
install_deb_using_github
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
|
else
|
||||||
apt-get update
|
# Import key safely (new method rather than deprecated apt-key approach) and install
|
||||||
apt-get -y install "gh${version_suffix}"
|
. /etc/os-release
|
||||||
rm -rf "/tmp/gh/gnupg"
|
receive_gpg_keys GITHUB_CLI_ARCHIVE_GPG_KEY /usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||||
echo "Done!"
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
|
||||||
|
apt-get update
|
||||||
|
apt-get -y install "gh${version_suffix}"
|
||||||
|
rm -rf "/tmp/gh/gnupg"
|
||||||
|
echo "Done!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
7
src/go/NOTES.md
Normal file
7
src/go/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@ Installs Go and common Go utilities. Auto-detects latest version and installs ne
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/go:1": {
|
"ghcr.io/devcontainers/features/go:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,7 +16,21 @@ Installs Go and common Go utilities. Auto-detects latest version and installs ne
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter a Go version to install | string | latest |
|
| version | Select or enter a Go version to install | string | latest |
|
||||||
|
| golangciLintVersion | Version of golangci-lint to install | string | latest |
|
||||||
|
|
||||||
|
## Customizations
|
||||||
|
|
||||||
|
### VS Code Extensions
|
||||||
|
|
||||||
|
- `golang.Go`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "go",
|
"id": "go",
|
||||||
"version": "1.0.0",
|
"version": "1.2.2",
|
||||||
"name": "Go",
|
"name": "Go",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/go",
|
||||||
"description": "Installs Go and common Go utilities. Auto-detects latest version and installs needed dependencies.",
|
"description": "Installs Go and common Go utilities. Auto-detects latest version and installs needed dependencies.",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
|
@ -9,25 +10,38 @@
|
||||||
"proposals": [
|
"proposals": [
|
||||||
"latest",
|
"latest",
|
||||||
"none",
|
"none",
|
||||||
"1.19",
|
"1.21",
|
||||||
"1.18"
|
"1.20"
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select or enter a Go version to install"
|
"description": "Select or enter a Go version to install"
|
||||||
|
},
|
||||||
|
"golangciLintVersion": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "latest",
|
||||||
|
"description": "Version of golangci-lint to install"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"init": true,
|
"init": true,
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"golang.Go"
|
"golang.Go"
|
||||||
],
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"GOPATH": "/usr/local/go",
|
"GOROOT": "/usr/local/go",
|
||||||
"PATH": "${GOPATH}/bin:${PATH}"
|
"GOPATH": "/go",
|
||||||
|
"PATH": "/usr/local/go/bin:/go/bin:${PATH}"
|
||||||
},
|
},
|
||||||
"capAdd": [
|
"capAdd": [
|
||||||
"SYS_PTRACE"
|
"SYS_PTRACE"
|
||||||
],
|
],
|
||||||
"securityOpt": [
|
"securityOpt": [
|
||||||
"seccomp=unconfined"
|
"seccomp=unconfined"
|
||||||
|
],
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,22 @@
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/go.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/go.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
TARGET_GO_VERSION=${VERSION:-"latest"}
|
TARGET_GO_VERSION="${VERSION:-"latest"}"
|
||||||
|
GOLANGCILINT_VERSION="${GOLANGCILINTVERSION:-"latest"}"
|
||||||
|
|
||||||
TARGET_GOROOT=${TARGET_GOROOT:-"/usr/local/go"}
|
TARGET_GOROOT="${TARGET_GOROOT:-"/usr/local/go"}"
|
||||||
TARGET_GOPATH=${TARGET_GOPATH:-"/go"}
|
TARGET_GOPATH="${TARGET_GOPATH:-"/go"}"
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
UPDATE_RC=${UPDATE_RC:-"true"}
|
INSTALL_GO_TOOLS="${INSTALL_GO_TOOLS:-"true"}"
|
||||||
INSTALL_GO_TOOLS=${INSTALL_GO_TOOLS:-"true"}
|
|
||||||
|
|
||||||
# https://www.google.com/linuxrepositories/
|
# https://www.google.com/linuxrepositories/
|
||||||
GO_GPG_KEY_URI="https://dl.google.com/linux/linux_signing_key.pub"
|
GO_GPG_KEY_URI="https://dl.google.com/linux/linux_signing_key.pub"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -47,17 +50,6 @@ elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
|
||||||
USERNAME=root
|
USERNAME=root
|
||||||
fi
|
fi
|
||||||
|
|
||||||
updaterc() {
|
|
||||||
if [ "${UPDATE_RC}" = "true" ]; then
|
|
||||||
echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
|
|
||||||
if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then
|
|
||||||
echo -e "$1" >> /etc/bash.bashrc
|
|
||||||
fi
|
|
||||||
if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then
|
|
||||||
echo -e "$1" >> /etc/zsh/zshrc
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# Figure out correct version of a three part version number is not passed
|
# Figure out correct version of a three part version number is not passed
|
||||||
find_version_from_git_tags() {
|
find_version_from_git_tags() {
|
||||||
local variable_name=$1
|
local variable_name=$1
|
||||||
|
@ -92,36 +84,18 @@ find_version_from_git_tags() {
|
||||||
echo "${variable_name}=${!variable_name}"
|
echo "${variable_name}=${!variable_name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get central common setting
|
apt_get_update()
|
||||||
get_common_setting() {
|
|
||||||
if [ "${common_settings_file_loaded}" != "true" ]; then
|
|
||||||
curl -sfL "https://aka.ms/vscode-dev-containers/script-library/settings.env" 2>/dev/null -o /tmp/vsdc-settings.env || echo "Could not download settings file. Skipping."
|
|
||||||
common_settings_file_loaded=true
|
|
||||||
fi
|
|
||||||
if [ -f "/tmp/vsdc-settings.env" ]; then
|
|
||||||
local multi_line=""
|
|
||||||
if [ "$2" = "true" ]; then multi_line="-z"; fi
|
|
||||||
local result="$(grep ${multi_line} -oP "$1=\"?\K[^\"]+" /tmp/vsdc-settings.env | tr -d '\0')"
|
|
||||||
if [ ! -z "${result}" ]; then declare -g $1="${result}"; fi
|
|
||||||
fi
|
|
||||||
echo "$1=${!1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -131,8 +105,7 @@ export DEBIAN_FRONTEND=noninteractive
|
||||||
# Install curl, tar, git, other dependencies if missing
|
# Install curl, tar, git, other dependencies if missing
|
||||||
check_packages curl ca-certificates gnupg2 tar g++ gcc libc6-dev make pkg-config
|
check_packages curl ca-certificates gnupg2 tar g++ gcc libc6-dev make pkg-config
|
||||||
if ! type git > /dev/null 2>&1; then
|
if ! type git > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
check_packages git
|
||||||
apt-get -y install --no-install-recommends git
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get closest match for version number specified
|
# Get closest match for version number specified
|
||||||
|
@ -154,12 +127,12 @@ if ! cat /etc/group | grep -e "^golang:" > /dev/null 2>&1; then
|
||||||
fi
|
fi
|
||||||
usermod -a -G golang "${USERNAME}"
|
usermod -a -G golang "${USERNAME}"
|
||||||
mkdir -p "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
mkdir -p "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
||||||
if [ "${TARGET_GO_VERSION}" != "none" ] && ! type go > /dev/null 2>&1; then
|
|
||||||
# Use a temporary locaiton for gpg keys to avoid polluting image
|
if [[ "${TARGET_GO_VERSION}" != "none" ]] && [[ "$(go version)" != *"${TARGET_GO_VERSION}"* ]]; then
|
||||||
|
# Use a temporary location for gpg keys to avoid polluting image
|
||||||
export GNUPGHOME="/tmp/tmp-gnupg"
|
export GNUPGHOME="/tmp/tmp-gnupg"
|
||||||
mkdir -p ${GNUPGHOME}
|
mkdir -p ${GNUPGHOME}
|
||||||
chmod 700 ${GNUPGHOME}
|
chmod 700 ${GNUPGHOME}
|
||||||
get_common_setting GO_GPG_KEY_URI
|
|
||||||
curl -sSL -o /tmp/tmp-gnupg/golang_key "${GO_GPG_KEY_URI}"
|
curl -sSL -o /tmp/tmp-gnupg/golang_key "${GO_GPG_KEY_URI}"
|
||||||
gpg -q --import /tmp/tmp-gnupg/golang_key
|
gpg -q --import /tmp/tmp-gnupg/golang_key
|
||||||
echo "Downloading Go ${TARGET_GO_VERSION}..."
|
echo "Downloading Go ${TARGET_GO_VERSION}..."
|
||||||
|
@ -198,20 +171,22 @@ if [ "${TARGET_GO_VERSION}" != "none" ] && ! type go > /dev/null 2>&1; then
|
||||||
tar -xzf /tmp/go.tar.gz -C "${TARGET_GOROOT}" --strip-components=1
|
tar -xzf /tmp/go.tar.gz -C "${TARGET_GOROOT}" --strip-components=1
|
||||||
rm -rf /tmp/go.tar.gz /tmp/go.tar.gz.asc /tmp/tmp-gnupg
|
rm -rf /tmp/go.tar.gz /tmp/go.tar.gz.asc /tmp/tmp-gnupg
|
||||||
else
|
else
|
||||||
echo "Go already installed. Skipping."
|
echo "(!) Go is already installed with version ${TARGET_GO_VERSION}. Skipping."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install Go tools that are isImportant && !replacedByGopls based on
|
# Install Go tools that are isImportant && !replacedByGopls based on
|
||||||
# https://github.com/golang/vscode-go/blob/v0.31.1/src/goToolsInformation.ts
|
# https://github.com/golang/vscode-go/blob/v0.38.0/src/goToolsInformation.ts
|
||||||
GO_TOOLS="\
|
GO_TOOLS="\
|
||||||
golang.org/x/tools/gopls@latest \
|
golang.org/x/tools/gopls@latest \
|
||||||
honnef.co/go/tools/cmd/staticcheck@latest \
|
honnef.co/go/tools/cmd/staticcheck@latest \
|
||||||
golang.org/x/lint/golint@latest \
|
golang.org/x/lint/golint@latest \
|
||||||
github.com/mgechev/revive@latest \
|
github.com/mgechev/revive@latest \
|
||||||
github.com/uudashr/gopkgs/v2/cmd/gopkgs@latest \
|
|
||||||
github.com/ramya-rao-a/go-outline@latest \
|
|
||||||
github.com/go-delve/delve/cmd/dlv@latest \
|
github.com/go-delve/delve/cmd/dlv@latest \
|
||||||
github.com/golangci/golangci-lint/cmd/golangci-lint@latest"
|
github.com/fatih/gomodifytags@latest \
|
||||||
|
github.com/haya14busa/goplay/cmd/goplay@latest \
|
||||||
|
github.com/cweill/gotests/gotests@latest \
|
||||||
|
github.com/josharian/impl@latest"
|
||||||
|
|
||||||
if [ "${INSTALL_GO_TOOLS}" = "true" ]; then
|
if [ "${INSTALL_GO_TOOLS}" = "true" ]; then
|
||||||
echo "Installing common Go tools..."
|
echo "Installing common Go tools..."
|
||||||
export PATH=${TARGET_GOROOT}/bin:${PATH}
|
export PATH=${TARGET_GOROOT}/bin:${PATH}
|
||||||
|
@ -231,24 +206,30 @@ if [ "${INSTALL_GO_TOOLS}" = "true" ]; then
|
||||||
(echo "${GO_TOOLS}" | xargs -n 1 go ${go_install_command} -v )2>&1 | tee -a /usr/local/etc/vscode-dev-containers/go.log
|
(echo "${GO_TOOLS}" | xargs -n 1 go ${go_install_command} -v )2>&1 | tee -a /usr/local/etc/vscode-dev-containers/go.log
|
||||||
|
|
||||||
# Move Go tools into path and clean up
|
# Move Go tools into path and clean up
|
||||||
|
if [ -d /tmp/gotools/bin ]; then
|
||||||
mv /tmp/gotools/bin/* ${TARGET_GOPATH}/bin/
|
mv /tmp/gotools/bin/* ${TARGET_GOPATH}/bin/
|
||||||
|
|
||||||
rm -rf /tmp/gotools
|
rm -rf /tmp/gotools
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Install golangci-lint from precompiled binares
|
||||||
|
if [ "$GOLANGCILINT_VERSION" = "latest" ] || [ "$GOLANGCILINT_VERSION" = "" ]; then
|
||||||
|
echo "Installing golangci-lint latest..."
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
|
||||||
|
sh -s -- -b "${TARGET_GOPATH}/bin"
|
||||||
|
else
|
||||||
|
echo "Installing golangci-lint ${GOLANGCILINT_VERSION}..."
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
|
||||||
|
sh -s -- -b "${TARGET_GOPATH}/bin" "v${GOLANGCILINT_VERSION}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Add GOPATH variable and bin directory into PATH in bashrc/zshrc files (unless disabled)
|
|
||||||
updaterc "$(cat << EOF
|
|
||||||
export GOPATH="${TARGET_GOPATH}"
|
|
||||||
if [[ "\${PATH}" != *"\${GOPATH}/bin"* ]]; then export PATH="\${PATH}:\${GOPATH}/bin"; fi
|
|
||||||
export GOROOT="${TARGET_GOROOT}"
|
|
||||||
if [[ "\${PATH}" != *"\${GOROOT}/bin"* ]]; then export PATH="\${PATH}:\${GOROOT}/bin"; fi
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
chown -R "${USERNAME}:golang" "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
chown -R "${USERNAME}:golang" "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
||||||
chmod -R g+r+w "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
chmod -R g+r+w "${TARGET_GOROOT}" "${TARGET_GOPATH}"
|
||||||
find "${TARGET_GOROOT}" -type d | xargs -n 1 chmod g+s
|
find "${TARGET_GOROOT}" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
find "${TARGET_GOPATH}" -type d | xargs -n 1 chmod g+s
|
find "${TARGET_GOPATH}" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
||||||
|
|
7
src/hugo/NOTES.md
Normal file
7
src/hugo/NOTES.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
|
@ -7,9 +7,7 @@
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/hugo:1": {
|
"ghcr.io/devcontainers/features/hugo:1": {}
|
||||||
"version": "latest"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -18,9 +16,17 @@
|
||||||
| Options Id | Description | Type | Default Value |
|
| Options Id | Description | Type | Default Value |
|
||||||
|-----|-----|-----|-----|
|
|-----|-----|-----|-----|
|
||||||
| version | Select or enter a version. | string | latest |
|
| version | Select or enter a version. | string | latest |
|
||||||
|
| extended | Install Hugo extended for SASS/SCSS changes | boolean | false |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/hugo/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/hugo/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"id": "hugo",
|
"id": "hugo",
|
||||||
"version": "1.0.0",
|
"version": "1.1.2",
|
||||||
"name": "Hugo",
|
"name": "Hugo",
|
||||||
|
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/hugo",
|
||||||
"options": {
|
"options": {
|
||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
@ -10,10 +11,18 @@
|
||||||
],
|
],
|
||||||
"default": "latest",
|
"default": "latest",
|
||||||
"description": "Select or enter a version."
|
"description": "Select or enter a version."
|
||||||
|
},
|
||||||
|
"extended": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Install Hugo extended for SASS/SCSS changes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"HUGO_DIR": "/usr/local/hugo",
|
"HUGO_DIR": "/usr/local/hugo",
|
||||||
"PATH": "${HUGO_DIR}/bin:${PATH}"
|
"PATH": "/usr/local/hugo/bin:${PATH}"
|
||||||
}
|
},
|
||||||
|
"installsAfter": [
|
||||||
|
"ghcr.io/devcontainers/features/common-utils"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,18 @@
|
||||||
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/hugo.md
|
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/hugo.md
|
||||||
# Maintainer: The VS Code and Codespaces Teams
|
# Maintainer: The VS Code and Codespaces Teams
|
||||||
|
|
||||||
VERSION=${VERSION:-"latest"}
|
VERSION="${VERSION:-"latest"}"
|
||||||
|
|
||||||
USERNAME=${USERNAME:-"automatic"}
|
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
|
||||||
UPDATE_RC=${UPDATE_RC:-"true"}
|
UPDATE_RC="${UPDATE_RC:-"true"}"
|
||||||
|
|
||||||
HUGO_DIR=${HUGO_DIR:-"/usr/local/hugo"}
|
HUGO_DIR="${HUGO_DIR:-"/usr/local/hugo"}"
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -61,21 +64,18 @@ updaterc() {
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to run apt-get if needed
|
apt_get_update()
|
||||||
apt_get_update_if_needed()
|
|
||||||
{
|
{
|
||||||
if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then
|
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
|
||||||
echo "Running apt-get update..."
|
echo "Running apt-get update..."
|
||||||
apt-get update
|
apt-get update -y
|
||||||
else
|
|
||||||
echo "Skipping apt-get update."
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks if packages are installed and installs them if not
|
# Checks if packages are installed and installs them if not
|
||||||
check_packages() {
|
check_packages() {
|
||||||
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
if ! dpkg -s "$@" > /dev/null 2>&1; then
|
||||||
apt_get_update_if_needed
|
apt_get_update
|
||||||
apt-get -y install --no-install-recommends "$@"
|
apt-get -y install --no-install-recommends "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,14 @@ if ! hugo version &> /dev/null ; then
|
||||||
arch="64bit"
|
arch="64bit"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
hugo_filename="hugo_${VERSION}_Linux-${arch}.tar.gz"
|
# Install extended version of hugo if desired
|
||||||
|
if [ "${EXTENDED}" = "true" ]; then
|
||||||
|
extended="extended_"
|
||||||
|
else
|
||||||
|
extended=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
hugo_filename="hugo_${extended}${VERSION}_Linux-${arch}.tar.gz"
|
||||||
|
|
||||||
curl -fsSLO --compressed "https://github.com/gohugoio/hugo/releases/download/v${VERSION}/${hugo_filename}"
|
curl -fsSLO --compressed "https://github.com/gohugoio/hugo/releases/download/v${VERSION}/${hugo_filename}"
|
||||||
tar -xzf "$hugo_filename" -C "$installation_dir"
|
tar -xzf "$hugo_filename" -C "$installation_dir"
|
||||||
|
@ -116,7 +123,10 @@ if ! hugo version &> /dev/null ; then
|
||||||
|
|
||||||
chown -R "${USERNAME}:hugo" "${HUGO_DIR}"
|
chown -R "${USERNAME}:hugo" "${HUGO_DIR}"
|
||||||
chmod -R g+r+w "${HUGO_DIR}"
|
chmod -R g+r+w "${HUGO_DIR}"
|
||||||
find "${HUGO_DIR}" -type d | xargs -n 1 chmod g+s
|
find "${HUGO_DIR}" -type d -print0 | xargs -n 1 -0 chmod g+s
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
echo "Done!"
|
echo "Done!"
|
||||||
|
|
10
src/java/NOTES.md
Normal file
10
src/java/NOTES.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
## License
|
||||||
|
|
||||||
|
For the Java Feature from this repository, see [NOTICE.txt](https://github.com/devcontainers/features/tree/main/src/java/NOTICE.txt) for licensing information on JDK distributions.
|
||||||
|
|
||||||
|
|
||||||
|
## OS Support
|
||||||
|
|
||||||
|
This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed.
|
||||||
|
|
||||||
|
`bash` is required to execute the `install.sh` script.
|
4405
src/java/NOTICE.txt
Normal file
4405
src/java/NOTICE.txt
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue