mirror of
https://github.com/coder/code-server.git
synced 2026-04-14 06:24:32 -05:00
Compare commits
480 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f64599b94d | ||
|
|
9917da068a | ||
|
|
8bf1bf2c9f | ||
|
|
79e8f3dfdb | ||
|
|
a37572d92d | ||
|
|
40a7c11ce3 | ||
|
|
7afa689285 | ||
|
|
f4d48bc880 | ||
|
|
9af3671c05 | ||
|
|
248c2adb2e | ||
|
|
52ea32f4a7 | ||
|
|
affa64c89c | ||
|
|
5e603056fd | ||
|
|
9889f30224 | ||
|
|
96995b78d1 | ||
|
|
6f14b8b8dd | ||
|
|
b73ea2fea2 | ||
|
|
e1702a1d21 | ||
|
|
5499a3d125 | ||
|
|
31b67062b0 | ||
|
|
72931edcf0 | ||
|
|
79478eb89f | ||
|
|
4574593664 | ||
|
|
71850e312b | ||
|
|
b8340a2ae9 | ||
|
|
f706039a9d | ||
|
|
de4949571c | ||
|
|
0a01338edd | ||
|
|
aa7415a479 | ||
|
|
10799aa1ec | ||
|
|
0e39bb9f2c | ||
|
|
03aa7709ca | ||
|
|
77c2a72cf8 | ||
|
|
f3d7d3f616 | ||
|
|
da6000b96f | ||
|
|
d969a5bd6b | ||
|
|
fe399ff0fe | ||
|
|
277211c4ce | ||
|
|
9d39c53c99 | ||
|
|
197a09f0c1 | ||
|
|
9453f891df | ||
|
|
14f408a837 | ||
|
|
8a8159c683 | ||
|
|
706bc23f04 | ||
|
|
af73b96313 | ||
|
|
2a13d003d3 | ||
|
|
687094802e | ||
|
|
139a28e0ea | ||
|
|
e03bbe3149 | ||
|
|
afff86ae9c | ||
|
|
fed545e67d | ||
|
|
6638daf6f0 | ||
|
|
8d3a7721fe | ||
|
|
75e52a3774 | ||
|
|
f4d7f00033 | ||
|
|
ef971009d9 | ||
|
|
30d2962e21 | ||
|
|
82e8a00a0d | ||
|
|
bea185b8b2 | ||
|
|
e08a55d44a | ||
|
|
481df70622 | ||
|
|
aa2cfa2c17 | ||
|
|
959497067c | ||
|
|
f7076247f9 | ||
|
|
f6c4434191 | ||
|
|
cb991a9143 | ||
|
|
3f1750cf83 | ||
|
|
7b2752a62c | ||
|
|
9e09c1f92b | ||
|
|
8252c372af | ||
|
|
396af23842 | ||
|
|
34225e2bdf | ||
|
|
476379a77e | ||
|
|
210fc049c4 | ||
|
|
e5c8e0aad1 | ||
|
|
c5ce365482 | ||
|
|
a653b93ce2 | ||
|
|
e2c35facdb | ||
|
|
75b93f9dc5 | ||
|
|
1eebde56ab | ||
|
|
e27188c2f9 | ||
|
|
ddbac8dd78 | ||
|
|
8066da12fe | ||
|
|
03e0013112 | ||
|
|
e243f6e369 | ||
|
|
c10450c4c5 | ||
|
|
c72c53f64d | ||
|
|
f4e5855318 | ||
|
|
3a074fd844 | ||
|
|
8a9e61defb | ||
|
|
1067507c41 | ||
|
|
f9e0990594 | ||
|
|
c07296cce0 | ||
|
|
31306f7fdd | ||
|
|
7affce5801 | ||
|
|
37b87dd2b8 | ||
|
|
9bde62fbd6 | ||
|
|
6fbbb1047f | ||
|
|
e07a591745 | ||
|
|
676c7bf915 | ||
|
|
9ad7d0b7a3 | ||
|
|
07e7c38ea2 | ||
|
|
0b9af6ef67 | ||
|
|
c63dc3a1ea | ||
|
|
a1b61d1659 | ||
|
|
bae28727bd | ||
|
|
8b85006996 | ||
|
|
10b3028196 | ||
|
|
860c99e3b8 | ||
|
|
f2f1fee6f1 | ||
|
|
504d89638b | ||
|
|
dc177ab505 | ||
|
|
cde94d5ed4 | ||
|
|
305348f0ac | ||
|
|
6ab6cb4f07 | ||
|
|
6422a8d74b | ||
|
|
257d9a4fa4 | ||
|
|
112eda4605 | ||
|
|
4b6cbacbad | ||
|
|
71dc5c7542 | ||
|
|
7e1e9d1249 | ||
|
|
62735da694 | ||
|
|
6cc1ee1b00 | ||
|
|
79443c14ff | ||
|
|
a0b7bf2180 | ||
|
|
30f3030530 | ||
|
|
759a78d9d8 | ||
|
|
7093f99a78 | ||
|
|
bca1bcfc03 | ||
|
|
4a3d2e5a94 | ||
|
|
14287df655 | ||
|
|
8e93e28162 | ||
|
|
9f25cc6d5d | ||
|
|
6000e389bc | ||
|
|
2928d362fa | ||
|
|
dcb303a437 | ||
|
|
daf204eeda | ||
|
|
f20f7ac166 | ||
|
|
a7c43a8eb6 | ||
|
|
30d05aeb4b | ||
|
|
07580e1fcb | ||
|
|
e3699cf258 | ||
|
|
2a22676d93 | ||
|
|
36b3183b75 | ||
|
|
d7cba30c6a | ||
|
|
30fafc8937 | ||
|
|
ec564091f1 | ||
|
|
83465a2f4f | ||
|
|
b4fd47b5af | ||
|
|
3570ff796d | ||
|
|
fd241d555b | ||
|
|
d323f4f75b | ||
|
|
40b1efa142 | ||
|
|
ea105a9290 | ||
|
|
e453d3107d | ||
|
|
a4a03c1492 | ||
|
|
d7ba9ae633 | ||
|
|
00383b79b9 | ||
|
|
c6ba12942c | ||
|
|
d7e3112625 | ||
|
|
26c735b434 | ||
|
|
466a04f874 | ||
|
|
e0769dc13a | ||
|
|
fe19391c03 | ||
|
|
021c084e43 | ||
|
|
1902296702 | ||
|
|
bb1bf88439 | ||
|
|
0a8e71c647 | ||
|
|
6bdaada689 | ||
|
|
811cf3364a | ||
|
|
64a6a460c8 | ||
|
|
1e4e72aa5b | ||
|
|
fcfb03382a | ||
|
|
d67bd3f604 | ||
|
|
2d1de749f4 | ||
|
|
c6c293d53a | ||
|
|
daa1c86fe0 | ||
|
|
9002f118c3 | ||
|
|
a5b6d080bd | ||
|
|
9ff37977a8 | ||
|
|
f5489cd3a0 | ||
|
|
c86d7398ab | ||
|
|
9f963c7e66 | ||
|
|
8063c79e44 | ||
|
|
febf4ead96 | ||
|
|
3e28ab85a0 | ||
|
|
85b0804be5 | ||
|
|
ebbcb8d6a7 | ||
|
|
df3089f3ad | ||
|
|
7cc16ceb3a | ||
|
|
bfe731f4f3 | ||
|
|
c4f1c053bf | ||
|
|
4b3c089630 | ||
|
|
1c16814a89 | ||
|
|
c3c24fe4d2 | ||
|
|
6e8248cf0c | ||
|
|
dd996d8f60 | ||
|
|
fae07e14fb | ||
|
|
c308ae0edd | ||
|
|
9035bfa871 | ||
|
|
22c4a7e10f | ||
|
|
607444c695 | ||
|
|
b22f3cb72f | ||
|
|
eacca7d692 | ||
|
|
0aa98279d6 | ||
|
|
55a7e8b56f | ||
|
|
916e24e109 | ||
|
|
c7c62daa67 | ||
|
|
579bb94a6c | ||
|
|
a44b4455f5 | ||
|
|
548a35c0ee | ||
|
|
402f5ebd77 | ||
|
|
c2ac126a50 | ||
|
|
b3811a67e0 | ||
|
|
ddda280df4 | ||
|
|
b415b7524f | ||
|
|
7a982555a8 | ||
|
|
e64b186527 | ||
|
|
11eaf0b470 | ||
|
|
8b5deac92b | ||
|
|
9d87c5328c | ||
|
|
cc5ed1eb57 | ||
|
|
e998dc1e82 | ||
|
|
ffe6a663aa | ||
|
|
938b460685 | ||
|
|
fef619aef8 | ||
|
|
0a2328c1f6 | ||
|
|
e44e574ce1 | ||
|
|
7991e09bbc | ||
|
|
9fb318cf15 | ||
|
|
4a250be79a | ||
|
|
3761f7bd51 | ||
|
|
ceceef1dae | ||
|
|
e858d11279 | ||
|
|
35a2d71b67 | ||
|
|
96a78c98d1 | ||
|
|
70b73d7cb9 | ||
|
|
8fe7986d0d | ||
|
|
559d05bb7b | ||
|
|
341cb342b2 | ||
|
|
34f8c77a03 | ||
|
|
d33df75662 | ||
|
|
85d5858b1d | ||
|
|
1b6ddb66f0 | ||
|
|
617cd38c71 | ||
|
|
75c8fdeed2 | ||
|
|
de41646fc4 | ||
|
|
882a2bfd5a | ||
|
|
b509063e14 | ||
|
|
1a82b2138d | ||
|
|
ada69969ac | ||
|
|
3f508e5e12 | ||
|
|
ce8577b1c3 | ||
|
|
d8d5908d85 | ||
|
|
1558ff6dac | ||
|
|
4b7c2ea322 | ||
|
|
4c4a7413a1 | ||
|
|
ceb2265b14 | ||
|
|
221e95ee89 | ||
|
|
255fa37e1d | ||
|
|
864a9e7bd6 | ||
|
|
a839da34d7 | ||
|
|
3912e9e333 | ||
|
|
eebb8bb314 | ||
|
|
ebbb1187da | ||
|
|
c8f63b61c4 | ||
|
|
c80d093dc4 | ||
|
|
6cc91869d3 | ||
|
|
bf09c294cc | ||
|
|
536ccc0f10 | ||
|
|
312a4d584c | ||
|
|
a730bec6f4 | ||
|
|
ce2eaf2f10 | ||
|
|
5c6cd11836 | ||
|
|
6539dd4dbe | ||
|
|
e8ac0d33f9 | ||
|
|
e237589f2e | ||
|
|
98d8d848a5 | ||
|
|
c8ce380f10 | ||
|
|
c6f054ad6f | ||
|
|
74910ffcdf | ||
|
|
3c90b1e327 | ||
|
|
0dcf469725 | ||
|
|
d8568ebaa9 | ||
|
|
f7790c9719 | ||
|
|
150d37868a | ||
|
|
8590f80c31 | ||
|
|
d6d24966be | ||
|
|
751a5ea3ad | ||
|
|
de568d446b | ||
|
|
7d02f34f71 | ||
|
|
2fad8a2a58 | ||
|
|
a0ff2014c3 | ||
|
|
8d03c22cb0 | ||
|
|
6e27869c09 | ||
|
|
934c8d4eb6 | ||
|
|
9b979ac869 | ||
|
|
3badf6bf7b | ||
|
|
10c2b956ac | ||
|
|
543d64268d | ||
|
|
fd36f8c168 | ||
|
|
c78d164948 | ||
|
|
4dd2c86cca | ||
|
|
42467b3e66 | ||
|
|
361e7103ea | ||
|
|
bac948ea6f | ||
|
|
1c8eede1aa | ||
|
|
486652abaf | ||
|
|
5370f7876d | ||
|
|
eccaf8eb50 | ||
|
|
cbf7c9556c | ||
|
|
b63cf192b5 | ||
|
|
50ed29e0f0 | ||
|
|
ecb9bb2428 | ||
|
|
e86c066438 | ||
|
|
b6e791f7d0 | ||
|
|
c581bca29d | ||
|
|
2fa5037859 | ||
|
|
7c2ca7d03e | ||
|
|
c67d31580f | ||
|
|
58bd7008b4 | ||
|
|
4b6c0a6fc3 | ||
|
|
554b6d6fcf | ||
|
|
8021385ac4 | ||
|
|
5ba650bb6f | ||
|
|
e8f6d30055 | ||
|
|
2819fd51e2 | ||
|
|
638ab7c557 | ||
|
|
0bd808270d | ||
|
|
bc78e16146 | ||
|
|
3764d296c6 | ||
|
|
90eec91f9c | ||
|
|
d3164fc910 | ||
|
|
6c5a9edced | ||
|
|
4727385a01 | ||
|
|
89cfe6876e | ||
|
|
de8e9804ad | ||
|
|
81d25dd048 | ||
|
|
0193516f55 | ||
|
|
19d14d2414 | ||
|
|
739ac468ed | ||
|
|
6c3e4d2a76 | ||
|
|
fb9ebeb7aa | ||
|
|
641b36be6a | ||
|
|
e858a4f4c7 | ||
|
|
a06522f254 | ||
|
|
96af9761b7 | ||
|
|
9ff0e455c3 | ||
|
|
ebef18d626 | ||
|
|
a942531079 | ||
|
|
cc9c9e9db5 | ||
|
|
a7026cc82c | ||
|
|
ed285f97fd | ||
|
|
1b7d4b5a18 | ||
|
|
364f9dd854 | ||
|
|
7e1aebe009 | ||
|
|
609c7ef4ec | ||
|
|
5a6411fa49 | ||
|
|
3da6c561b8 | ||
|
|
bb118eba6e | ||
|
|
96e57f1e6f | ||
|
|
2a9b7a4d5f | ||
|
|
3d9e3b8717 | ||
|
|
264abed82c | ||
|
|
19257a8bc2 | ||
|
|
034266db47 | ||
|
|
69b8096eb3 | ||
|
|
7b982ae782 | ||
|
|
3a37add48d | ||
|
|
7958cc7e29 | ||
|
|
88c76d4794 | ||
|
|
022a2e0860 | ||
|
|
bd2e55dcf3 | ||
|
|
d3773c11f1 | ||
|
|
59694fb72e | ||
|
|
ac2bf56ebc | ||
|
|
48f7c27248 | ||
|
|
06b387fe98 | ||
|
|
4cf81d88a7 | ||
|
|
79d1e179f8 | ||
|
|
c00f931500 | ||
|
|
fd5c5960c2 | ||
|
|
ab081cd522 | ||
|
|
e2789608b2 | ||
|
|
85ad7e4fb4 | ||
|
|
cb9c5b2d49 | ||
|
|
d4ef7c1412 | ||
|
|
5815b4a0c0 | ||
|
|
bdb670e852 | ||
|
|
11d7932968 | ||
|
|
02a77b528b | ||
|
|
206f195c1c | ||
|
|
2c2a6498af | ||
|
|
7ab47b3d83 | ||
|
|
9a3b9fcac2 | ||
|
|
b88163392c | ||
|
|
c7cad402b4 | ||
|
|
8dfac0fb65 | ||
|
|
90caca3336 | ||
|
|
80bcfd918b | ||
|
|
69ad52907e | ||
|
|
fbd85649f9 | ||
|
|
30e9c516e7 | ||
|
|
af398c49fd | ||
|
|
29e5c4a293 | ||
|
|
f71d8875d0 | ||
|
|
06c26a22cd | ||
|
|
fa45fd0e31 | ||
|
|
665ca017a1 | ||
|
|
33bca2d141 | ||
|
|
eb17a293e5 | ||
|
|
c51d94d8a9 | ||
|
|
e9101a2421 | ||
|
|
7ef82d8422 | ||
|
|
42b5152888 | ||
|
|
7dcfde7329 | ||
|
|
15cd727b96 | ||
|
|
e55d3e49e1 | ||
|
|
ac9b57c07e | ||
|
|
f117475970 | ||
|
|
a40dabbd22 | ||
|
|
e0172d0953 | ||
|
|
c80b2748e1 | ||
|
|
510d84898c | ||
|
|
0129e002e8 | ||
|
|
3b11733bd8 | ||
|
|
96eeb9fea0 | ||
|
|
2ba8fee605 | ||
|
|
9d0dcf3c44 | ||
|
|
3140a0cb15 | ||
|
|
9a8c06d09d | ||
|
|
c8b58a0f70 | ||
|
|
c9afd01b60 | ||
|
|
81a4dd7d89 | ||
|
|
3445a55c2b | ||
|
|
0559d4d870 | ||
|
|
608cefa8cd | ||
|
|
521ac7d91f | ||
|
|
08f5760718 | ||
|
|
3ddf242c65 | ||
|
|
0d207f4f9a | ||
|
|
2064e88e06 | ||
|
|
37d287199f | ||
|
|
1ee407bf0c | ||
|
|
971217c4e6 | ||
|
|
078571d267 | ||
|
|
25ea76ebc9 | ||
|
|
f4c97abe91 | ||
|
|
073317394b | ||
|
|
cf887ab10a | ||
|
|
6421206732 | ||
|
|
288e7a5fb5 | ||
|
|
5ec8a6efbd | ||
|
|
8053ec6872 | ||
|
|
520d8e66a8 | ||
|
|
9858af9014 | ||
|
|
aa87270148 | ||
|
|
8b329caf0e | ||
|
|
6f1309795e | ||
|
|
5f94d5a687 | ||
|
|
d6b1d0c7ff | ||
|
|
ce9d14d55e | ||
|
|
eccee53142 | ||
|
|
f7f11ad6c2 | ||
|
|
0c2381f4ff | ||
|
|
e4ddffd0e2 | ||
|
|
f5ac262a2f | ||
|
|
04cd74cad0 | ||
|
|
7b1edd5ad4 | ||
|
|
47d50c9163 | ||
|
|
8a3466e86f | ||
|
|
59f0128d27 | ||
|
|
761c2035c7 | ||
|
|
094ca2ad97 | ||
|
|
c33a4651c9 | ||
|
|
783dfe0a14 | ||
|
|
b9f43c3542 | ||
|
|
65325eef89 | ||
|
|
2421cab479 | ||
|
|
ec1c74c146 |
@@ -19,10 +19,23 @@ extends:
|
||||
- prettier/@typescript-eslint # Remove conflicts again.
|
||||
|
||||
rules:
|
||||
# Sometimes you need to add args to implement a function signature even
|
||||
# if they are unused.
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }]
|
||||
# For overloads.
|
||||
no-dupe-class-members: off
|
||||
"@typescript-eslint/no-use-before-define": off
|
||||
"@typescript-eslint/no-non-null-assertion": off
|
||||
"@typescript-eslint/ban-types": off
|
||||
"@typescript-eslint/no-var-requires": off
|
||||
"@typescript-eslint/explicit-module-boundary-types": off
|
||||
"@typescript-eslint/no-explicit-any": off
|
||||
eqeqeq: error
|
||||
import/order:
|
||||
[error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }]
|
||||
no-async-promise-executor: off
|
||||
# This isn't a real module, just types, which apparently doesn't resolve.
|
||||
import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }]
|
||||
|
||||
settings:
|
||||
# Does not work with CommonJS unfortunately.
|
||||
|
||||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1 +1,3 @@
|
||||
* @code-asher @nhooyr
|
||||
|
||||
ci/helm-chart @Matthew-Beckett @alexgorbatchev
|
||||
|
||||
28
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report a bug and help us improve
|
||||
title: ""
|
||||
labels: ""
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
<!--
|
||||
Please see https://github.com/cdr/code-server/blob/master/doc/FAQ.md#how-do-i-debug-issues-with-code-server
|
||||
and include any logging information relevant to the issue.
|
||||
|
||||
Please search for existing issues before filing.
|
||||
|
||||
If you can reproduce the issue on vanilla VS Code,
|
||||
please file the issue at the VS Code repository instead.
|
||||
|
||||
Provide screenshots if applicable.
|
||||
|
||||
Please fill in the issue template and try to be as detailed
|
||||
and clear as possible!
|
||||
-->
|
||||
|
||||
- Web Browser:
|
||||
- Local OS:
|
||||
- Remote OS:
|
||||
- Remote Architecture:
|
||||
- `code-server --version`:
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question
|
||||
url: https://github.com/cdr/code-server/discussions/new?category_id=22503114
|
||||
about: Ask the community for help on our GitHub Discussions board
|
||||
- name: Chat
|
||||
about: Need immediate help or just want to talk? Hop in our Slack
|
||||
url: https://cdr.co/join-community
|
||||
7
.github/ISSUE_TEMPLATE/doc.md
vendored
Normal file
7
.github/ISSUE_TEMPLATE/doc.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Documentation improvement
|
||||
about: Suggest a documentation improvement
|
||||
title: ""
|
||||
labels: "docs"
|
||||
assignees: ""
|
||||
---
|
||||
18
.github/ISSUE_TEMPLATE/extension-request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/extension-request.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: Extension request
|
||||
about: Request an extension missing from the code-server marketplace
|
||||
title: ""
|
||||
labels: extension-request
|
||||
assignees: cmoog
|
||||
---
|
||||
|
||||
<!--
|
||||
Details on the code-server extension marketplace are at
|
||||
|
||||
https://github.com/cdr/code-server/blob/master/doc/FAQ.md#whats-the-deal-with-extensions
|
||||
|
||||
Please fill in the issue template!
|
||||
-->
|
||||
|
||||
- [ ] Extension name:
|
||||
- [ ] Extension GitHub or homepage:
|
||||
13
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea
|
||||
title: ""
|
||||
labels: feature
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
<!--
|
||||
Please search for existing issues before filing.
|
||||
|
||||
Please describe the feature as clearly as possible!
|
||||
-->
|
||||
11
.github/issue_template.md
vendored
11
.github/issue_template.md
vendored
@@ -1,11 +0,0 @@
|
||||
<!--
|
||||
Please file all questions and support requests at https://www.reddit.com/r/codeserver/
|
||||
The issue tracker is only for bugs.
|
||||
|
||||
Please see https://github.com/cdr/code-server/blob/master/doc/FAQ.md#how-do-i-debug-issues-with-code-server
|
||||
and include any logging information relevant to the issue.
|
||||
|
||||
Please search for existing issues before filing.
|
||||
|
||||
Please ensure you cannot reproduce on VS Code before filing.
|
||||
-->
|
||||
37
.github/lock.yml
vendored
Normal file
37
.github/lock.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 90
|
||||
|
||||
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||
skipCreatedBefore: false
|
||||
|
||||
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||
exemptLabels: []
|
||||
|
||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||
lockLabel: false
|
||||
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: >
|
||||
This thread has been automatically locked since there has not been
|
||||
any recent activity after it was closed. Please open a new issue for
|
||||
related bugs.
|
||||
|
||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||
setLockReason: true
|
||||
# Limit to only `issues` or `pulls`
|
||||
# only: issues
|
||||
|
||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - help-wanted
|
||||
# lockLabel: outdated
|
||||
|
||||
# pulls:
|
||||
# daysUntilLock: 30
|
||||
|
||||
# Repository to extend settings from
|
||||
# _extends: repo
|
||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -1,4 +1,6 @@
|
||||
<!--
|
||||
Please link to the issue this PR solves.
|
||||
If there is no existing issue, please first create one unless the fix is minor.
|
||||
|
||||
Please make sure the base of your PR is the master branch!
|
||||
-->
|
||||
|
||||
38
.github/workflows/ci.yaml
vendored
38
.github/workflows/ci.yaml
vendored
@@ -1,6 +1,6 @@
|
||||
name: ci
|
||||
|
||||
on: [push, pull_request]
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
fmt:
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/fmt.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/fmt.sh
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/lint.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/lint.sh
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/test.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/test.sh
|
||||
|
||||
@@ -35,14 +35,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/release.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/release.sh
|
||||
- name: Upload npm package artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: npm-package
|
||||
path: ./release
|
||||
path: ./release-npm-package
|
||||
|
||||
linux-amd64:
|
||||
needs: release
|
||||
@@ -53,11 +53,11 @@ jobs:
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: npm-package
|
||||
path: ./release
|
||||
- name: Run ./ci/steps/release-static.sh
|
||||
uses: ./ci/container
|
||||
path: ./release-npm-package
|
||||
- name: Run ./ci/steps/release-packages.sh
|
||||
uses: ./ci/images/centos7
|
||||
with:
|
||||
args: ./ci/steps/release-static.sh
|
||||
args: ./ci/steps/release-packages.sh
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@@ -73,11 +73,11 @@ jobs:
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: npm-package
|
||||
path: ./release
|
||||
- name: Run ./ci/steps/release-static.sh
|
||||
uses: ./ci/container
|
||||
path: ./release-npm-package
|
||||
- name: Run ./ci/steps/release-packages.sh
|
||||
uses: ./ci/images/centos7
|
||||
with:
|
||||
args: ./ci/steps/release-static.sh
|
||||
args: ./ci/steps/release-packages.sh
|
||||
- name: Upload release artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
@@ -93,10 +93,8 @@ jobs:
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: npm-package
|
||||
path: ./release
|
||||
- run: brew unlink node@12
|
||||
- run: brew install node
|
||||
- run: ./ci/steps/release-static.sh
|
||||
path: ./release-npm-package
|
||||
- run: ./ci/steps/release-packages.sh
|
||||
env:
|
||||
# Otherwise we get rate limited when fetching the ripgrep binary.
|
||||
# For whatever reason only MacOS needs it.
|
||||
@@ -118,7 +116,7 @@ jobs:
|
||||
name: release-packages
|
||||
path: ./release-packages
|
||||
- name: Run ./ci/steps/build-docker-image.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/build-docker-image.sh
|
||||
- name: Upload release image
|
||||
@@ -138,7 +136,7 @@ jobs:
|
||||
name: release-packages
|
||||
path: ./release-packages
|
||||
- name: Run ./ci/steps/build-docker-image.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/centos7
|
||||
with:
|
||||
args: ./ci/steps/build-docker-image.sh
|
||||
- name: Upload release image
|
||||
|
||||
4
.github/workflows/publish.yaml
vendored
4
.github/workflows/publish.yaml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/publish-npm.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/publish-npm.sh
|
||||
env:
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Run ./ci/steps/push-docker-manifest.sh
|
||||
uses: ./ci/container
|
||||
uses: ./ci/images/debian10
|
||||
with:
|
||||
args: ./ci/steps/push-docker-manifest.sh
|
||||
env:
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -3,8 +3,13 @@
|
||||
dist*
|
||||
out*
|
||||
release/
|
||||
release-static/
|
||||
release-npm-package/
|
||||
release-standalone/
|
||||
release-packages/
|
||||
release-gcp/
|
||||
release-images/
|
||||
node_modules
|
||||
node-*
|
||||
/plugins
|
||||
/lib/coder-cloud-agent
|
||||
.home
|
||||
|
||||
1
.gitmodules
vendored
1
.gitmodules
vendored
@@ -1,3 +1,4 @@
|
||||
[submodule "lib/vscode"]
|
||||
path = lib/vscode
|
||||
url = https://github.com/microsoft/vscode
|
||||
ignore = dirty
|
||||
|
||||
116
README.md
116
README.md
@@ -1,105 +1,69 @@
|
||||
# code-server
|
||||
# code-server · [](https://github.com/cdr/code-server/discussions) [](https://cdr.co/join-community) [](https://twitter.com/coderhq)
|
||||
|
||||
Run [VS Code](https://github.com/Microsoft/vscode) on any machine anywhere and access it in the browser.
|
||||
|
||||
- **Code everywhere:** Code on your Chromebook, tablet, and laptop with a
|
||||
consistent dev environment. Develop on a Linux machine and pick up from any
|
||||
device with a web browser.
|
||||
- **Server-powered:** Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
|
||||
Preserve battery life when you're on the go since all intensive tasks runs on your server.
|
||||
Make use of a spare computer you have lying around and turn it into a full development environment.
|
||||

|
||||
|
||||

|
||||
## Highlights
|
||||
|
||||
## Getting started
|
||||
- Code on any device with a consistent development environment
|
||||
- Use cloud servers to speed up tests, compilations, downloads, and more
|
||||
- Preserve battery life when you're on the go; all intensive tasks run on your server
|
||||
|
||||
For a full setup and walkthrough, please see [./doc/guide.md](./doc/guide.md).
|
||||
## Getting Started
|
||||
|
||||
### Debian, Ubuntu
|
||||
There are two ways to get started:
|
||||
|
||||
1. Using the [install script](./install.sh), which automates most of the process. The script uses the system package manager (if possible)
|
||||
2. Manually installing code-server; see [Installation](./doc/install.md) for instructions applicable to most use cases
|
||||
|
||||
If you choose to use the install script, you can preview what occurs during the install process:
|
||||
|
||||
```bash
|
||||
curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server_3.3.0_amd64.deb
|
||||
sudo dpkg -i code-server_3.3.0_amd64.deb
|
||||
systemctl --user enable --now code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
### Fedora, Red Hat, SUSE
|
||||
To install, run:
|
||||
|
||||
```bash
|
||||
curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server-3.3.0-amd64.rpm
|
||||
sudo yum install -y code-server-3.3.0-amd64.rpm
|
||||
systemctl --user enable --now code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
```
|
||||
|
||||
### npm
|
||||
When done, the install script prints out instructions for running and starting code-server.
|
||||
|
||||
We recommend installing from `npm` if we don't have a precompiled release for your machine's
|
||||
platform or architecture.
|
||||
We also have an in-depth [setup and configuration](./doc/guide.md) guide.
|
||||
|
||||
**note:** Installing via `npm` builds native modules on install and so requires C dependencies.
|
||||
See [./doc/npm.md](./doc/npm.md) for installing these dependencies.
|
||||
### Alpha Program 🐣
|
||||
|
||||
You will need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633).
|
||||
We're working on a cloud platform that makes deploying and managing code-server easier. Consider [updating to 3.7.0](https://github.com/cdr/code-server/releases/tag/v3.7.0) and running code-server with our experimental flag `--link` if you don't want to worry about
|
||||
|
||||
- TLS
|
||||
- Authentication
|
||||
- Port Forwarding
|
||||
|
||||
```bash
|
||||
npm install -g code-server
|
||||
code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
```bash
|
||||
brew install code-server
|
||||
brew services start code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
# This will start a code-server container and expose it at http://127.0.0.1:8080.
|
||||
# It will also mount your current directory into the container as `/home/coder/project`
|
||||
# and forward your UID/GID so that all file system operations occur as your user outside
|
||||
# the container.
|
||||
docker run -it -p 127.0.0.1:8080:8080 \
|
||||
-v "$PWD:/home/coder/project" \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
codercom/code-server:latest
|
||||
```
|
||||
|
||||
### Static releases
|
||||
|
||||
We publish self contained `.tar.gz` archives for every release on [github](https://github.com/cdr/code-server/releases).
|
||||
They bundle the node binary and compiled native modules.
|
||||
|
||||
1. Download the latest release archive for your system from [github](https://github.com/cdr/code-server/releases).
|
||||
2. Unpack the release.
|
||||
3. You can run code-server by executing `./bin/code-server`.
|
||||
|
||||
Add the code-server `bin` directory to your `$PATH` to easily execute `code-server` without the full path every time.
|
||||
|
||||
Here is an example script for installing and using a static `code-server` release on Linux:
|
||||
|
||||
```bash
|
||||
curl -sSL https://github.com/cdr/code-server/releases/download/3.3.0/code-server-3.3.0-linux-amd64.tar.gz | sudo tar -C /usr/local -xz
|
||||
sudo mv /usr/local/code-server-3.3.0-linux-amd64 /usr/local/code-server
|
||||
PATH="$PATH:/usr/local/code-server/bin"
|
||||
code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
$ code-server --link
|
||||
Proxying code-server to Coder Cloud, you can access your IDE at https://valmar-jon.cdr.co
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
See [./doc/FAQ.md](./doc/FAQ.md).
|
||||
|
||||
## Contributing
|
||||
## Want to help?
|
||||
|
||||
See [./doc/CONTRIBUTING.md](./doc/CONTRIBUTING.md).
|
||||
See [CONTRIBUTING](./doc/CONTRIBUTING.md) for details.
|
||||
|
||||
## Enterprise
|
||||
## Hiring
|
||||
|
||||
Visit [our website](https://coder.com) for more information about our
|
||||
enterprise offerings.
|
||||
We ([@cdr](https://github.com/cdr)) are looking for engineers to help [maintain
|
||||
code-server](https://jobs.lever.co/coder/e40becde-2cbd-4885-9029-e5c7b0a734b8), innovate on open source, and streamline dev workflows.
|
||||
|
||||
Our main office is in Austin, Texas. Remote is ok as long as
|
||||
you're in North America or Europe.
|
||||
|
||||
Please get in [touch](mailto:jobs@coder.com) with your resume/GitHub if interested.
|
||||
|
||||
## For Organizations
|
||||
|
||||
Visit [our website](https://coder.com) for more information about remote development for your organization or enterprise.
|
||||
|
||||
22
ThirdPartyNotices.txt
Normal file
22
ThirdPartyNotices.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
code-server
|
||||
|
||||
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
|
||||
Do Not Translate or Localize
|
||||
|
||||
1. Microsoft/vscode version 1.47.0 (https://github.com/Microsoft/vscode)
|
||||
|
||||
%% Microsoft/vscode NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
|
||||
|
||||
Copyright (c) 2015 - present Microsoft Corporation
|
||||
|
||||
|
||||
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.
|
||||
53
ci/README.md
53
ci/README.md
@@ -14,26 +14,37 @@ Any file or directory in this subdirectory should be documented here.
|
||||
|
||||
Make sure you have `$GITHUB_TOKEN` set and [hub](https://github.com/github/hub) installed.
|
||||
|
||||
1. Update the version of code-server in `package.json` and README.md/guide.md install examples and push a commit.
|
||||
1. Update the version of code-server and make a PR.
|
||||
1. Update in `package.json`
|
||||
2. Update in [./doc/install.md](../doc/install.md)
|
||||
3. Update in [./ci/helm-chart/README.md](../ci/helm-chart/README.md)
|
||||
2. GitHub actions will generate the `npm-package`, `release-packages` and `release-images` artifacts.
|
||||
1. You do not have to wait for these.
|
||||
3. Run `yarn release:github-draft` to create a GitHub draft release from the template with
|
||||
the updated version.
|
||||
1. Summarize the major changes in the release notes and link to the relevant issues.
|
||||
4. Wait for the artifacts in step 2 to build.
|
||||
5. Run `yarn release:github-assets` to download the `release-packages` artifact and then
|
||||
upload them to the draft release.
|
||||
5. Run `yarn release:github-assets` to download the `release-packages` artifact.
|
||||
- It will upload them to the draft release.
|
||||
6. Run some basic sanity tests on one of the released packages.
|
||||
7. Publish the release.
|
||||
- Especially make sure the terminal works fine.
|
||||
7. Make sure the github release tag is the commit with the artifacts. This is a bug in
|
||||
`hub` where uploading assets in step 5 will break the tag.
|
||||
8. Publish the release and merge the PR.
|
||||
1. CI will automatically grab the artifacts and then:
|
||||
1. Publish the NPM package from `npm-package`.
|
||||
2. Publish the Docker Hub image from `release-images`.
|
||||
8. Update the homebrew and AUR packages.
|
||||
9. Update the AUR package.
|
||||
- Instructions on updating the AUR package are at [cdr/code-server-aur](https://github.com/cdr/code-server-aur).
|
||||
10. Wait for the npm package to be published.
|
||||
11. Update the homebrew package.
|
||||
- Send a pull request to [homebrew-core](https://github.com/Homebrew/homebrew-core) with the URL in the [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/code-server.rb) updated.
|
||||
|
||||
## dev
|
||||
|
||||
This directory contains scripts used for the development of code-server.
|
||||
|
||||
- [./ci/dev/container](./dev/container)
|
||||
- [./ci/dev/image](./dev/image)
|
||||
- See [./doc/CONTRIBUTING.md](../doc/CONTRIBUTING.md) for docs on the development container.
|
||||
- [./ci/dev/fmt.sh](./dev/fmt.sh) (`yarn fmt`)
|
||||
- Runs formatters.
|
||||
@@ -67,24 +78,24 @@ You can disable minification by setting `MINIFY=`.
|
||||
- Builds vscode into `./lib/vscode/out-vscode`.
|
||||
- [./ci/build/build-release.sh](./build/build-release.sh) (`yarn release`)
|
||||
- Bundles the output of the above two scripts into a single node module at `./release`.
|
||||
- [./ci/build/build-static-release.sh](./build/build-static-release.sh) (`yarn release:static`)
|
||||
- [./ci/build/build-standalone-release.sh](./build/build-standalone-release.sh) (`yarn release:standalone`)
|
||||
- Requires a node module already built into `./release` with the above script.
|
||||
- Will build a static release with node and native modules bundled into `./release-static`.
|
||||
- Will build a standalone release with node and node_modules bundled into `./release-standalone`.
|
||||
- [./ci/build/clean.sh](./build/clean.sh) (`yarn clean`)
|
||||
- Removes all build artifacts.
|
||||
- Will also `git reset --hard lib/vscode`.
|
||||
- Useful to do a clean build.
|
||||
- [./ci/build/code-server.sh](./build/code-server.sh)
|
||||
- Copied into static releases to run code-server with the bundled node binary.
|
||||
- [./ci/build/test-static-release.sh](./build/test-static-release.sh) (`yarn test:static-release`)
|
||||
- Ensures code-server in the `./release-static` directory works by installing an extension.
|
||||
- Copied into standalone releases to run code-server with the bundled node binary.
|
||||
- [./ci/build/test-standalone-release.sh](./build/test-standalone-release.sh) (`yarn test:standalone-release`)
|
||||
- Ensures code-server in the `./release-standalone` directory works by installing an extension.
|
||||
- [./ci/build/build-packages.sh](./build/build-packages.sh) (`yarn package`)
|
||||
- Packages `./release-static` into a `.tar.gz` archive in `./release-packages`.
|
||||
- Packages `./release-standalone` into a `.tar.gz` archive in `./release-packages`.
|
||||
- If on linux, [nfpm](https://github.com/goreleaser/nfpm) is used to generate `.deb` and `.rpm`.
|
||||
- [./ci/build/nfpm.yaml](./build/nfpm.yaml)
|
||||
- Used to configure [nfpm](https://github.com/goreleaser/nfpm) to generate `.deb` and `.rpm`.
|
||||
- [./ci/build/code-server-nfpm.sh](./build/code-server-nfpm.sh)
|
||||
- Entrypoint script for code-server for `.deb` and .rpm`.
|
||||
- Entrypoint script for code-server for `.deb` and `.rpm`.
|
||||
- [./ci/build/code-server.service](./build/code-server.service)
|
||||
- systemd user service packaged into the `.deb` and `.rpm`.
|
||||
- [./ci/build/release-github-draft.sh](./build/release-github-draft.sh) (`yarn release:github-draft`)
|
||||
@@ -97,17 +108,17 @@ You can disable minification by setting `MINIFY=`.
|
||||
- Post install script for the npm package.
|
||||
- Bundled by`yarn release`.
|
||||
|
||||
## release-container
|
||||
## release-image
|
||||
|
||||
This directory contains the release docker container.
|
||||
This directory contains the release docker container image.
|
||||
|
||||
- [./release-container/build.sh](./release-container/build.sh)
|
||||
- [./release-image/build.sh](./release-image/build.sh)
|
||||
- Builds the release container with the tag `codercom/code-server-$ARCH:$VERSION`.
|
||||
- Assumes debian releases are ready in `./release-packages`.
|
||||
|
||||
## container
|
||||
## images
|
||||
|
||||
This directory contains the container for CI.
|
||||
This directory contains the images for CI.
|
||||
|
||||
## steps
|
||||
|
||||
@@ -123,9 +134,9 @@ Helps avoid clobbering the CI configuration.
|
||||
- [./steps/release.sh](./steps/release.sh)
|
||||
- Runs the release process.
|
||||
- Generates the npm package at `./release`.
|
||||
- [./steps/release-static.sh](./steps/release-static.sh)
|
||||
- Takes the output of the previous script and generates a static release and
|
||||
release packages into `release-packages`.
|
||||
- [./steps/release-packages.sh](./steps/release-packages.sh)
|
||||
- Takes the output of the previous script and generates a standalone release and
|
||||
release packages into `./release-packages`.
|
||||
- [./steps/publish-npm.sh](./steps/publish-npm.sh)
|
||||
- Grabs the `npm-package` release artifact for the current commit and publishes it on npm.
|
||||
- [./steps/build-docker-image.sh](./steps/build-docker-image.sh)
|
||||
|
||||
@@ -9,7 +9,8 @@ MINIFY=${MINIFY-true}
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
|
||||
npx tsc --outDir out --tsBuildInfoFile .cache/out.tsbuildinfo
|
||||
tsc
|
||||
|
||||
# If out/node/entry.js does not already have the shebang,
|
||||
# we make sure to add it and make it executable.
|
||||
if ! grep -q -m1 "^#!/usr/bin/env node" out/node/entry.js; then
|
||||
@@ -17,13 +18,20 @@ main() {
|
||||
chmod +x out/node/entry.js
|
||||
fi
|
||||
|
||||
npx parcel build \
|
||||
--public-url "/static/$(git rev-parse HEAD)/dist" \
|
||||
if ! [ -f ./lib/coder-cloud-agent ]; then
|
||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
fi
|
||||
|
||||
parcel build \
|
||||
--public-url "." \
|
||||
--out-dir dist \
|
||||
$([[ $MINIFY ]] || echo --no-minify) \
|
||||
src/browser/pages/app.ts \
|
||||
src/browser/register.ts \
|
||||
src/browser/serviceWorker.ts
|
||||
src/browser/serviceWorker.ts \
|
||||
src/browser/pages/login.ts \
|
||||
src/browser/pages/vscode.ts
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -2,28 +2,32 @@
|
||||
set -euo pipefail
|
||||
|
||||
# Packages code-server for the current OS and architecture into ./release-packages.
|
||||
# This script assumes that a static release is built already into ./release-static.
|
||||
# This script assumes that a standalone release is built already into ./release-standalone
|
||||
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
local release_name="code-server-$VERSION-$OS-$ARCH"
|
||||
mkdir -p release-packages
|
||||
|
||||
release_archive
|
||||
|
||||
if [[ $OS == "linux" ]]; then
|
||||
tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-static/$release_name/" ./release-static
|
||||
release_nfpm
|
||||
fi
|
||||
}
|
||||
|
||||
release_archive() {
|
||||
local release_name="code-server-$VERSION-$OS-$ARCH"
|
||||
if [[ $OS == "linux" ]]; then
|
||||
tar -czf "release-packages/$release_name.tar.gz" --transform "s/^\.\/release-standalone/$release_name/" ./release-standalone
|
||||
else
|
||||
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-static/$release_name/" release-static
|
||||
tar -czf "release-packages/$release_name.tar.gz" -s "/^release-standalone/$release_name/" release-standalone
|
||||
fi
|
||||
|
||||
echo "done (release-packages/$release_name)"
|
||||
|
||||
release_gcp
|
||||
|
||||
if [[ $OSTYPE == linux* ]]; then
|
||||
release_nfpm
|
||||
fi
|
||||
}
|
||||
|
||||
release_gcp() {
|
||||
@@ -36,10 +40,10 @@ release_gcp() {
|
||||
# Generates deb and rpm packages.
|
||||
release_nfpm() {
|
||||
local nfpm_config
|
||||
nfpm_config=$(envsubst < ./ci/build/nfpm.yaml)
|
||||
nfpm_config="$(envsubst < ./ci/build/nfpm.yaml)"
|
||||
|
||||
# The underscores are convention for .deb.
|
||||
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_${ARCH}.deb"
|
||||
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server_${VERSION}_$ARCH.deb"
|
||||
nfpm pkg -f <(echo "$nfpm_config") --target "release-packages/code-server-$VERSION-$ARCH.rpm"
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ set -euo pipefail
|
||||
# MINIFY controls whether minified vscode is bundled.
|
||||
MINIFY="${MINIFY-true}"
|
||||
|
||||
# KEEP_MODULES controls whether the script cleans all node_modules requiring a yarn install
|
||||
# to run first.
|
||||
KEEP_MODULES="${KEEP_MODULES-0}"
|
||||
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
source ./ci/lib.sh
|
||||
@@ -21,6 +25,12 @@ main() {
|
||||
rsync README.md "$RELEASE_PATH"
|
||||
rsync LICENSE.txt "$RELEASE_PATH"
|
||||
rsync ./lib/vscode/ThirdPartyNotices.txt "$RELEASE_PATH"
|
||||
|
||||
# code-server exports types which can be imported and used by plugins. Those
|
||||
# types import ipc.d.ts but it isn't included in the final vscode build so
|
||||
# we'll copy it ourselves here.
|
||||
mkdir -p "$RELEASE_PATH/lib/vscode/src/vs/server"
|
||||
rsync ./lib/vscode/src/vs/server/ipc.d.ts "$RELEASE_PATH/lib/vscode/src/vs/server"
|
||||
}
|
||||
|
||||
bundle_code_server() {
|
||||
@@ -31,6 +41,7 @@ bundle_code_server() {
|
||||
rsync src/browser/media/ "$RELEASE_PATH/src/browser/media"
|
||||
mkdir -p "$RELEASE_PATH/src/browser/pages"
|
||||
rsync src/browser/pages/*.html "$RELEASE_PATH/src/browser/pages"
|
||||
rsync src/browser/robots.txt "$RELEASE_PATH/src/browser"
|
||||
|
||||
# Adds the commit to package.json
|
||||
jq --slurp '.[0] * .[1]' package.json <(
|
||||
@@ -45,15 +56,28 @@ EOF
|
||||
) > "$RELEASE_PATH/package.json"
|
||||
rsync yarn.lock "$RELEASE_PATH"
|
||||
rsync ci/build/npm-postinstall.sh "$RELEASE_PATH/postinstall.sh"
|
||||
|
||||
if [ "$KEEP_MODULES" = 1 ]; then
|
||||
rsync node_modules/ "$RELEASE_PATH/node_modules"
|
||||
mkdir -p "$RELEASE_PATH/lib"
|
||||
rsync ./lib/coder-cloud-agent "$RELEASE_PATH/lib"
|
||||
fi
|
||||
}
|
||||
|
||||
bundle_vscode() {
|
||||
mkdir -p "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/package.json" "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/node_modules" "$VSCODE_OUT_PATH"
|
||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY+-min}/" "$VSCODE_OUT_PATH/out"
|
||||
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
|
||||
|
||||
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
|
||||
if [ "$KEEP_MODULES" = 0 ]; then
|
||||
rm -Rf "$VSCODE_OUT_PATH/extensions/node_modules"
|
||||
else
|
||||
rsync "$VSCODE_SRC_PATH/node_modules/" "$VSCODE_OUT_PATH/node_modules"
|
||||
fi
|
||||
rsync "$VSCODE_SRC_PATH/extensions/package.json" "$VSCODE_OUT_PATH/extensions"
|
||||
rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions"
|
||||
rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions"
|
||||
|
||||
mkdir -p "$VSCODE_OUT_PATH/resources/linux"
|
||||
rsync "$VSCODE_SRC_PATH/resources/linux/code.png" "$VSCODE_OUT_PATH/resources/linux/code.png"
|
||||
@@ -68,26 +92,10 @@ bundle_vscode() {
|
||||
EOF
|
||||
) > "$VSCODE_OUT_PATH/product.json"
|
||||
|
||||
pushd "$VSCODE_OUT_PATH"
|
||||
yarn --production --frozen-lockfile --ignore-scripts
|
||||
popd
|
||||
|
||||
# We clear any native module builds.
|
||||
local native_modules
|
||||
mapfile -t native_modules < <(find "$VSCODE_OUT_PATH/node_modules" -name "binding.gyp" -exec dirname {} \;)
|
||||
local nm
|
||||
for nm in "${native_modules[@]}"; do
|
||||
rm -R "$nm/build"
|
||||
done
|
||||
|
||||
# We have to rename node_modules to node_modules.bundled to avoid them being ignored by yarn.
|
||||
local node_modules
|
||||
mapfile -t node_modules < <(find "$VSCODE_OUT_PATH" -depth -name "node_modules")
|
||||
local nm
|
||||
for nm in "${node_modules[@]}"; do
|
||||
rm -Rf "$nm.bundled"
|
||||
mv "$nm" "$nm.bundled"
|
||||
done
|
||||
# We remove the scripts field so that later on we can run
|
||||
# yarn to fetch node_modules if necessary without build scripts running.
|
||||
# We cannot use --no-scripts because we still want dependent package scripts to run.
|
||||
jq 'del(.scripts)' < "$VSCODE_SRC_PATH/package.json" > "$VSCODE_OUT_PATH/package.json"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -5,8 +5,8 @@ main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
rsync "$RELEASE_PATH/" "$RELEASE_PATH-static"
|
||||
RELEASE_PATH+=-static
|
||||
rsync "$RELEASE_PATH/" "$RELEASE_PATH-standalone"
|
||||
RELEASE_PATH+=-standalone
|
||||
|
||||
# We cannot find the path to node from $PATH because yarn shims a script to ensure
|
||||
# we use the same version it's using so we instead run a script with yarn that
|
||||
@@ -18,6 +18,9 @@ main() {
|
||||
rsync ./ci/build/code-server.sh "$RELEASE_PATH/bin/code-server"
|
||||
rsync "$node_path" "$RELEASE_PATH/lib/node"
|
||||
|
||||
ln -s "./bin/code-server" "$RELEASE_PATH/code-server"
|
||||
ln -s "./lib/node" "$RELEASE_PATH/node"
|
||||
|
||||
cd "$RELEASE_PATH"
|
||||
yarn --production --frozen-lockfile
|
||||
}
|
||||
@@ -5,15 +5,7 @@ main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
rm -Rf \
|
||||
out \
|
||||
release \
|
||||
release-static \
|
||||
release-packages \
|
||||
release-gcp \
|
||||
dist \
|
||||
.tsbuildinfo \
|
||||
.cache/out.tsbuildinfo
|
||||
git clean -Xffd
|
||||
|
||||
pushd lib/vscode
|
||||
git clean -xffd
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
# This script is intended to be bundled into the static releases.
|
||||
# Runs code-server with the bundled Node binary.
|
||||
# This script is intended to be bundled into the standalone releases.
|
||||
# Runs code-server with the bundled node binary.
|
||||
|
||||
# More complicated than readlink -f or realpath to support macOS.
|
||||
# See https://github.com/cdr/code-server/issues/1537
|
||||
bin_dir() {
|
||||
# We read the symlink, which may be relative from $0.
|
||||
dst="$(readlink "$0")"
|
||||
# We cd into the $0 directory.
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
# Now we can cd into the dst directory.
|
||||
cd "$(dirname "$dst")" || exit 1
|
||||
# Finally we use pwd -P to print the absolute path of the directory of $dst.
|
||||
pwd -P || exit 1
|
||||
_realpath() {
|
||||
# See https://github.com/cdr/code-server/issues/1537 on why no realpath or readlink -f.
|
||||
|
||||
script="$1"
|
||||
cd "$(dirname "$script")"
|
||||
|
||||
while [ -L "$(basename "$script")" ]; do
|
||||
if [ -L "./node" ] && [ -L "./code-server" ] &&
|
||||
[ -f "package.json" ] &&
|
||||
cat package.json | grep -q '^ "name": "code-server",$'; then
|
||||
echo "***** Please use the script in bin/code-server instead!" >&2
|
||||
echo "***** This script will soon be removed!" >&2
|
||||
echo "***** See the release notes at https://github.com/cdr/code-server/releases/tag/v3.4.0" >&2
|
||||
fi
|
||||
|
||||
script="$(readlink "$(basename "$script")")"
|
||||
cd "$(dirname "$script")"
|
||||
done
|
||||
|
||||
echo "$PWD/$(basename "$script")"
|
||||
}
|
||||
|
||||
BIN_DIR=$(bin_dir)
|
||||
exec "$BIN_DIR/../lib/node" "$BIN_DIR/.." "$@"
|
||||
root() {
|
||||
script="$(_realpath "$0")"
|
||||
bin_dir="$(dirname "$script")"
|
||||
dirname "$bin_dir"
|
||||
}
|
||||
|
||||
ROOT="$(root)"
|
||||
exec "$ROOT/lib/node" "$ROOT" "$@"
|
||||
|
||||
12
ci/build/code-server@.service
Normal file
12
ci/build/code-server@.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=code-server
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
ExecStart=/usr/bin/code-server
|
||||
Restart=always
|
||||
User=%i
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -10,8 +10,10 @@ description: |
|
||||
vendor: "Coder"
|
||||
homepage: "https://github.com/cdr/code-server"
|
||||
license: "MIT"
|
||||
bindir: "/usr/bin"
|
||||
files:
|
||||
./ci/build/code-server-nfpm.sh: /usr/bin/code-server
|
||||
./ci/build/code-server.service: /usr/lib/systemd/user/code-server.service
|
||||
./release-static/**/*: "/usr/lib/code-server/"
|
||||
./ci/build/code-server@.service: /usr/lib/systemd/system/code-server@.service
|
||||
# Only included for backwards compat with previous releases that shipped
|
||||
# the user service. See #1997
|
||||
./ci/build/code-server-user.service: /usr/lib/systemd/user/code-server.service
|
||||
./release-standalone/**/*: "/usr/lib/code-server/"
|
||||
|
||||
@@ -24,24 +24,32 @@ main() {
|
||||
;;
|
||||
esac
|
||||
|
||||
cd lib/vscode
|
||||
OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
if curl -fsSL "https://storage.googleapis.com/coder-cloud-releases/agent/latest/$OS/cloud-agent" -o ./lib/coder-cloud-agent; then
|
||||
chmod +x ./lib/coder-cloud-agent
|
||||
else
|
||||
echo "Failed to download cloud agent; --link will not work"
|
||||
fi
|
||||
|
||||
# We have to rename node_modules.bundled to node_modules.
|
||||
# The bundled modules were renamed originally to avoid being ignored by yarn.
|
||||
node_modules="$(find . -depth -name "node_modules.bundled")"
|
||||
for nm in $node_modules; do
|
||||
rm -Rf "${nm%.bundled}"
|
||||
mv "$nm" "${nm%.bundled}"
|
||||
done
|
||||
|
||||
# $npm_config_global makes npm rebuild return without rebuilding.
|
||||
unset npm_config_global
|
||||
# Rebuilds native modules.
|
||||
if ! npm rebuild; then
|
||||
if ! vscode_yarn; then
|
||||
echo "You may not have the required dependencies to build the native modules."
|
||||
echo "Please see https://github.com/cdr/code-server/blob/master/doc/npm.md"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
vscode_yarn() {
|
||||
cd lib/vscode
|
||||
yarn --production --frozen-lockfile
|
||||
cd extensions
|
||||
yarn --production --frozen-lockfile
|
||||
for ext in */; do
|
||||
ext="${ext%/}"
|
||||
echo "extensions/$ext: installing dependencies"
|
||||
cd "$ext"
|
||||
yarn --production --frozen-lockfile
|
||||
cd "$OLDPWD"
|
||||
done
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -11,7 +11,7 @@ main() {
|
||||
source ./ci/lib.sh
|
||||
|
||||
download_artifact release-packages ./release-packages
|
||||
local assets=(./release-packages/*)
|
||||
local assets=(./release-packages/code-server*"$VERSION"*{.tar.gz,.deb,.rpm})
|
||||
for i in "${!assets[@]}"; do
|
||||
assets[$i]="--attach=${assets[$i]}"
|
||||
done
|
||||
|
||||
@@ -9,6 +9,7 @@ main() {
|
||||
|
||||
hub release create \
|
||||
--file - \
|
||||
-t "$(git rev-parse HEAD)" \
|
||||
--draft "${assets[@]}" "v$VERSION" << EOF
|
||||
v$VERSION
|
||||
|
||||
|
||||
28
ci/build/test-standalone-release.sh
Executable file
28
ci/build/test-standalone-release.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Makes sure the release works.
|
||||
# This is to make sure we don't have Node version errors or any other
|
||||
# compilation-related errors.
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
|
||||
local EXTENSIONS_DIR
|
||||
EXTENSIONS_DIR="$(mktemp -d)"
|
||||
|
||||
echo "Testing standalone release."
|
||||
|
||||
./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
|
||||
local installed_extensions
|
||||
installed_extensions="$(./release-standalone/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
|
||||
# We use grep as ms-python.python may have dependency extensions that change.
|
||||
if ! echo "$installed_extensions" | grep -q "ms-python.python"; then
|
||||
echo "Unexpected output from listing extensions:"
|
||||
echo "$installed_extensions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Standalone release works correctly."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Makes sure the release works.
|
||||
# This is to make sure we don't have Node version errors or any other
|
||||
# compilation-related errors.
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../.."
|
||||
|
||||
local EXTENSIONS_DIR
|
||||
EXTENSIONS_DIR="$(mktemp -d)"
|
||||
|
||||
echo "Testing static release"
|
||||
|
||||
./release-static/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --install-extension ms-python.python
|
||||
local installed_extensions
|
||||
installed_extensions="$(./release-static/bin/code-server --extensions-dir "$EXTENSIONS_DIR" --list-extensions 2>&1)"
|
||||
if [[ $installed_extensions != "ms-python.python" ]]; then
|
||||
echo "Unexpected output from listing extensions:"
|
||||
echo "$installed_extensions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Static release works correctly"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,43 +0,0 @@
|
||||
FROM debian
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
# Needed for debian repositories added below.
|
||||
RUN apt-get install -y curl gnupg
|
||||
|
||||
# Installs node.
|
||||
RUN curl -sSL https://deb.nodesource.com/setup_14.x | bash - && \
|
||||
apt-get install -y nodejs
|
||||
|
||||
# Installs yarn.
|
||||
RUN curl -sSL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
|
||||
apt-get update && apt-get install -y yarn
|
||||
|
||||
# Installs VS Code build deps.
|
||||
RUN apt-get install -y build-essential \
|
||||
libsecret-1-dev \
|
||||
libx11-dev \
|
||||
libxkbfile-dev
|
||||
|
||||
# Installs envsubst.
|
||||
RUN apt-get install -y gettext-base
|
||||
|
||||
# Misc build dependencies.
|
||||
RUN apt-get install -y jq git rsync
|
||||
|
||||
# Installs shellcheck.
|
||||
RUN curl -sSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \
|
||||
tar -xJ && \
|
||||
mv shellcheck*/shellcheck /usr/local/bin && \
|
||||
rm -R shellcheck*
|
||||
|
||||
# Install Go dependencies
|
||||
RUN ARCH="$(dpkg --print-architecture)" && \
|
||||
curl -sSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
|
||||
ENV PATH=/usr/local/go/bin:/root/go/bin:$PATH
|
||||
ENV GO111MODULE=on
|
||||
RUN go get mvdan.cc/sh/v3/cmd/shfmt
|
||||
RUN go get github.com/goreleaser/nfpm/cmd/nfpm
|
||||
|
||||
RUN curl -fsSL https://get.docker.com | sh
|
||||
@@ -1,13 +0,0 @@
|
||||
FROM node:12
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
iproute2 \
|
||||
vim \
|
||||
iptables \
|
||||
net-tools \
|
||||
libsecret-1-dev \
|
||||
libx11-dev \
|
||||
libxkbfile-dev
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Opens an interactive bash session inside of a docker container
|
||||
# for improved isolation during development.
|
||||
# If the container exists it is restarted if necessary, then reused.
|
||||
|
||||
main() {
|
||||
cd "$(dirname "${0}")/../../.."
|
||||
|
||||
local container_name=code-server-dev
|
||||
|
||||
if docker inspect $container_name &> /dev/null; then
|
||||
echo "-- Starting container"
|
||||
docker start "$container_name" > /dev/null
|
||||
|
||||
enter
|
||||
exit 0
|
||||
fi
|
||||
|
||||
build
|
||||
run
|
||||
enter
|
||||
}
|
||||
|
||||
enter() {
|
||||
echo "--- Entering $container_name"
|
||||
docker exec -it "$container_name" /bin/bash
|
||||
}
|
||||
|
||||
run() {
|
||||
echo "--- Spawning $container_name"
|
||||
docker run \
|
||||
-it \
|
||||
--name $container_name \
|
||||
"-v=$PWD:/code-server" \
|
||||
"-w=/code-server" \
|
||||
"-p=127.0.0.1:8080:8080" \
|
||||
$(if [[ -t 0 ]]; then echo -it; fi) \
|
||||
"$container_name"
|
||||
}
|
||||
|
||||
build() {
|
||||
echo "--- Building $container_name"
|
||||
docker build -t $container_name ./ci/dev/container > /dev/null
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -6,7 +6,7 @@ main() {
|
||||
|
||||
cd ./lib/vscode
|
||||
git add -A
|
||||
git diff HEAD > ../../ci/dev/vscode.patch
|
||||
git diff HEAD --full-index > ../../ci/dev/vscode.patch
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -4,7 +4,7 @@ set -euo pipefail
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
shfmt -i 2 -w -s -sr $(git ls-files "*.sh")
|
||||
shfmt -i 2 -w -sr $(git ls-files "*.sh")
|
||||
|
||||
local prettierExts
|
||||
prettierExts=(
|
||||
@@ -19,10 +19,16 @@ main() {
|
||||
"*.yaml"
|
||||
"*.yml"
|
||||
)
|
||||
prettier --write --loglevel=warn $(git ls-files "${prettierExts[@]}")
|
||||
prettier --write --loglevel=warn $(
|
||||
git ls-files "${prettierExts[@]}" | grep -v 'helm-chart'
|
||||
)
|
||||
|
||||
doctoc --title '# FAQ' doc/FAQ.md > /dev/null
|
||||
doctoc --title '# Setup Guide' doc/guide.md > /dev/null
|
||||
doctoc --title '# Install' doc/install.md > /dev/null
|
||||
doctoc --title '# npm Install Requirements' doc/npm.md > /dev/null
|
||||
doctoc --title '# Contributing' doc/CONTRIBUTING.md > /dev/null
|
||||
doctoc --title '# iPad' doc/ipad.md > /dev/null
|
||||
|
||||
if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then
|
||||
echo "Files need generation or are formatted incorrectly:"
|
||||
|
||||
31
ci/dev/image/run.sh
Executable file
31
ci/dev/image/run.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../../.."
|
||||
source ./ci/lib.sh
|
||||
mkdir -p .home
|
||||
|
||||
docker run \
|
||||
-it \
|
||||
--rm \
|
||||
-v "$PWD:/src" \
|
||||
-e HOME="/src/.home" \
|
||||
-e USER="coder" \
|
||||
-e GITHUB_TOKEN \
|
||||
-e KEEP_MODULES \
|
||||
-e MINIFY \
|
||||
-w /src \
|
||||
-p 127.0.0.1:8080:8080 \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-e CI \
|
||||
"$(docker_build ./ci/images/"${IMAGE-debian10}")" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
docker_build() {
|
||||
docker build "$@" >&2
|
||||
docker build -q "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -7,7 +7,10 @@ main() {
|
||||
eslint --max-warnings=0 --fix $(git ls-files "*.ts" "*.tsx" "*.js")
|
||||
stylelint $(git ls-files "*.css")
|
||||
tsc --noEmit
|
||||
shellcheck -e SC2046,SC2164,SC2154 $(git ls-files "*.sh")
|
||||
shellcheck -e SC2046,SC2164,SC2154,SC1091,SC1090,SC2002 $(git ls-files "*.sh")
|
||||
if command -v helm && helm kubeval --help > /dev/null; then
|
||||
helm kubeval ci/helm-chart
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -4,7 +4,10 @@ set -euo pipefail
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
mocha -r ts-node/register ./test/*.test.ts
|
||||
cd test/test-plugin
|
||||
make -s out/index.js
|
||||
cd "$OLDPWD"
|
||||
mocha -r ts-node/register ./test/*.test.ts "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
1507
ci/dev/vscode.patch
1507
ci/dev/vscode.patch
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,9 @@ class Watcher {
|
||||
|
||||
const vscode = cp.spawn("yarn", ["watch"], { cwd: this.vscodeSourcePath })
|
||||
const tsc = cp.spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath })
|
||||
const plugin = process.env.PLUGIN_DIR
|
||||
? cp.spawn("yarn", ["build", "--watch"], { cwd: process.env.PLUGIN_DIR })
|
||||
: undefined
|
||||
const bundler = this.createBundler()
|
||||
|
||||
const cleanup = (code?: number | null): void => {
|
||||
@@ -48,6 +51,12 @@ class Watcher {
|
||||
tsc.removeAllListeners()
|
||||
tsc.kill()
|
||||
|
||||
if (plugin) {
|
||||
Watcher.log("killing plugin")
|
||||
plugin.removeAllListeners()
|
||||
plugin.kill()
|
||||
}
|
||||
|
||||
if (server) {
|
||||
Watcher.log("killing server")
|
||||
server.removeAllListeners()
|
||||
@@ -69,6 +78,12 @@ class Watcher {
|
||||
Watcher.log("tsc terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
if (plugin) {
|
||||
plugin.on("exit", (code) => {
|
||||
Watcher.log("plugin terminated unexpectedly")
|
||||
cleanup(code)
|
||||
})
|
||||
}
|
||||
const bundle = bundler.bundle().catch(() => {
|
||||
Watcher.log("parcel watcher terminated unexpectedly")
|
||||
cleanup(1)
|
||||
@@ -82,6 +97,9 @@ class Watcher {
|
||||
|
||||
vscode.stderr.on("data", (d) => process.stderr.write(d))
|
||||
tsc.stderr.on("data", (d) => process.stderr.write(d))
|
||||
if (plugin) {
|
||||
plugin.stderr.on("data", (d) => process.stderr.write(d))
|
||||
}
|
||||
|
||||
// From https://github.com/chalk/ansi-regex
|
||||
const pattern = [
|
||||
@@ -140,21 +158,34 @@ class Watcher {
|
||||
bundle.then(restartServer)
|
||||
}
|
||||
})
|
||||
|
||||
if (plugin) {
|
||||
onLine(plugin, (line, original) => {
|
||||
// tsc outputs blank lines; skip them.
|
||||
if (line !== "") {
|
||||
console.log("[plugin]", original)
|
||||
}
|
||||
if (line.includes("Watching for file changes")) {
|
||||
bundle.then(restartServer)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private createBundler(out = "dist"): Bundler {
|
||||
return new Bundler(
|
||||
[
|
||||
path.join(this.rootPath, "src/browser/pages/app.ts"),
|
||||
path.join(this.rootPath, "src/browser/register.ts"),
|
||||
path.join(this.rootPath, "src/browser/serviceWorker.ts"),
|
||||
path.join(this.rootPath, "src/browser/pages/login.ts"),
|
||||
path.join(this.rootPath, "src/browser/pages/vscode.ts"),
|
||||
],
|
||||
{
|
||||
outDir: path.join(this.rootPath, out),
|
||||
cacheDir: path.join(this.rootPath, ".cache"),
|
||||
minify: !!process.env.MINIFY,
|
||||
logLevel: 1,
|
||||
publicUrl: "/static/development/dist",
|
||||
publicUrl: ".",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
23
ci/helm-chart/.helmignore
Normal file
23
ci/helm-chart/.helmignore
Normal file
@@ -0,0 +1,23 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
23
ci/helm-chart/Chart.yaml
Normal file
23
ci/helm-chart/Chart.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
apiVersion: v2
|
||||
name: code-server
|
||||
description: A Helm chart for cdr/code-server
|
||||
|
||||
# A chart can be either an 'application' or a 'library' chart.
|
||||
#
|
||||
# Application charts are a collection of templates that can be packaged into versioned archives
|
||||
# to be deployed.
|
||||
#
|
||||
# Library charts provide useful utilities or functions for the chart developer. They're included as
|
||||
# a dependency of application charts to inject those utilities and functions into the rendering
|
||||
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
|
||||
type: application
|
||||
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 1.0.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
appVersion: 3.7.0
|
||||
117
ci/helm-chart/README.md
Normal file
117
ci/helm-chart/README.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# code-server
|
||||
|
||||
  
|
||||
|
||||
[code-server](https://github.com/cdr/code-server) code-server is VS Code running
|
||||
on a remote server, accessible through the browser.
|
||||
|
||||
This chart is community maintained by [@Matthew-Beckett](https://github.com/Matthew-Beckett) and [@alexgorbatchev](https://github.com/alexgorbatchev)
|
||||
|
||||
## TL;DR;
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/cdr/code-server
|
||||
$ cd code-server
|
||||
$ helm upgrade --install code-server ci/helm-chart
|
||||
```
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart bootstraps a code-server deployment on a
|
||||
[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh)
|
||||
package manager.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.6+
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `code-server`:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/cdr/code-server
|
||||
$ cd code-server
|
||||
$ helm upgrade --install code-server ci/helm-chart
|
||||
```
|
||||
|
||||
The command deploys code-server on the Kubernetes cluster in the default
|
||||
configuration. The [configuration](#configuration) section lists the parameters
|
||||
that can be configured during installation.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `code-server` deployment:
|
||||
|
||||
```console
|
||||
$ helm delete code-server
|
||||
```
|
||||
|
||||
The command removes all the Kubernetes components associated with the chart and
|
||||
deletes the release.
|
||||
|
||||
## Configuration
|
||||
|
||||
The following table lists the configurable parameters of the code-server chart
|
||||
and their default values.
|
||||
|
||||
## Values
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----|------|---------|-------------|
|
||||
| affinity | object | `{}` | |
|
||||
| extraArgs | list | `[]` | |
|
||||
| extraConfigmapMounts | list | `[]` | |
|
||||
| extraContainers | string | `""` | |
|
||||
| extraSecretMounts | list | `[]` | |
|
||||
| extraVars | list | `[]` | |
|
||||
| extraVolumeMounts | list | `[]` | |
|
||||
| fullnameOverride | string | `""` | |
|
||||
| hostnameOverride | string | `""` | |
|
||||
| image.pullPolicy | string | `"Always"` | |
|
||||
| image.repository | string | `"codercom/code-server"` | |
|
||||
| image.tag | string | `"3.7.0"` | |
|
||||
| imagePullSecrets | list | `[]` | |
|
||||
| ingress.enabled | bool | `false` | |
|
||||
| nameOverride | string | `""` | |
|
||||
| nodeSelector | object | `{}` | |
|
||||
| persistence.accessMode | string | `"ReadWriteOnce"` | |
|
||||
| persistence.annotations | object | `{}` | |
|
||||
| persistence.enabled | bool | `true` | |
|
||||
| persistence.size | string | `"1Gi"` | |
|
||||
| podAnnotations | object | `{}` | |
|
||||
| podSecurityContext | object | `{}` | |
|
||||
| replicaCount | int | `1` | |
|
||||
| resources | object | `{}` | |
|
||||
| securityContext.enabled | bool | `true` | |
|
||||
| securityContext.fsGroup | int | `1000` | |
|
||||
| securityContext.runAsUser | int | `1000` | |
|
||||
| service.port | int | `8443` | |
|
||||
| service.type | string | `"ClusterIP"` | |
|
||||
| serviceAccount.create | bool | `true` | |
|
||||
| serviceAccount.name | string | `nil` | |
|
||||
| tolerations | list | `[]` | |
|
||||
| volumePermissions.enabled | bool | `true` | |
|
||||
| volumePermissions.securityContext.runAsUser | int | `0` | |
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm
|
||||
install`. For example,
|
||||
|
||||
```console
|
||||
$ helm upgrade --install code-server \
|
||||
ci/helm-chart \
|
||||
--set persistence.enabled=false
|
||||
```
|
||||
|
||||
The above command sets the the persistence storage to false.
|
||||
|
||||
Alternatively, a YAML file that specifies the values for the above parameters
|
||||
can be provided while installing the chart. For example,
|
||||
|
||||
```console
|
||||
$ helm upgrade --install code-server ci/helm-chart -f values.yaml
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml)
|
||||
25
ci/helm-chart/templates/NOTES.txt
Normal file
25
ci/helm-chart/templates/NOTES.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "code-server.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "code-server.fullname" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
|
||||
echo http://$SERVICE_IP:{{ .Values.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl port-forward $POD_NAME 8080:80
|
||||
{{- end }}
|
||||
|
||||
Administrator credentials:
|
||||
|
||||
Password: echo $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "code-server.fullname" . }} -o jsonpath="{.data.password}" | base64 --decode)
|
||||
63
ci/helm-chart/templates/_helpers.tpl
Normal file
63
ci/helm-chart/templates/_helpers.tpl
Normal file
@@ -0,0 +1,63 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "code-server.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "code-server.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
||||
{{- if contains $name .Release.Name -}}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "code-server.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "code-server.labels" -}}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
{{ include "code-server.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "code-server.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "code-server.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
{{ default (include "code-server.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else -}}
|
||||
{{ default "default" .Values.serviceAccount.name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
152
ci/helm-chart/templates/deployment.yaml
Normal file
152
ci/helm-chart/templates/deployment.yaml
Normal file
@@ -0,0 +1,152 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "code-server.fullname" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.hostnameOverride }}
|
||||
hostname: {{ .Values.hostnameOverride }}
|
||||
{{- end }}
|
||||
{{- if .Values.securityContext.enabled }}
|
||||
securityContext:
|
||||
fsGroup: {{ .Values.securityContext.fsGroup }}
|
||||
{{- end }}
|
||||
{{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }}
|
||||
initContainers:
|
||||
- name: init-chmod-data
|
||||
image: busybox:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
chown -R {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /home/coder
|
||||
securityContext:
|
||||
runAsUser: {{ .Values.volumePermissions.securityContext.runAsUser }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /home/coder
|
||||
{{- end }}
|
||||
containers:
|
||||
{{- if .Values.extraContainers }}
|
||||
{{ toYaml .Values.extraContainers | indent 8}}
|
||||
{{- end }}
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
{{- if .Values.securityContext.enabled }}
|
||||
securityContext:
|
||||
runAsUser: {{ .Values.securityContext.runAsUser }}
|
||||
{{- end }}
|
||||
env:
|
||||
{{- if .Values.extraVars }}
|
||||
{{ toYaml .Values.extraVars | indent 10 }}
|
||||
{{- end }}
|
||||
- name: PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
{{- if .Values.existingSecret }}
|
||||
name: {{ .Values.existingSecret }}
|
||||
{{- else }}
|
||||
name: {{ template "code-server.fullname" . }}
|
||||
{{- end }}
|
||||
key: password
|
||||
{{- if .Values.extraArgs }}
|
||||
args:
|
||||
{{ toYaml .Values.extraArgs | indent 10 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /home/coder
|
||||
{{- range .Values.extraConfigmapMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- range .Values.extraSecretMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- range .Values.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ template "code-server.serviceAccountName" . }}
|
||||
volumes:
|
||||
- name: data
|
||||
{{- if .Values.persistence.enabled }}
|
||||
{{- if not .Values.persistence.hostPath }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim | default (include "code-server.fullname" .) }}
|
||||
{{- else }}
|
||||
hostPath:
|
||||
path: {{ .Values.persistence.hostPath }}
|
||||
type: Directory
|
||||
{{- end -}}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end -}}
|
||||
{{- range .Values.extraSecretMounts }}
|
||||
- name: {{ .name }}
|
||||
secret:
|
||||
secretName: {{ .secretName }}
|
||||
defaultMode: {{ .defaultMode }}
|
||||
{{- end }}
|
||||
{{- range .Values.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .existingClaim }}
|
||||
{{- else }}
|
||||
hostPath:
|
||||
path: {{ .hostPath }}
|
||||
type: Directory
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
41
ci/helm-chart/templates/ingress.yaml
Normal file
41
ci/helm-chart/templates/ingress.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "code-server.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
{{- else -}}
|
||||
apiVersion: extensions/v1beta1
|
||||
{{- end }}
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "code-server.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ . }}
|
||||
backend:
|
||||
serviceName: {{ $fullName }}
|
||||
servicePort: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
29
ci/helm-chart/templates/pvc.yaml
Normal file
29
ci/helm-chart/templates/pvc.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
{{- if and (and .Values.persistence.enabled (not .Values.persistence.existingClaim)) (not .Values.persistence.hostPath) }}
|
||||
kind: PersistentVolumeClaim
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ include "code-server.fullname" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
{{- with .Values.persistence.annotations }}
|
||||
annotations:
|
||||
{{ toYaml . | indent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode | quote }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size | quote }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: "{{ .Values.persistence.storageClass }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
18
ci/helm-chart/templates/secrets.yaml
Normal file
18
ci/helm-chart/templates/secrets.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "code-server.fullname" . }}
|
||||
annotations:
|
||||
"helm.sh/hook": "pre-install"
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
type: Opaque
|
||||
data:
|
||||
{{ if .Values.password }}
|
||||
password: "{{ .Values.password | b64enc }}"
|
||||
{{ else }}
|
||||
password: "{{ randAlphaNum 24 | b64enc }}"
|
||||
{{ end }}
|
||||
19
ci/helm-chart/templates/service.yaml
Normal file
19
ci/helm-chart/templates/service.yaml
Normal file
@@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "code-server.fullname" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
11
ci/helm-chart/templates/serviceaccount.yaml
Normal file
11
ci/helm-chart/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
{{- if or .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ template "code-server.serviceAccountName" . }}
|
||||
{{- end -}}
|
||||
18
ci/helm-chart/templates/tests/test-connection.yaml
Normal file
18
ci/helm-chart/templates/tests/test-connection.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: "{{ include "code-server.fullname" . }}-test-connection"
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "code-server.name" . }}
|
||||
helm.sh/chart: {{ include "code-server.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
annotations:
|
||||
"helm.sh/hook": test-success
|
||||
spec:
|
||||
containers:
|
||||
- name: wget
|
||||
image: busybox
|
||||
command: ['wget']
|
||||
args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}']
|
||||
restartPolicy: Never
|
||||
163
ci/helm-chart/values.yaml
Normal file
163
ci/helm-chart/values.yaml
Normal file
@@ -0,0 +1,163 @@
|
||||
# Default values for code-server.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: codercom/code-server
|
||||
tag: '3.7.0'
|
||||
pullPolicy: Always
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
hostnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
# Specifies whether a service account should be created
|
||||
create: true
|
||||
# Annotations to add to the service account
|
||||
annotations: {}
|
||||
# The name of the service account to use.
|
||||
# If not set and create is true, a name is generated using the fullname template
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
|
||||
podSecurityContext: {}
|
||||
# fsGroup: 2000
|
||||
|
||||
securityContext: {}
|
||||
# capabilities:
|
||||
# drop:
|
||||
# - ALL
|
||||
# readOnlyRootFilesystem: true
|
||||
# runAsNonRoot: true
|
||||
# runAsUser: 1000
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
#annotations:
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# kubernetes.io/tls-acme: "true"
|
||||
#hosts:
|
||||
# - host: code-server.example.loc
|
||||
# paths:
|
||||
# - /
|
||||
|
||||
#tls:
|
||||
# - secretName: code-server
|
||||
# hosts:
|
||||
# - code-server.example.loc
|
||||
|
||||
# Optional additional arguments
|
||||
extraArgs: []
|
||||
# - --allow-http
|
||||
# - --no-auth
|
||||
|
||||
# Optional additional environment variables
|
||||
extraVars: []
|
||||
# - name: DISABLE_TELEMETRY
|
||||
# value: true
|
||||
|
||||
##
|
||||
## Init containers parameters:
|
||||
## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup
|
||||
##
|
||||
volumePermissions:
|
||||
enabled: true
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
|
||||
## Pod Security Context
|
||||
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
|
||||
##
|
||||
securityContext:
|
||||
enabled: true
|
||||
fsGroup: 1000
|
||||
runAsUser: 1000
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
# resources, such as Minikube. If you do want to specify resources, uncomment the following
|
||||
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
|
||||
# limits:
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
# requests:
|
||||
# cpu: 100m
|
||||
# memory: 1000Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
## Persist data to a persistent volume
|
||||
persistence:
|
||||
enabled: true
|
||||
## code-server data Persistent Volume Storage Class
|
||||
## If defined, storageClassName: <storageClass>
|
||||
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||
## If undefined (the default) or set to null, no storageClassName spec is
|
||||
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||
## GKE, AWS & OpenStack)
|
||||
##
|
||||
# storageClass: "-"
|
||||
accessMode: ReadWriteOnce
|
||||
size: 10Gi
|
||||
annotations: {}
|
||||
# existingClaim: ""
|
||||
# hostPath: /data
|
||||
|
||||
serviceAccount:
|
||||
create: true
|
||||
name:
|
||||
|
||||
## Enable an Specify container in extraContainers.
|
||||
## This is meant to allow adding code-server dependencies, like docker-dind.
|
||||
extraContainers: |
|
||||
#- name: docker-dind
|
||||
# image: docker:19.03-dind
|
||||
# imagePullPolicy: IfNotPresent
|
||||
# resources:
|
||||
# requests:
|
||||
# cpu: 250m
|
||||
# memory: 256M
|
||||
# securityContext:
|
||||
# privileged: true
|
||||
# procMount: Default
|
||||
# env:
|
||||
# - name: DOCKER_TLS_CERTDIR
|
||||
# value: ""
|
||||
# - name: DOCKER_DRIVER
|
||||
# value: "overlay2"
|
||||
|
||||
## Additional code-server secret mounts
|
||||
extraSecretMounts: []
|
||||
# - name: secret-files
|
||||
# mountPath: /etc/secrets
|
||||
# secretName: code-server-secret-files
|
||||
# readOnly: true
|
||||
|
||||
## Additional code-server volume mounts
|
||||
extraVolumeMounts: []
|
||||
# - name: extra-volume
|
||||
# mountPath: /mnt/volume
|
||||
# readOnly: true
|
||||
# existingClaim: volume-claim
|
||||
# hostPath: ""
|
||||
|
||||
extraConfigmapMounts: []
|
||||
# - name: certs-configmap
|
||||
# mountPath: /etc/code-server/ssl/
|
||||
# subPath: certificates.crt # (optional)
|
||||
# configMap: certs-configmap
|
||||
# readOnly: true
|
||||
32
ci/images/centos7/Dockerfile
Normal file
32
ci/images/centos7/Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM centos:7
|
||||
|
||||
ARG NODE_VERSION=v12.18.4
|
||||
RUN ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')" && \
|
||||
curl -fsSL "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-$ARCH.tar.xz" | tar -C /usr/local -xJ && \
|
||||
mv "/usr/local/node-$NODE_VERSION-linux-$ARCH" "/usr/local/node-$NODE_VERSION"
|
||||
ENV PATH=/usr/local/node-$NODE_VERSION/bin:$PATH
|
||||
RUN npm install -g yarn
|
||||
|
||||
RUN yum groupinstall -y 'Development Tools'
|
||||
RUN yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel
|
||||
|
||||
RUN npm config set python python2
|
||||
|
||||
RUN yum install -y epel-release && yum install -y jq
|
||||
RUN yum install -y rsync
|
||||
|
||||
# Copied from ../debian10/Dockerfile
|
||||
# Install Go.
|
||||
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
|
||||
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
|
||||
ENV GOPATH=/gopath
|
||||
# Ensures running this image as another user works.
|
||||
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
|
||||
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
|
||||
|
||||
# Install Go dependencies
|
||||
ENV GO111MODULE=on
|
||||
RUN go get mvdan.cc/sh/v3/cmd/shfmt
|
||||
RUN go get github.com/goreleaser/nfpm/cmd/nfpm
|
||||
|
||||
RUN curl -fsSL https://get.docker.com | sh
|
||||
54
ci/images/debian10/Dockerfile
Normal file
54
ci/images/debian10/Dockerfile
Normal file
@@ -0,0 +1,54 @@
|
||||
FROM debian:10
|
||||
|
||||
RUN apt-get update
|
||||
|
||||
# Needed for debian repositories added below.
|
||||
RUN apt-get install -y curl gnupg
|
||||
|
||||
# Installs node.
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_12.x | bash - && \
|
||||
apt-get install -y nodejs
|
||||
|
||||
# Installs yarn.
|
||||
RUN curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
|
||||
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
|
||||
apt-get update && apt-get install -y yarn
|
||||
|
||||
# Installs VS Code build deps.
|
||||
RUN apt-get install -y build-essential \
|
||||
libsecret-1-dev \
|
||||
libx11-dev \
|
||||
libxkbfile-dev
|
||||
|
||||
# Installs envsubst.
|
||||
RUN apt-get install -y gettext-base
|
||||
|
||||
# Misc build dependencies.
|
||||
RUN apt-get install -y git rsync unzip jq
|
||||
|
||||
# Installs shellcheck.
|
||||
RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.7.1/shellcheck-v0.7.1.linux.$(uname -m).tar.xz | \
|
||||
tar -xJ && \
|
||||
mv shellcheck*/shellcheck /usr/local/bin && \
|
||||
rm -R shellcheck*
|
||||
|
||||
# Install Go.
|
||||
RUN ARCH="$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')" && \
|
||||
curl -fsSL "https://dl.google.com/go/go1.14.3.linux-$ARCH.tar.gz" | tar -C /usr/local -xz
|
||||
ENV GOPATH=/gopath
|
||||
# Ensures running this image as another user works.
|
||||
RUN mkdir -p $GOPATH && chmod -R 777 $GOPATH
|
||||
ENV PATH=/usr/local/go/bin:$GOPATH/bin:$PATH
|
||||
|
||||
# Install Go dependencies
|
||||
ENV GO111MODULE=on
|
||||
RUN go get mvdan.cc/sh/v3/cmd/shfmt
|
||||
RUN go get github.com/goreleaser/nfpm/cmd/nfpm
|
||||
|
||||
RUN VERSION="$(curl -fsSL https://storage.googleapis.com/kubernetes-release/release/stable.txt)" && \
|
||||
curl -fsSL "https://storage.googleapis.com/kubernetes-release/release/$VERSION/bin/linux/amd64/kubectl" > /usr/local/bin/kubectl \
|
||||
&& chmod +x /usr/local/bin/kubectl
|
||||
RUN curl -fsSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||
RUN helm plugin install https://github.com/instrumenta/helm-kubeval
|
||||
|
||||
RUN curl -fsSL https://get.docker.com | sh
|
||||
@@ -56,14 +56,14 @@ curl() {
|
||||
# This will contain the artifacts we want.
|
||||
# https://developer.github.com/v3/actions/workflow-runs/#list-workflow-runs
|
||||
get_artifacts_url() {
|
||||
curl -sSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
|
||||
curl -fsSL 'https://api.github.com/repos/cdr/code-server/actions/workflows/ci.yaml/runs?status=success&event=push' | jq -r ".workflow_runs[] | select(.head_sha == \"$(git rev-parse HEAD)\") | .artifacts_url" | head -n 1
|
||||
}
|
||||
|
||||
# Grabs the artifact's download url.
|
||||
# https://developer.github.com/v3/actions/artifacts/#list-workflow-run-artifacts
|
||||
get_artifact_url() {
|
||||
local artifact_name="$1"
|
||||
curl -sSL "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
|
||||
curl -fsSL "$(get_artifacts_url)" | jq -r ".artifacts[] | select(.name == \"$artifact_name\") | .archive_download_url" | head -n 1
|
||||
}
|
||||
|
||||
# Uses the above two functions to download a artifact into a directory.
|
||||
@@ -74,7 +74,7 @@ download_artifact() {
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp)"
|
||||
|
||||
curl -sSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
|
||||
curl -fsSL "$(get_artifact_url "$artifact_name")" > "$tmp_file"
|
||||
unzip -q -o "$tmp_file" -d "$dst"
|
||||
rm "$tmp_file"
|
||||
}
|
||||
|
||||
@@ -28,16 +28,21 @@ RUN adduser --gecos '' --disabled-password coder && \
|
||||
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||
|
||||
RUN ARCH="$(dpkg --print-architecture)" && \
|
||||
curl -sSL "https://github.com/boxboat/fixuid/releases/download/v0.4.1/fixuid-0.4.1-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
|
||||
curl -fsSL "https://github.com/boxboat/fixuid/releases/download/v0.4.1/fixuid-0.4.1-linux-$ARCH.tar.gz" | tar -C /usr/local/bin -xzf - && \
|
||||
chown root:root /usr/local/bin/fixuid && \
|
||||
chmod 4755 /usr/local/bin/fixuid && \
|
||||
mkdir -p /etc/fixuid && \
|
||||
printf "user: coder\ngroup: coder\n" > /etc/fixuid/config.yml
|
||||
|
||||
COPY release-packages/code-server*.deb /tmp/
|
||||
COPY ci/release-image/entrypoint.sh /usr/bin/entrypoint.sh
|
||||
RUN dpkg -i /tmp/code-server*$(dpkg --print-architecture).deb && rm /tmp/code-server*.deb
|
||||
|
||||
EXPOSE 8080
|
||||
USER coder
|
||||
# This way, if someone sets $DOCKER_USER, docker-exec will still work as
|
||||
# the uid will remain the same. note: only relevant if -u isn't passed to
|
||||
# docker-run.
|
||||
USER 1000
|
||||
ENV USER=coder
|
||||
WORKDIR /home/coder
|
||||
ENTRYPOINT ["dumb-init", "fixuid", "-q", "/usr/bin/code-server", "--bind-addr", "0.0.0.0:8080", "."]
|
||||
ENTRYPOINT ["/usr/bin/entrypoint.sh", "--bind-addr", "0.0.0.0:8080", "."]
|
||||
@@ -5,7 +5,7 @@ main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-container/Dockerfile .
|
||||
docker build -t "codercom/code-server-$ARCH:$VERSION" -f ./ci/release-image/Dockerfile .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
20
ci/release-image/entrypoint.sh
Executable file
20
ci/release-image/entrypoint.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
# We do this first to ensure sudo works below when renaming the user.
|
||||
# Otherwise the current container UID may not exist in the passwd database.
|
||||
eval "$(fixuid -q)"
|
||||
|
||||
if [ "${DOCKER_USER-}" ]; then
|
||||
echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers.d/nopasswd > /dev/null
|
||||
# Unfortunately we cannot change $HOME as we cannot move any bind mounts
|
||||
# nor can we bind mount $HOME into a new home as that requires a privileged container.
|
||||
sudo usermod --login "$DOCKER_USER" coder
|
||||
sudo groupmod -n "$DOCKER_USER" coder
|
||||
|
||||
USER="$DOCKER_USER"
|
||||
|
||||
sudo sed -i "/coder/d" /etc/sudoers.d/nopasswd
|
||||
fi
|
||||
|
||||
dumb-init /usr/bin/code-server "$@"
|
||||
@@ -5,7 +5,7 @@ main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
source ./ci/lib.sh
|
||||
|
||||
./ci/release-container/build.sh
|
||||
./ci/release-image/build.sh
|
||||
|
||||
mkdir -p release-images
|
||||
docker save "codercom/code-server-$ARCH:$VERSION" > "release-images/code-server-$ARCH-$VERSION.tar"
|
||||
|
||||
@@ -9,9 +9,9 @@ main() {
|
||||
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
|
||||
fi
|
||||
|
||||
download_artifact npm-package ./release
|
||||
download_artifact npm-package ./release-npm-package
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
chmod +x $(grep -rl '^#!/.*' release)
|
||||
tar -xzf release-npm-package/package.tar.gz
|
||||
yarn publish --non-interactive release
|
||||
}
|
||||
|
||||
|
||||
21
ci/steps/release-packages.sh
Executable file
21
ci/steps/release-packages.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
NODE_VERSION=v12.18.4
|
||||
NODE_OS="$(uname | tr '[:upper:]' '[:lower:]')"
|
||||
NODE_ARCH="$(uname -m | sed 's/86_64/64/; s/aarch64/arm64/')"
|
||||
curl -L "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH.tar.gz" | tar -xz
|
||||
PATH="$PWD/node-$NODE_VERSION-$NODE_OS-$NODE_ARCH/bin:$PATH"
|
||||
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
tar -xzf release-npm-package/package.tar.gz
|
||||
|
||||
yarn release:standalone
|
||||
yarn test:standalone-release
|
||||
yarn package
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
chmod +x $(grep -rl '^#!/.*' release)
|
||||
|
||||
yarn release:static
|
||||
yarn test:static-release
|
||||
yarn package
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -9,6 +9,10 @@ main() {
|
||||
yarn build
|
||||
yarn build:vscode
|
||||
yarn release
|
||||
|
||||
# https://github.com/actions/upload-artifact/issues/38
|
||||
mkdir -p release-npm-package
|
||||
tar -czf release-npm-package/package.tar.gz release
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -1,16 +1,41 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
# Contributing
|
||||
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Requirements](#requirements)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Build](#build)
|
||||
- [Structure](#structure)
|
||||
- [VS Code Patch](#vs-code-patch)
|
||||
- [Currently Known Issues](#currently-known-issues)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
- [Detailed CI and build process docs](../ci)
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Please create a [GitHub Issue](https://github.com/cdr/code-server/issues) for each issue
|
||||
you'd like to address unless the proposed fix is minor.
|
||||
|
||||
In your Pull Requests (PR), link to the issue that the PR solves.
|
||||
|
||||
Please ensure that the base of your PR is the **master** branch. (Note: The default
|
||||
GitHub branch is the latest release branch, though you should point all of your changes to be merged into
|
||||
master).
|
||||
|
||||
## Requirements
|
||||
|
||||
Please refer to [VS Code's prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||
The prerequisites for contributing to code-server are almost the same as those for
|
||||
[VS Code](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites).
|
||||
There are several differences, however. You must:
|
||||
|
||||
Differences:
|
||||
- Use Node.js version 12.x (or greater)
|
||||
- Have [nfpm](https://github.com/goreleaser/nfpm) (which is used to build `.deb` and `.rpm` packages and [jq](https://stedolan.github.io/jq/) (used to build code-server releases) installed
|
||||
|
||||
- We require a minimum of node v12 but later versions should work.
|
||||
- We use [fnpm](https://github.com/goreleaser/nfpm) to build `.deb` and `.rpm` packages.
|
||||
- The [CI container](../ci/container/Dockerfile) is a useful reference for all our dependencies.
|
||||
The [CI container](../ci/images/debian8/Dockerfile) is a useful reference for all
|
||||
of the dependencies code-server uses.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
@@ -18,100 +43,120 @@ Differences:
|
||||
yarn
|
||||
yarn vscode
|
||||
yarn watch
|
||||
# Visit http://localhost:8080 once the build completed.
|
||||
# Visit http://localhost:8080 once the build is completed.
|
||||
```
|
||||
|
||||
To develop inside of an isolated docker container:
|
||||
To develop inside an isolated Docker container:
|
||||
|
||||
```shell
|
||||
./ci/dev/container/exec.sh
|
||||
|
||||
root@12345:/code-server# yarn
|
||||
root@12345:/code-server# yarn vscode
|
||||
root@12345:/code-server# yarn watch
|
||||
./ci/dev/image/run.sh yarn
|
||||
./ci/dev/image/run.sh yarn vscode
|
||||
./ci/dev/image/run.sh yarn watch
|
||||
```
|
||||
|
||||
Any changes made to the source will be live reloaded.
|
||||
`yarn watch` will live reload changes to the source.
|
||||
|
||||
If changes are made to the patch and you've built previously you must manually
|
||||
reset VS Code then run `yarn vscode:patch`.
|
||||
If you introduce changes to the patch and you've previously built, you
|
||||
must (1) manually reset VS Code and (2) run `yarn vscode:patch`.
|
||||
|
||||
## Build
|
||||
|
||||
You can build using:
|
||||
|
||||
```shell
|
||||
./ci/dev/image/run.sh ./ci/steps/release.sh
|
||||
```
|
||||
|
||||
Run your build with:
|
||||
|
||||
```shell
|
||||
cd release
|
||||
yarn --production
|
||||
# Runs the built JavaScript with Node.
|
||||
node .
|
||||
```
|
||||
|
||||
Build the release packages (make sure that you run `./ci/steps/release.sh` first):
|
||||
|
||||
```shell
|
||||
IMAGE=centos7 ./ci/dev/image/run.sh ./ci/steps/release-packages.sh
|
||||
# The standalone release is in ./release-standalone
|
||||
# .deb, .rpm and the standalone archive are in ./release-packages
|
||||
```
|
||||
|
||||
The `release.sh` script is equal to running:
|
||||
|
||||
```shell
|
||||
yarn
|
||||
yarn vscode
|
||||
yarn build
|
||||
yarn build:vscode
|
||||
yarn release
|
||||
cd release
|
||||
yarn --production
|
||||
# Runs the built JavaScript with Node.
|
||||
node .
|
||||
```
|
||||
|
||||
Now you can make it static and build packages with:
|
||||
And `release-packages.sh` is equal to:
|
||||
|
||||
```
|
||||
yarn release:static
|
||||
yarn test:static-release
|
||||
```shell
|
||||
yarn release:standalone
|
||||
yarn test:standalone-release
|
||||
yarn package
|
||||
# The static release is in ./release-static
|
||||
# .deb, .rpm and the static archive are in ./release-packages
|
||||
```
|
||||
|
||||
For a faster release build, you can run instead:
|
||||
|
||||
```shell
|
||||
KEEP_MODULES=1 ./ci/steps/release.sh
|
||||
node ./release
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
The `code-server` script serves an HTTP API to login and start a remote VS Code process.
|
||||
The `code-server` script serves an HTTP API for login and starting a remote VS Code process.
|
||||
|
||||
The CLI code is in [./src/node](./src/node) and the HTTP routes are implemented in
|
||||
[./src/node/app](./src/node/app).
|
||||
|
||||
Most of the meaty parts are in our VS Code patch which is described next.
|
||||
Most of the meaty parts are in the VS Code patch, which we described next.
|
||||
|
||||
### VS Code Patch
|
||||
|
||||
Back in v1 of code-server, we had an extensive patch of VS Code that split the codebase
|
||||
into a frontend and server. The frontend consisted of all UI code and the server ran
|
||||
the extensions and exposed an API to the frontend for file access and everything else
|
||||
that the UI needed.
|
||||
In v1 of code-server, we had a patch of VS Code that split the codebase into a front-end
|
||||
and a server. The front-end consisted of all UI code, while the server ran the extensions
|
||||
and exposed an API to the front-end for file access and all UI needs.
|
||||
|
||||
This worked but eventually Microsoft added support to VS Code to run it in the web.
|
||||
They have open sourced the frontend but have kept the server closed source.
|
||||
|
||||
So in interest of piggy backing off their work, v2 and beyond use the VS Code
|
||||
web frontend and fill in the server. This is contained in our
|
||||
Over time, Microsoft added support to VS Code to run it on the web. They have made
|
||||
the front-end open source, but not the server. As such, code-server v2 (and later) uses
|
||||
the VS Code front-end and implements the server. You can find this in
|
||||
[./ci/dev/vscode.patch](../ci/dev/vscode.patch) under the path `src/vs/server`.
|
||||
|
||||
Other notable changes in our patch include:
|
||||
|
||||
- Add our own build file which includes our code and VS Code's web code.
|
||||
- Allow multiple extension directories (both user and built-in).
|
||||
- Modify the loader, websocket, webview, service worker, and asset requests to
|
||||
use the URL of the page as a base (and TLS if necessary for the websocket).
|
||||
- Send client-side telemetry through the server.
|
||||
- Allow modification of the display language.
|
||||
- Make it possible for us to load code on the client.
|
||||
- Make extensions work in the browser.
|
||||
- Make it possible to install extensions of any kind.
|
||||
- Fix getting permanently disconnected when you sleep or hibernate for a while.
|
||||
- Add connection type to web socket query parameters.
|
||||
- Adding our build file, which includes our code and VS Code's web code
|
||||
- Allowing multiple extension directories (both user and built-in)
|
||||
- Modifying the loader, websocket, webview, service worker, and asset requests to
|
||||
use the URL of the page as a base (and TLS, if necessary for the websocket)
|
||||
- Sending client-side telemetry through the server
|
||||
- Allowing modification of the display language
|
||||
- Making it possible for us to load code on the client
|
||||
- Making extensions work in the browser
|
||||
- Making it possible to install extensions of any kind
|
||||
- Fixing issue with getting disconnected when your machine sleeps or hibernates
|
||||
- Adding connection type to web socket query parameters
|
||||
|
||||
Some known issues presently:
|
||||
|
||||
- Creating custom VS Code extensions and debugging them doesn't work.
|
||||
- Extension profiling and tips are currently disabled.
|
||||
|
||||
As the web portion of VS Code matures, we'll be able to shrink and maybe even entirely
|
||||
eliminate our patch. In the meantime, however, upgrading the VS Code version requires
|
||||
ensuring that the patch still applies and has the intended effects.
|
||||
|
||||
To generate a new patch run `yarn vscode:diff`.
|
||||
|
||||
**note**: We have extension docs on the CI and build system at [./ci/README.md](../ci/README.md)
|
||||
|
||||
If functionality doesn't depend on code from VS Code then it should be moved
|
||||
into code-server otherwise it should be in the patch.
|
||||
|
||||
In the future we'd like to run VS Code unit tests against our builds to ensure features
|
||||
As the web portion of VS Code matures, we'll be able to shrink and possibly
|
||||
eliminate our patch. In the meantime, upgrading the VS Code version requires
|
||||
us to ensure that the patch is applied and works as intended. In the future,
|
||||
we'd like to run VS Code unit tests against our builds to ensure that features
|
||||
work as expected.
|
||||
|
||||
To generate a new patch, run `yarn vscode:diff`
|
||||
|
||||
**Note**: We have [extension docs](../ci/README.md) on the CI and build system.
|
||||
|
||||
If the functionality you're working on does NOT depend on code from VS Code, please
|
||||
move it out and into code-server.
|
||||
|
||||
### Currently Known Issues
|
||||
|
||||
- Creating custom VS Code extensions and debugging them doesn't work
|
||||
- Extension profiling and tips are currently disabled
|
||||
|
||||
197
doc/FAQ.md
197
doc/FAQ.md
@@ -3,48 +3,79 @@
|
||||
# FAQ
|
||||
|
||||
- [Questions?](#questions)
|
||||
- [What's the deal with extensions?](#whats-the-deal-with-extensions)
|
||||
- [iPad Status?](#ipad-status)
|
||||
- [How can I reuse my VS Code configuration?](#how-can-i-reuse-my-vs-code-configuration)
|
||||
- [Differences compared to VS Code?](#differences-compared-to-vs-code)
|
||||
- [How can I request a missing extension?](#how-can-i-request-a-missing-extension)
|
||||
- [How do I configure the marketplace URL?](#how-do-i-configure-the-marketplace-url)
|
||||
- [Where are extensions stored?](#where-are-extensions-stored)
|
||||
- [How is this different from VS Code Codespaces?](#how-is-this-different-from-vs-code-codespaces)
|
||||
- [How should I expose code-server to the internet?](#how-should-i-expose-code-server-to-the-internet)
|
||||
- [How do I securely access web services?](#how-do-i-securely-access-web-services)
|
||||
- [Sub-domains](#sub-domains)
|
||||
- [Sub-paths](#sub-paths)
|
||||
- [Sub-domains](#sub-domains)
|
||||
- [Multi-tenancy](#multi-tenancy)
|
||||
- [Docker in code-server docker container?](#docker-in-code-server-docker-container)
|
||||
- [Collaboration](#collaboration)
|
||||
- [Docker in code-server container?](#docker-in-code-server-container)
|
||||
- [How can I disable telemetry?](#how-can-i-disable-telemetry)
|
||||
- [How does code-server decide what workspace or folder to open?](#how-does-code-server-decide-what-workspace-or-folder-to-open)
|
||||
- [How do I debug issues with code-server?](#how-do-i-debug-issues-with-code-server)
|
||||
- [Heartbeat file](#heartbeat-file)
|
||||
- [Heartbeat File](#heartbeat-file)
|
||||
- [Healthz endpoint](#healthz-endpoint)
|
||||
- [How does the config file work?](#how-does-the-config-file-work)
|
||||
- [Isn't an install script piped into sh insecure?](#isnt-an-install-script-piped-into-sh-insecure)
|
||||
- [How do I make my keyboard shortcuts work?](#how-do-i-make-my-keyboard-shortcuts-work)
|
||||
- [Differences compared to Theia?](#differences-compared-to-theia)
|
||||
- [Enterprise](#enterprise)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## Questions?
|
||||
|
||||
Please file all questions and support requests at https://www.reddit.com/r/codeserver/.
|
||||
Please file all questions and support requests at https://github.com/cdr/code-server/discussions.
|
||||
|
||||
The issue tracker is **only** for bugs.
|
||||
## iPad Status?
|
||||
|
||||
## What's the deal with extensions?
|
||||
Please see [./ipad.md](./ipad.md).
|
||||
|
||||
Unfortunately, the Microsoft VS Code Marketplace license prohibits use with any non Microsoft
|
||||
product.
|
||||
## How can I reuse my VS Code configuration?
|
||||
|
||||
See https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf
|
||||
The very popular [Settings Sync](https://marketplace.visualstudio.com/items?itemName=Shan.code-settings-sync) extension works.
|
||||
|
||||
You can also pass `--user-data-dir ~/.vscode` to reuse your existing VS Code extensions and configuration.
|
||||
|
||||
Or copy `~/.vscode` into `~/.local/share/code-server`.
|
||||
|
||||
## Differences compared to VS Code?
|
||||
|
||||
`code-server` takes the open source core of VS Code and allows you to run it in the browser.
|
||||
However, it is not entirely equivalent to Microsoft's VS Code.
|
||||
|
||||
While the core of VS Code is open source, the marketplace and many published Microsoft extensions are not.
|
||||
|
||||
Furthermore, Microsoft prohibits the use of any non-Microsoft VS Code from accessing their marketplace.
|
||||
|
||||
See the [TOS](https://cdn.vsassets.io/v/M146_20190123.39/_content/Microsoft-Visual-Studio-Marketplace-Terms-of-Use.pdf).
|
||||
|
||||
> Marketplace Offerings are intended for use only with Visual Studio Products and Services
|
||||
> and you may only install and use Marketplace Offerings with Visual Studio Products and Services.
|
||||
|
||||
As a result, Coder has created its own marketplace for open source extensions. It works by scraping
|
||||
GitHub for VS Code extensions and building them. It's not perfect but getting better by the day with
|
||||
more and more extensions.
|
||||
As a result, we cannot offer any extensions on the Microsoft marketplace. Instead,
|
||||
we have created our own marketplace for open source extensions.
|
||||
It works by scraping GitHub for VS Code extensions and building them. It's not perfect but getting
|
||||
better by the day with more and more extensions.
|
||||
|
||||
Issue [#1299](https://github.com/cdr/code-server/issues/1299) is a big one in making the experience here
|
||||
better by allowing the community to submit extensions and repos to avoid waiting until the scraper finds
|
||||
an extension.
|
||||
These are the closed source extensions presently unavailable:
|
||||
|
||||
1. [Live Share](https://visualstudio.microsoft.com/services/live-share)
|
||||
- We may implement something similar, see [#33](https://github.com/cdr/code-server/issues/33)
|
||||
1. [Remote Extensions (SSH, Containers, WSL)](https://github.com/microsoft/vscode-remote-release)
|
||||
- We may reimplement these at some point, see [#1315](https://github.com/cdr/code-server/issues/1315)
|
||||
|
||||
For more about the closed source parts of VS Code, see [vscodium/vscodium](https://github.com/VSCodium/vscodium#why-does-this-exist).
|
||||
|
||||
## How can I request a missing extension?
|
||||
|
||||
Please open a new issue and select the `Extension request` template.
|
||||
|
||||
If an extension is not available or does not work, you can grab its VSIX from its Github releases or
|
||||
build it yourself. Then run the `Extensions: Install from VSIX` command in the Command Palette and
|
||||
@@ -52,10 +83,26 @@ point to the .vsix file.
|
||||
|
||||
See below for installing an extension from the cli.
|
||||
|
||||
Feel free to file an issue to add a missing extension to the marketplace.
|
||||
## How do I configure the marketplace URL?
|
||||
|
||||
If you have your own custom marketplace, it is possible to point code-server to it by setting
|
||||
`$SERVICE_URL` and `$ITEM_URL` to point to it.
|
||||
If you have your own marketplace that implements the VS Code Extension Gallery API, it is possible to
|
||||
point code-server to it by setting `$SERVICE_URL` and `$ITEM_URL`. These correspond directly
|
||||
to `serviceUrl` and `itemUrl` in VS Code's `product.json`.
|
||||
|
||||
e.g. to use [open-vsx.org](https://open-vsx.org):
|
||||
|
||||
```bash
|
||||
export SERVICE_URL=https://open-vsx.org/vscode/gallery
|
||||
export ITEM_URL=https://open-vsx.org/vscode/item
|
||||
```
|
||||
|
||||
While you can technically use Microsoft's marketplace with these, please do not do so as it
|
||||
is against their terms of use. See [above](#differences-compared-to-vs-code) and this
|
||||
discussion regarding the use of the Microsoft URLs in forks:
|
||||
|
||||
https://github.com/microsoft/vscode/issues/31168#issue-244533026
|
||||
|
||||
These variables are most valuable to our enterprise customers for whom we have a self hosted marketplace product.
|
||||
|
||||
## Where are extensions stored?
|
||||
|
||||
@@ -79,11 +126,11 @@ code-server --install-extension downloaded-ms-python.python.vsix
|
||||
VS Code Codespaces is a closed source and paid service by Microsoft. It also allows you to access
|
||||
VS Code via the browser.
|
||||
|
||||
However, code-server is free, open source and can be ran on any machine without any limitations.
|
||||
However, code-server is free, open source and can be run on any machine without any limitations.
|
||||
|
||||
While you can self host environments with VS Code Codespaces, you still need to an Azure billing
|
||||
account and you access VS Code via the Codespaces web dashboard instead of directly connecting to
|
||||
your instance.
|
||||
While you can self host environments with VS Code Codespaces, you still need an Azure billing
|
||||
account and you have to access VS Code via the Codespaces web dashboard instead of directly
|
||||
connecting to your instance.
|
||||
|
||||
## How should I expose code-server to the internet?
|
||||
|
||||
@@ -94,20 +141,23 @@ code-server only supports password authentication natively.
|
||||
**note**: code-server will rate limit password authentication attempts at 2 a minute and 12 an hour.
|
||||
|
||||
If you want to use external authentication (i.e sign in with Google) you should handle this
|
||||
with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy).
|
||||
with a reverse proxy using something like [oauth2_proxy](https://github.com/pusher/oauth2_proxy)
|
||||
or [Cloudflare Access](https://teams.cloudflare.com/access).
|
||||
|
||||
For HTTPS, you can use a self signed certificate by passing in just `--cert` or
|
||||
pass in an existing certificate by providing the path to `--cert` and the path to
|
||||
its key with `--cert-key`.
|
||||
the key with `--cert-key`.
|
||||
|
||||
The self signed certificate will be generated into
|
||||
`~/.local/share/code-server/self-signed.crt`.
|
||||
|
||||
If `code-server` has been passed a certificate it will also respond to HTTPS
|
||||
requests and will redirect all HTTP requests to HTTPS. Otherwise it will respond
|
||||
only to HTTP requests.
|
||||
requests and will redirect all HTTP requests to HTTPS.
|
||||
|
||||
You can use [Let's Encrypt](https://letsencrypt.org/) to get an SSL certificate
|
||||
You can use [Let's Encrypt](https://letsencrypt.org/) to get a TLS certificate
|
||||
for free.
|
||||
|
||||
Again, Please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
|
||||
Again, please follow [./guide.md](./guide.md) for our recommendations on setting up and using code-server.
|
||||
|
||||
## How do I securely access web services?
|
||||
|
||||
@@ -115,6 +165,10 @@ code-server is capable of proxying to any port using either a subdomain or a
|
||||
subpath which means you can securely access these services using code-server's
|
||||
built-in authentication.
|
||||
|
||||
### Sub-paths
|
||||
|
||||
Just browse to `/proxy/<port>/`.
|
||||
|
||||
### Sub-domains
|
||||
|
||||
You will need a DNS entry that points to your server for each port you want to
|
||||
@@ -134,35 +188,22 @@ code-server --proxy-domain <domain>
|
||||
Now you can browse to `<port>.<domain>`. Note that this uses the host header so
|
||||
ensure your reverse proxy forwards that information if you are using one.
|
||||
|
||||
### Sub-paths
|
||||
|
||||
Just browse to `/proxy/<port>/`.
|
||||
|
||||
## Multi-tenancy
|
||||
|
||||
If you want to run multiple code-server's on shared infrastructure, we recommend using virtual
|
||||
If you want to run multiple code-servers on shared infrastructure, we recommend using virtual
|
||||
machines with a VM per user. This will easily allow users to run a docker daemon. If you want
|
||||
to use kubernetes, you'll definitely want to use [kubevirt](https://kubevirt.io) to give each
|
||||
user a virtual machine instead of just a container. Docker in docker while supported requires
|
||||
privileged containers which are a security risk in a multi tenant infrastructure.
|
||||
user a virtual machine instead of just a container.
|
||||
|
||||
## Docker in code-server docker container?
|
||||
## Docker in code-server container?
|
||||
|
||||
If you'd like to access docker inside of code-server, we'd recommend running a docker:dind container
|
||||
and mounting in a directory to share between dind and the code-server container at /var/run. After, install
|
||||
the docker CLI in the code-server container and you should be able to access the daemon as the socket
|
||||
will be shared at /var/run/docker.sock.
|
||||
If you'd like to access docker inside of code-server, mount the docker socket in from `/var/run/docker.sock`.
|
||||
Install the docker CLI in the code-server container and you should be able to access the daemon!
|
||||
|
||||
In order to make volume mounts work, mount the home directory in the code-server container and the
|
||||
dind container at the same path. i.e you'd volume mount a directory from the host to `/home/coder`
|
||||
on both. This will allow any volume mounts in the home directory to work. Similar process
|
||||
to make volume mounts in any other directory work.
|
||||
|
||||
## Collaboration
|
||||
|
||||
We understand the high demand but the team is swamped right now.
|
||||
|
||||
You can follow progress at [#33](https://github.com/cdr/code-server/issues/33).
|
||||
You can even make volume mounts work. Lets say you want to run a container and mount in
|
||||
`/home/coder/myproject` into it from inside the `code-server` container. You need to make sure
|
||||
the docker daemon's `/home/coder/myproject` is the same as the one mounted inside the `code-server`
|
||||
container and the mount will just work.
|
||||
|
||||
## How can I disable telemetry?
|
||||
|
||||
@@ -192,23 +233,37 @@ Once this is done, replicate the issue you're having then collect logging
|
||||
information from the following places:
|
||||
|
||||
1. stdout
|
||||
2. The most recently created directory in the `~/.local/share/code-server/logs` directory
|
||||
2. The most recently created directory in the `~/.local/share/code-server/logs` directory.
|
||||
3. The browser console and network tabs.
|
||||
|
||||
Additionally, collecting core dumps (you may need to enable them first) if
|
||||
code-server crashes can be helpful.
|
||||
|
||||
## Heartbeat file
|
||||
## Heartbeat File
|
||||
|
||||
`code-server` touches `~/.local/share/code-server/heartbeat` once a minute as long
|
||||
as there is an active browser connection.
|
||||
|
||||
If you want to shutdown `code-server` if there hasn't been an active connection in X minutes
|
||||
you can do so by continuously checking the last modified time on the heartbeat file and if it is
|
||||
older than X minutes, you should kill `code-server`.
|
||||
older than X minutes, kill `code-server`.
|
||||
|
||||
[#1636](https://github.com/cdr/code-server/issues/1636) will make the experience here better.
|
||||
|
||||
## Healthz endpoint
|
||||
|
||||
`code-server` exposes an endpoint at `/healthz` which can be used to check
|
||||
whether `code-server` is up without triggering a heartbeat. The response will
|
||||
include a status (`alive` or `expired`) and a timestamp for the last heartbeat
|
||||
(defaults to `0`). This endpoint does not require authentication.
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "alive",
|
||||
"lastHeartbeat": 1599166210566
|
||||
}
|
||||
```
|
||||
|
||||
## How does the config file work?
|
||||
|
||||
When `code-server` starts up, it creates a default config file in `~/.config/code-server/config.yaml` that looks
|
||||
@@ -229,6 +284,38 @@ and no TLS. Any flags passed to `code-server` will take priority over the config
|
||||
|
||||
The `--config` flag or `$CODE_SERVER_CONFIG` can be used to change the config file's location.
|
||||
|
||||
The default location also respects `$XDG_CONFIG_HOME`.
|
||||
|
||||
## Isn't an install script piped into sh insecure?
|
||||
|
||||
Please give
|
||||
[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by
|
||||
[sandstorm.io](https://sandstorm.io) a read.
|
||||
|
||||
## How do I make my keyboard shortcuts work?
|
||||
|
||||
Many shortcuts will not work by default as they'll be caught by the browser.
|
||||
|
||||
If you use Chrome you can get around this by installing the PWA.
|
||||
|
||||
Once you've entered the editor, click the "plus" icon present in the URL toolbar area.
|
||||
This will install a Chrome PWA and now all keybindings will work!
|
||||
|
||||
For other browsers you'll have to remap keybindings unfortunately.
|
||||
|
||||
## Differences compared to Theia?
|
||||
|
||||
[Theia](https://github.com/eclipse-theia/theia) is a browser IDE loosely based on VS Code. It uses the same
|
||||
text editor library named [Monaco](https://github.com/Microsoft/monaco-editor) and the same
|
||||
extension API but everything else is very different. It also uses [open-vsx.org](https://open-vsx.org)
|
||||
for extensions which has an order of magnitude less extensions than our marketplace.
|
||||
See [#1473](https://github.com/cdr/code-server/issues/1473).
|
||||
|
||||
You can't just use your VS Code config in Theia like you can with code-server.
|
||||
|
||||
To summarize, code-server is a patched fork of VS Code to run in the browser whereas
|
||||
Theia takes some parts of VS Code but is an entirely different editor.
|
||||
|
||||
## Enterprise
|
||||
|
||||
Visit [our enterprise page](https://coder.com) for more information about our
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 MiB |
BIN
doc/assets/screenshot.png
Normal file
BIN
doc/assets/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 524 KiB |
165
doc/guide.md
165
doc/guide.md
@@ -9,23 +9,31 @@
|
||||
- [3. Expose code-server](#3-expose-code-server)
|
||||
- [SSH forwarding](#ssh-forwarding)
|
||||
- [Let's Encrypt](#lets-encrypt)
|
||||
- [NGINX](#nginx)
|
||||
- [Self Signed Certificate](#self-signed-certificate)
|
||||
- [Change the password?](#change-the-password)
|
||||
- [How do I securely access development web services?](#how-do-i-securely-access-development-web-services)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
This guide demonstrates how to setup and use code-server.
|
||||
To reiterate, code-server lets you run VS Code on a remote server and then access it via a browser.
|
||||
This guide demonstrates how to setup and use `code-server`.
|
||||
To reiterate, `code-server` lets you run VS Code on a remote server and then access it via a browser.
|
||||
|
||||
See [README.md](../README.md) for a general overview and [FAQ.md](./FAQ.md) for further user docs.
|
||||
Further docs are at:
|
||||
|
||||
We'll walk you through acquiring a remote machine to run code-server on and then exposing `code-server` so you can
|
||||
securely access it.
|
||||
- [README](../README.md) for a general overview
|
||||
- [INSTALL](../doc/install.md) for installation
|
||||
- [FAQ](./FAQ.md) for common questions.
|
||||
- [CONTRIBUTING](../doc/CONTRIBUTING.md) for development docs
|
||||
|
||||
We highly recommend reading the [FAQ](./FAQ.md) on the [Differences compared to VS Code](./FAQ.md#differences-compared-to-vs-code) before beginning.
|
||||
|
||||
We'll walk you through acquiring a remote machine to run `code-server` on
|
||||
and then exposing `code-server` so you can securely access it.
|
||||
|
||||
## 1. Acquire a remote machine
|
||||
|
||||
First, you need a machine to run code-server on. You can use a physical
|
||||
First, you need a machine to run `code-server` on. You can use a physical
|
||||
machine you have lying around or use a VM on GCP/AWS.
|
||||
|
||||
### Requirements
|
||||
@@ -56,83 +64,92 @@ Once you've signed up and created a GCP project, create a new Compute Engine VM
|
||||
- Change the type to custom and set at least 2 cores and 2 GB of ram.
|
||||
- Add more vCPUs and memory as you prefer, you can edit after creating the instance as well.
|
||||
- https://cloud.google.com/compute/docs/machine-types#general_purpose
|
||||
7. We highly recommend switching the persistent disk to a SSD of at least 32 GB.
|
||||
7. We highly recommend switching the persistent disk to an SSD of at least 32 GB.
|
||||
- Click `Change` under `Boot Disk` and change the type to `SSD Persistent Disk` and the size
|
||||
to `32`.
|
||||
- You can always grow your disk later.
|
||||
- The default OS of Debian 10 is fine.
|
||||
8. Navigate to `Networking -> Network interfaces` and edit the existing interface
|
||||
to use a static external IP.
|
||||
- Click done to save network interface changes.
|
||||
9. If you do not have a [project wide SSH key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide), navigate to `Security - > SSH Keys` and add your public key there.
|
||||
9. If you do not have a [project wide SSH key](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#project-wide), navigate to `Security -> SSH Keys` and add your public key there.
|
||||
10. Click create!
|
||||
|
||||
Remember, you can shutdown your server when not in use to lower costs.
|
||||
|
||||
We highly recommend learning to use the [`gcloud`](https://cloud.google.com/sdk/gcloud) cli
|
||||
to avoid the slow dashboard.
|
||||
|
||||
## 2. Install code-server
|
||||
|
||||
SSH into your instance and run the appropriate commands documented in [README.md](../README.md).
|
||||
We have a [script](../install.sh) to install `code-server` for Linux, macOS and FreeBSD.
|
||||
|
||||
Assuming Debian:
|
||||
It tries to use the system package manager if possible.
|
||||
|
||||
First run to print out the install process:
|
||||
|
||||
```bash
|
||||
curl -sSOL https://github.com/cdr/code-server/releases/download/3.3.0/code-server_3.3.0_amd64.deb
|
||||
sudo dpkg -i code-server_3.3.0_amd64.deb
|
||||
systemctl --user enable --now code-server
|
||||
# Now code-server is running at http://127.0.0.1:8080
|
||||
# Your password is in ~/.config/code-server/config.yaml
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
Now to actually install:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
```
|
||||
|
||||
The install script will print out how to run and start using `code-server`.
|
||||
|
||||
Docs on the install script, manual installation and docker image are at [./install.md](./install.md).
|
||||
|
||||
## 3. Expose code-server
|
||||
|
||||
**Never**, **ever** expose `code-server` directly to the internet without some form of authentication
|
||||
and encryption as someone can completely takeover your machine with the terminal.
|
||||
|
||||
There are several approaches to securely operating and exposing code-server.
|
||||
By default, `code-server` will enable password authentication which will require you to copy the
|
||||
password from the`code-server`config file to login. It will listen on`localhost` to avoid exposing
|
||||
itself to the world. This is fine for testing but will not work if you want to access `code-server`
|
||||
from a different machine.
|
||||
|
||||
By default, code-server will enable password authentication which will
|
||||
require you to copy the password from the code-server config file to login. You
|
||||
can also set a custom password with `$PASSWORD`.
|
||||
There are several approaches to securely operating and exposing `code-server`.
|
||||
|
||||
**tip**: You can list the full set of code-server options with `code-server --help`
|
||||
**tip**: You can list the full set of `code-server` options with `code-server --help`
|
||||
|
||||
### SSH forwarding
|
||||
|
||||
We highly recommend this approach for not requiring any additional setup, you just need an
|
||||
SSH server on your remote machine. The downside is you won't be able to access `code-server`
|
||||
without an SSH client like an iPad. If that's important to you, skip to [Let's Encrypt](#lets-encrypt).
|
||||
on any machine without an SSH client like on iPad. If that's important to you, skip to [Let's Encrypt](#lets-encrypt).
|
||||
|
||||
Recommended reading: https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding.
|
||||
|
||||
First, ssh into your instance and edit your code-server config file to disable password authentication.
|
||||
First, ssh into your instance and edit your `code-server` config file to disable password authentication.
|
||||
|
||||
```bash
|
||||
# Replaces "auth: password" with "auth: none" in the code-server config.
|
||||
sed -i.bak 's/auth: password/auth: none/' ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
Restart code-server with (assuming you followed the guide):
|
||||
Restart `code-server` with (assuming you followed the guide):
|
||||
|
||||
```bash
|
||||
systemctl --user restart code-server
|
||||
sudo systemctl restart code-server@$USER
|
||||
```
|
||||
|
||||
Now forward local port 8080 to `127.0.0.1:8080` on the remote instance.
|
||||
Now forward local port 8080 to `127.0.0.1:8080` on the remote instance by running the following command on your local machine.
|
||||
|
||||
Recommended reading: https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding.
|
||||
|
||||
```bash
|
||||
# -N disables executing a remote shell
|
||||
ssh -N -L 8080:127.0.0.1:8080 <instance-ip>
|
||||
ssh -N -L 8080:127.0.0.1:8080 [user]@<instance-ip>
|
||||
```
|
||||
|
||||
Now if you access http://127.0.0.1:8080 locally, you should see code-server!
|
||||
Now if you access http://127.0.0.1:8080 locally, you should see `code-server`!
|
||||
|
||||
If you want to make the SSH port forwarding persistent we recommend using
|
||||
[mutagen](https://mutagen.io/documentation/introduction/installation).
|
||||
|
||||
```
|
||||
# Same as the above SSH command but runs in the background continously.
|
||||
# Same as the above SSH command but runs in the background continuously.
|
||||
# Add `mutagen daemon start` to your ~/.bashrc to start the mutagen daemon when you open a shell.
|
||||
mutagen forward create --name=code-server tcp:127.0.0.1:8080 <instance-ip>:tcp:127.0.0.1:8080
|
||||
```
|
||||
@@ -145,16 +162,16 @@ ServerAliveInterval 5
|
||||
ExitOnForwardFailure yes
|
||||
```
|
||||
|
||||
You can also forward your SSH key and GPG agent to the instance to securely access GitHub
|
||||
and sign commits without copying your keys onto the instance.
|
||||
You can also forward your SSH and GPG agent to the instance to securely access GitHub
|
||||
and sign commits without copying your keys.
|
||||
|
||||
1. https://developer.github.com/v3/guides/using-ssh-agent-forwarding/
|
||||
2. https://wiki.gnupg.org/AgentForwarding
|
||||
|
||||
### Let's Encrypt
|
||||
|
||||
[Let's Encrypt](https://letsencrypt.org) is a great option if you want to access code-server on an iPad
|
||||
or do not want to use SSH forwarding. This does require that the remote machine is exposed to the internet.
|
||||
[Let's Encrypt](https://letsencrypt.org) is a great option if you want to access `code-server` on an iPad
|
||||
or do not want to use SSH forwarding. This does require that the remote machine be exposed to the internet.
|
||||
|
||||
Assuming you have been following the guide, edit your instance and checkmark the allow HTTP/HTTPS traffic options.
|
||||
|
||||
@@ -177,31 +194,73 @@ mydomain.com
|
||||
reverse_proxy 127.0.0.1:8080
|
||||
```
|
||||
|
||||
Remember to replace `mydomain.com` with your domain name!
|
||||
|
||||
5. Reload caddy with:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload caddy
|
||||
```
|
||||
|
||||
Visit `https://<your-domain-name>` to access code-server. Congratulations!
|
||||
Visit `https://<your-domain-name>` to access `code-server`. Congratulations!
|
||||
|
||||
In a future release we plan to integrate Let's Encrypt directly with code-server to avoid
|
||||
In a future release we plan to integrate Let's Encrypt directly with `code-server` to avoid
|
||||
the dependency on caddy.
|
||||
|
||||
#### NGINX
|
||||
|
||||
If you prefer to use NGINX instead of Caddy then please follow steps 1-2 above and then:
|
||||
|
||||
3. Install `nginx`:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y nginx certbot python-certbot-nginx
|
||||
```
|
||||
|
||||
4. Put the following config into `/etc/nginx/sites-available/code-server` with sudo:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name mydomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:8080/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection upgrade;
|
||||
proxy_set_header Accept-Encoding gzip;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Remember to replace `mydomain.com` with your domain name!
|
||||
|
||||
5. Enable the config:
|
||||
|
||||
```bash
|
||||
sudo ln -s ../sites-available/code-server /etc/nginx/sites-enabled/code-server
|
||||
sudo certbot --non-interactive --redirect --agree-tos --nginx -d mydomain.com -m me@example.com
|
||||
```
|
||||
|
||||
Make sure to substitute `me@example.com` with your actual email.
|
||||
|
||||
Visit `https://<your-domain-name>` to access `code-server`. Congratulations!
|
||||
|
||||
### Self Signed Certificate
|
||||
|
||||
**note:** Self signed certificates do not work with iPad and will cause a blank page. You'll
|
||||
have to use [Let's Encrypt](#lets-encrypt) instead.
|
||||
**note:** Self signed certificates do not work with iPad normally. See [./ipad.md](./ipad.md) for details.
|
||||
|
||||
Recommended reading: https://security.stackexchange.com/a/8112.
|
||||
|
||||
We recommend this as a last resort as self signed certificates do not work with iPads and can
|
||||
cause other bizarre issues. Not to mention all the warnings when you access code-server.
|
||||
We recommend this as a last resort because self signed certificates do not work with iPads and can
|
||||
cause other bizarre issues. Not to mention all the warnings when you access `code-server`.
|
||||
Only use this if:
|
||||
|
||||
1. You do not want to buy a domain.
|
||||
2. You cannot expose the remote machine to the internet.
|
||||
3. You do not want to use SSH forwarding.
|
||||
1. You do not want to buy a domain or you cannot expose the remote machine to the internet.
|
||||
2. You do not want to use SSH forwarding.
|
||||
|
||||
ssh into your instance and edit your code-server config file to use a randomly generated self signed certificate:
|
||||
|
||||
@@ -214,32 +273,32 @@ sed -i.bak 's/bind-addr: 127.0.0.1:8080/bind-addr: 0.0.0.0:443/' ~/.config/code-
|
||||
sudo setcap cap_net_bind_service=+ep /usr/lib/code-server/lib/node
|
||||
```
|
||||
|
||||
Assuming you have been following the guide, restart code-server with:
|
||||
Assuming you have been following the guide, restart `code-server` with:
|
||||
|
||||
```bash
|
||||
systemctl --user restart code-server
|
||||
sudo systemctl restart code-server@$USER
|
||||
```
|
||||
|
||||
Edit your instance and checkmark the allow HTTPS traffic option.
|
||||
|
||||
Visit `https://<your-instance-ip>` to access code-server.
|
||||
Visit `https://<your-instance-ip>` to access `code-server`.
|
||||
You'll get a warning when accessing but if you click through you should be good.
|
||||
|
||||
To avoid the warnings, you can use [mkcert](https://mkcert.dev) to create a self signed certificate
|
||||
trusted by your OS and then pass it into code-server via the `cert` and `cert-key` config
|
||||
trusted by your OS and then pass it into `code-server` via the `cert` and `cert-key` config
|
||||
fields.
|
||||
|
||||
### Change the password?
|
||||
|
||||
Edit the code-server config file at `~/.config/code-server/config.yaml` and then restart
|
||||
code-server with:
|
||||
Edit the `password` field in the `code-server` config file at `~/.config/code-server/config.yaml`
|
||||
and then restart `code-server` with:
|
||||
|
||||
```bash
|
||||
systemctl --user restart code-server
|
||||
sudo systemctl restart code-server@$USER
|
||||
```
|
||||
|
||||
### How do I securely access development web services?
|
||||
|
||||
If you're working on a web service and want to access it locally, code-server can proxy it for you.
|
||||
If you're working on a web service and want to access it locally, `code-server` can proxy it for you.
|
||||
|
||||
See [FAQ.md](https://github.com/cdr/code-server/blob/master/doc/FAQ.md#how-do-i-securely-access-web-services).
|
||||
See the [FAQ](./FAQ.md#how-do-i-securely-access-web-services).
|
||||
|
||||
199
doc/install.md
Normal file
199
doc/install.md
Normal file
@@ -0,0 +1,199 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
# Install
|
||||
|
||||
- [install.sh](#installsh)
|
||||
- [Flags](#flags)
|
||||
- [Detection Reference](#detection-reference)
|
||||
- [Debian, Ubuntu](#debian-ubuntu)
|
||||
- [Fedora, CentOS, RHEL, SUSE](#fedora-centos-rhel-suse)
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [yarn, npm](#yarn-npm)
|
||||
- [macOS](#macos)
|
||||
- [Standalone Releases](#standalone-releases)
|
||||
- [Docker](#docker)
|
||||
- [helm](#helm)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
This document demonstrates how to install `code-server` on
|
||||
various distros and operating systems.
|
||||
|
||||
## install.sh
|
||||
|
||||
We have a [script](../install.sh) to install code-server for Linux, macOS and FreeBSD.
|
||||
|
||||
It tries to use the system package manager if possible.
|
||||
|
||||
First run to print out the install process:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
Now to actually install:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://code-server.dev/install.sh | sh
|
||||
```
|
||||
|
||||
The script will print out how to run and start using code-server.
|
||||
|
||||
If you believe an install script used with `curl | sh` is insecure, please give
|
||||
[this wonderful blogpost](https://sandstorm.io/news/2015-09-24-is-curl-bash-insecure-pgp-verified-install) by
|
||||
[sandstorm.io](https://sandstorm.io) a read.
|
||||
|
||||
If you'd still prefer manual installation despite the below [detection reference](#detection-reference) and `--dry-run`
|
||||
then continue on for docs on manual installation. The [`install.sh`](../install.sh) script runs the _exact_ same
|
||||
commands presented in the rest of this document.
|
||||
|
||||
### Flags
|
||||
|
||||
- `--dry-run` to echo the commands for the install process without running them.
|
||||
- `--method` to choose the installation method.
|
||||
- `--method=detect` to detect the package manager but fallback to `--method=standalone`.
|
||||
- `--method=standalone` to install a standalone release archive into `~/.local`.
|
||||
- `--prefix=/usr/local` to install a standalone release archive system wide.
|
||||
- `--version=X.X.X` to install version `X.X.X` instead of latest.
|
||||
- `--help` to see full usage docs.
|
||||
|
||||
### Detection Reference
|
||||
|
||||
- For Debian, Ubuntu and Raspbian it will install the latest deb package.
|
||||
- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
|
||||
- For Arch Linux it will install the AUR package.
|
||||
- For any unrecognized Linux operating system it will install the latest standalone release into `~/.local`.
|
||||
|
||||
- Add `~/.local/bin` to your `$PATH` to run code-server.
|
||||
|
||||
- For macOS it will install the Homebrew package.
|
||||
|
||||
- If Homebrew is not installed it will install the latest standalone release into `~/.local`.
|
||||
- Add `~/.local/bin` to your `$PATH` to run code-server.
|
||||
|
||||
- For FreeBSD, it will install the [npm package](#yarn-npm) with `yarn` or `npm`.
|
||||
|
||||
- If ran on an architecture with no releases, it will install the [npm package](#yarn-npm) with `yarn` or `npm`.
|
||||
- We only have releases for amd64 and arm64 presently.
|
||||
- The [npm package](#yarn-npm) builds the native modules on postinstall.
|
||||
|
||||
## Debian, Ubuntu
|
||||
|
||||
```bash
|
||||
curl -fOL https://github.com/cdr/code-server/releases/download/v3.7.0/code-server_3.7.0_amd64.deb
|
||||
sudo dpkg -i code-server_3.7.0_amd64.deb
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## Fedora, CentOS, RHEL, SUSE
|
||||
|
||||
```bash
|
||||
curl -fOL https://github.com/cdr/code-server/releases/download/v3.7.0/code-server-3.7.0-amd64.rpm
|
||||
sudo rpm -i code-server-3.7.0-amd64.rpm
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## Arch Linux
|
||||
|
||||
```bash
|
||||
# Installs code-server from the AUR using yay.
|
||||
yay -S code-server
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
```bash
|
||||
# Installs code-server from the AUR with plain makepkg.
|
||||
git clone https://aur.archlinux.org/code-server.git
|
||||
cd code-server
|
||||
makepkg -si
|
||||
sudo systemctl enable --now code-server@$USER
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## yarn, npm
|
||||
|
||||
We recommend installing with `yarn` or `npm` when:
|
||||
|
||||
1. You aren't on `amd64` or `arm64`.
|
||||
2. If you're on Linux with glibc < v2.17 or glibcxx < v3.4.18
|
||||
|
||||
**note:** Installing via `yarn` or `npm` builds native modules on install and so requires C dependencies.
|
||||
See [./npm.md](./npm.md) for installing these dependencies.
|
||||
|
||||
You will need at least node v12 installed. See [#1633](https://github.com/cdr/code-server/issues/1633).
|
||||
|
||||
```bash
|
||||
yarn global add code-server
|
||||
# Or: npm install -g code-server
|
||||
code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## macOS
|
||||
|
||||
```bash
|
||||
brew install code-server
|
||||
brew services start code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## Standalone Releases
|
||||
|
||||
We publish self contained `.tar.gz` archives for every release on [github](https://github.com/cdr/code-server/releases).
|
||||
They bundle the node binary and `node_modules`.
|
||||
|
||||
These are created from the [npm package](#yarn-npm) and the rest of the releases are created from these.
|
||||
Only requirement is glibc >= 2.17 && glibcxx >= v3.4.18 on Linux and for macOS there is no minimum system requirement.
|
||||
|
||||
1. Download the latest release archive for your system from [github](https://github.com/cdr/code-server/releases).
|
||||
2. Unpack the release.
|
||||
3. You can run code-server by executing `./bin/code-server`.
|
||||
|
||||
You can add the code-server `bin` directory to your `$PATH` to easily execute `code-server`
|
||||
without the full path every time.
|
||||
|
||||
Here is an example script for installing and using a standalone `code-server` release on Linux:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.local/lib ~/.local/bin
|
||||
curl -fL https://github.com/cdr/code-server/releases/download/v3.7.0/code-server-3.7.0-linux-amd64.tar.gz \
|
||||
| tar -C ~/.local/lib -xz
|
||||
mv ~/.local/lib/code-server-3.7.0-linux-amd64 ~/.local/lib/code-server-3.7.0
|
||||
ln -s ~/.local/lib/code-server-3.7.0/bin/code-server ~/.local/bin/code-server
|
||||
PATH="~/.local/bin:$PATH"
|
||||
code-server
|
||||
# Now visit http://127.0.0.1:8080. Your password is in ~/.config/code-server/config.yaml
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
# This will start a code-server container and expose it at http://127.0.0.1:8080.
|
||||
# It will also mount your current directory into the container as `/home/coder/project`
|
||||
# and forward your UID/GID so that all file system operations occur as your user outside
|
||||
# the container.
|
||||
#
|
||||
# Your $HOME/.config is mounted at $HOME/.config within the container to ensure you can
|
||||
# easily access/modify your code-server config in $HOME/.config/code-server/config.json
|
||||
# outside the container.
|
||||
mkdir -p ~/.config
|
||||
docker run -it --name code-server -p 127.0.0.1:8080:8080 \
|
||||
-v "$HOME/.config:/home/coder/.config" \
|
||||
-v "$PWD:/home/coder/project" \
|
||||
-u "$(id -u):$(id -g)" \
|
||||
-e "DOCKER_USER=$USER" \
|
||||
codercom/code-server:latest
|
||||
```
|
||||
|
||||
Our official image supports `amd64` and `arm64`.
|
||||
|
||||
For `arm32` support there is a popular community maintained alternative:
|
||||
|
||||
https://hub.docker.com/r/linuxserver/code-server
|
||||
|
||||
## helm
|
||||
|
||||
See [the chart](../ci/helm-chart).
|
||||
56
doc/ipad.md
Normal file
56
doc/ipad.md
Normal file
@@ -0,0 +1,56 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
# iPad
|
||||
|
||||
- [iPad](#ipad)
|
||||
- [Known Issues](#known-issues)
|
||||
- [How to access code-server with a self signed certificate on iPad?](#how-to-access-code-server-with-a-self-signed-certificate-on-ipad)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
# iPad
|
||||
|
||||
## Known Issues
|
||||
|
||||
- Getting self signed certificates certificates to work is involved, see below.
|
||||
- Keyboard may disappear sometimes [#1313](https://github.com/cdr/code-server/issues/1313), [#979](https://github.com/cdr/code-server/issues/979)
|
||||
- Trackpad scrolling does not work [#1455](https://github.com/cdr/code-server/issues/1455)
|
||||
- See [issues tagged with the iPad label](https://github.com/cdr/code-server/issues?q=is%3Aopen+is%3Aissue+label%3AiPad) for more.
|
||||
|
||||
## How to access code-server with a self signed certificate on iPad?
|
||||
|
||||
Accessing a self signed certificate on iPad isn't as easy as accepting through all
|
||||
the security warnings. Safari will prevent WebSocket connections unless the certificate
|
||||
is installed as a profile on the device.
|
||||
|
||||
The below assumes you are using the self signed certificate that code-server
|
||||
generates for you. If not, that's fine but you'll have to make sure your certificate
|
||||
abides by the following guidelines from Apple: https://support.apple.com/en-us/HT210176
|
||||
|
||||
**note**: Another undocumented requirement we noticed is that the certificate has to have `basicConstraints=CA:true`.
|
||||
|
||||
The following instructions assume you have code-server installed and running
|
||||
with a self signed certificate. If not, please first go through [./guide.md](./guide.md)!
|
||||
|
||||
**warning**: Your iPad must access code-server via a domain name. It could be local
|
||||
DNS like `mymacbookpro.local` but it must be a domain name. Otherwise Safari will
|
||||
refuse to allow WebSockets to connect.
|
||||
|
||||
1. Your certificate **must** have a subject alt name that matches the hostname
|
||||
at which you will access code-server from your iPad. You can pass this to code-server
|
||||
so that it generates the certificate correctly with `--cert-host`.
|
||||
2. Share your self signed certificate with the iPad.
|
||||
- code-server will print the location of the certificate it has generated in the logs.
|
||||
|
||||
```
|
||||
[2020-10-30T08:55:45.139Z] info - Using generated certificate and key for HTTPS: ~/.local/share/code-server/mymbp_local.crt
|
||||
```
|
||||
|
||||
- You can mail it to yourself or if you have a Mac, it's easiest to just Airdrop to the iPad.
|
||||
|
||||
3. When opening the `*.crt` file, you'll be prompted to go into settings to install.
|
||||
4. Go to `Settings -> General -> Profile`, select the profile and then hit `Install`.
|
||||
- It should say the profile is verified.
|
||||
5. Go to `Settings -> About -> Certificate Trust Settings` and enable full trust for
|
||||
the certificate.
|
||||
6. Now you can access code-server! 🍻
|
||||
16
doc/npm.md
16
doc/npm.md
@@ -1,5 +1,13 @@
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
# npm Install Requirements
|
||||
|
||||
- [Ubuntu, Debian](#ubuntu-debian)
|
||||
- [Fedora, CentOS, RHEL](#fedora-centos-rhel)
|
||||
- [macOS](#macos)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
If you're installing the npm module you'll need certain dependencies to build
|
||||
the native modules used by VS Code.
|
||||
|
||||
@@ -13,14 +21,16 @@ sudo apt-get install -y \
|
||||
pkg-config \
|
||||
libx11-dev \
|
||||
libxkbfile-dev \
|
||||
libsecret-1-dev
|
||||
libsecret-1-dev \
|
||||
python3
|
||||
npm config set python python3
|
||||
```
|
||||
|
||||
## Fedora, Red Hat, SUSE
|
||||
## Fedora, CentOS, RHEL
|
||||
|
||||
```bash
|
||||
sudo yum groupinstall -y 'Development Tools'
|
||||
sudo yum config-manager --set-enabled PowerTools
|
||||
sudo yum config-manager --set-enabled PowerTools # unnecessary on CentOS 7
|
||||
sudo yum install -y python2 libsecret-devel libX11-devel libxkbfile-devel
|
||||
npm config set python python2
|
||||
```
|
||||
|
||||
559
install.sh
Executable file
559
install.sh
Executable file
@@ -0,0 +1,559 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
# code-server's automatic install script.
|
||||
# See https://github.com/cdr/code-server/blob/master/doc/install.md
|
||||
|
||||
usage() {
|
||||
arg0="$0"
|
||||
if [ "$0" = sh ]; then
|
||||
arg0="curl -fsSL https://code-server.dev/install.sh | sh -s --"
|
||||
else
|
||||
not_curl_usage="The latest script is available at https://code-server.dev/install.sh
|
||||
"
|
||||
fi
|
||||
|
||||
cath << EOF
|
||||
Installs code-server for Linux, macOS and FreeBSD.
|
||||
It tries to use the system package manager if possible.
|
||||
After successful installation it explains how to start using code-server.
|
||||
|
||||
Pass in user@host to install code-server on user@host over ssh.
|
||||
The remote host must have internet access.
|
||||
${not_curl_usage-}
|
||||
Usage:
|
||||
|
||||
$arg0 [--dry-run] [--version X.X.X] [--method detect] \
|
||||
[--prefix ~/.local] [--rsh ssh] [user@host]
|
||||
|
||||
--dry-run
|
||||
Echo the commands for the install process without running them.
|
||||
|
||||
--version X.X.X
|
||||
Install a specific version instead of the latest.
|
||||
|
||||
--method [detect | standalone]
|
||||
Choose the installation method. Defaults to detect.
|
||||
- detect detects the system package manager and tries to use it.
|
||||
Full reference on the process is further below.
|
||||
- standalone installs a standalone release archive into ~/.local
|
||||
Add ~/.local/bin to your \$PATH to use it.
|
||||
|
||||
--prefix <dir>
|
||||
Sets the prefix used by standalone release archives. Defaults to ~/.local
|
||||
The release is unarchived into ~/.local/lib/code-server-X.X.X
|
||||
and the binary symlinked into ~/.local/bin/code-server
|
||||
To install system wide pass ---prefix=/usr/local
|
||||
|
||||
--rsh <bin>
|
||||
Specifies the remote shell for remote installation. Defaults to ssh.
|
||||
|
||||
- For Debian, Ubuntu and Raspbian it will install the latest deb package.
|
||||
- For Fedora, CentOS, RHEL and openSUSE it will install the latest rpm package.
|
||||
- For Arch Linux it will install the AUR package.
|
||||
- For any unrecognized Linux operating system it will install the latest standalone
|
||||
release into ~/.local
|
||||
|
||||
- For macOS it will install the Homebrew package.
|
||||
- If Homebrew is not installed it will install the latest standalone release
|
||||
into ~/.local
|
||||
|
||||
- For FreeBSD, it will install the npm package with yarn or npm.
|
||||
|
||||
- If ran on an architecture with no releases, it will install the
|
||||
npm package with yarn or npm.
|
||||
- We only have releases for amd64 and arm64 presently.
|
||||
- The npm package builds the native modules on postinstall.
|
||||
|
||||
It will cache all downloaded assets into ~/.cache/code-server
|
||||
|
||||
More installation docs are at https://github.com/cdr/code-server/blob/master/doc/install.md
|
||||
EOF
|
||||
}
|
||||
|
||||
echo_latest_version() {
|
||||
# https://gist.github.com/lukechilds/a83e1d7127b78fef38c2914c4ececc3c#gistcomment-2758860
|
||||
version="$(curl -fsSLI -o /dev/null -w "%{url_effective}" https://github.com/cdr/code-server/releases/latest)"
|
||||
version="${version#https://github.com/cdr/code-server/releases/tag/}"
|
||||
version="${version#v}"
|
||||
echo "$version"
|
||||
}
|
||||
|
||||
echo_standalone_postinstall() {
|
||||
echoh
|
||||
cath << EOF
|
||||
Standalone release has been installed into $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION
|
||||
Please extend your path to use code-server:
|
||||
PATH="$STANDALONE_INSTALL_PREFIX/bin:\$PATH"
|
||||
Then you can run:
|
||||
code-server
|
||||
EOF
|
||||
}
|
||||
|
||||
echo_systemd_postinstall() {
|
||||
echoh
|
||||
cath << EOF
|
||||
To have systemd start code-server now and restart on boot:
|
||||
sudo systemctl enable --now code-server@\$USER
|
||||
Or, if you don't want/need a background service you can run:
|
||||
code-server
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "${TRACE-}" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
unset \
|
||||
DRY_RUN \
|
||||
METHOD \
|
||||
STANDALONE_INSTALL_PREFIX \
|
||||
VERSION \
|
||||
OPTIONAL \
|
||||
ALL_FLAGS \
|
||||
RSH_ARGS \
|
||||
RSH
|
||||
|
||||
ALL_FLAGS=""
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-*)
|
||||
ALL_FLAGS="${ALL_FLAGS} $1"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
;;
|
||||
--method)
|
||||
METHOD="$(parse_arg "$@")"
|
||||
shift
|
||||
;;
|
||||
--method=*)
|
||||
METHOD="$(parse_arg "$@")"
|
||||
;;
|
||||
--prefix)
|
||||
STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
|
||||
shift
|
||||
;;
|
||||
--prefix=*)
|
||||
STANDALONE_INSTALL_PREFIX="$(parse_arg "$@")"
|
||||
;;
|
||||
--version)
|
||||
VERSION="$(parse_arg "$@")"
|
||||
shift
|
||||
;;
|
||||
--version=*)
|
||||
VERSION="$(parse_arg "$@")"
|
||||
;;
|
||||
--rsh)
|
||||
RSH="$(parse_arg "$@")"
|
||||
shift
|
||||
;;
|
||||
--rsh=*)
|
||||
RSH="$(parse_arg "$@")"
|
||||
;;
|
||||
-h | --h | -help | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
# We remove the -- added above.
|
||||
ALL_FLAGS="${ALL_FLAGS% --}"
|
||||
RSH_ARGS="$*"
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
echoerr "Unknown flag $1"
|
||||
echoerr "Run with --help to see usage."
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
RSH_ARGS="$*"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [ "${RSH_ARGS-}" ]; then
|
||||
RSH="${RSH-ssh}"
|
||||
echoh "Installing remotely with $RSH $RSH_ARGS"
|
||||
curl -fsSL https://code-server.dev/install.sh | prefix "$RSH_ARGS" "$RSH" "$RSH_ARGS" sh -s -- "$ALL_FLAGS"
|
||||
return
|
||||
fi
|
||||
|
||||
VERSION="${VERSION-$(echo_latest_version)}"
|
||||
METHOD="${METHOD-detect}"
|
||||
if [ "$METHOD" != detect ] && [ "$METHOD" != standalone ]; then
|
||||
echoerr "Unknown install method \"$METHOD\""
|
||||
echoerr "Run with --help to see usage."
|
||||
exit 1
|
||||
fi
|
||||
STANDALONE_INSTALL_PREFIX="${STANDALONE_INSTALL_PREFIX-$HOME/.local}"
|
||||
|
||||
OS="$(os)"
|
||||
if [ ! "$OS" ]; then
|
||||
echoerr "Unsupported OS $(uname)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
distro_name
|
||||
|
||||
ARCH="$(arch)"
|
||||
if [ ! "$ARCH" ]; then
|
||||
if [ "$METHOD" = standalone ]; then
|
||||
echoerr "No precompiled releases for $(uname -m)."
|
||||
echoerr 'Please rerun without the "--method standalone" flag to install from npm.'
|
||||
exit 1
|
||||
fi
|
||||
echoh "No precompiled releases for $(uname -m)."
|
||||
install_npm
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$OS" = "freebsd" ]; then
|
||||
if [ "$METHOD" = standalone ]; then
|
||||
echoerr "No precompiled releases available for $OS."
|
||||
echoerr 'Please rerun without the "--method standalone" flag to install from npm.'
|
||||
exit 1
|
||||
fi
|
||||
echoh "No precompiled releases available for $OS."
|
||||
install_npm
|
||||
return
|
||||
fi
|
||||
|
||||
CACHE_DIR="$(echo_cache_dir)"
|
||||
|
||||
if [ "$METHOD" = standalone ]; then
|
||||
install_standalone
|
||||
return
|
||||
fi
|
||||
|
||||
case "$(distro)" in
|
||||
macos)
|
||||
install_macos
|
||||
;;
|
||||
ubuntu | debian | raspbian)
|
||||
install_deb
|
||||
;;
|
||||
centos | fedora | rhel | opensuse)
|
||||
install_rpm
|
||||
;;
|
||||
arch)
|
||||
install_aur
|
||||
;;
|
||||
*)
|
||||
echoh "Unsupported package manager."
|
||||
install_standalone
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
parse_arg() {
|
||||
case "$1" in
|
||||
*=*)
|
||||
# Remove everything after first equal sign.
|
||||
opt="${1%%=*}"
|
||||
# Remove everything before first equal sign.
|
||||
optarg="${1#*=}"
|
||||
if [ ! "$optarg" ] && [ ! "${OPTIONAL-}" ]; then
|
||||
echoerr "$opt requires an argument"
|
||||
echoerr "Run with --help to see usage."
|
||||
exit 1
|
||||
fi
|
||||
echo "$optarg"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "${2-}" in
|
||||
"" | -*)
|
||||
if [ ! "${OPTIONAL-}" ]; then
|
||||
echoerr "$1 requires an argument"
|
||||
echoerr "Run with --help to see usage."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "$2"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
fetch() {
|
||||
URL="$1"
|
||||
FILE="$2"
|
||||
|
||||
if [ -e "$FILE" ]; then
|
||||
echoh "+ Reusing $FILE"
|
||||
return
|
||||
fi
|
||||
|
||||
sh_c mkdir -p "$CACHE_DIR"
|
||||
sh_c curl \
|
||||
-#fL \
|
||||
-o "$FILE.incomplete" \
|
||||
-C - \
|
||||
"$URL"
|
||||
sh_c mv "$FILE.incomplete" "$FILE"
|
||||
}
|
||||
|
||||
install_macos() {
|
||||
if command_exists brew; then
|
||||
echoh "Installing from Homebrew."
|
||||
echoh
|
||||
|
||||
sh_c brew install code-server
|
||||
|
||||
return
|
||||
fi
|
||||
|
||||
echoh "Homebrew not installed."
|
||||
|
||||
install_standalone
|
||||
}
|
||||
|
||||
install_deb() {
|
||||
echoh "Installing v$VERSION deb package from GitHub releases."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server_${VERSION}_$ARCH.deb" \
|
||||
"$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
|
||||
sudo_sh_c dpkg -i "$CACHE_DIR/code-server_${VERSION}_$ARCH.deb"
|
||||
|
||||
echo_systemd_postinstall
|
||||
}
|
||||
|
||||
install_rpm() {
|
||||
echoh "Installing v$VERSION rpm package from GitHub releases."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$ARCH.rpm" \
|
||||
"$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
|
||||
sudo_sh_c rpm -i "$CACHE_DIR/code-server-$VERSION-$ARCH.rpm"
|
||||
|
||||
echo_systemd_postinstall
|
||||
}
|
||||
|
||||
install_aur() {
|
||||
echoh "Installing from the AUR."
|
||||
echoh
|
||||
|
||||
sh_c mkdir -p "$CACHE_DIR/code-server-aur"
|
||||
sh_c "curl -#fsSL https://aur.archlinux.org/cgit/aur.git/snapshot/code-server.tar.gz | tar -xzC $CACHE_DIR/code-server-aur --strip-components 1"
|
||||
echo "+ cd $CACHE_DIR/code-server-aur"
|
||||
if [ ! "${DRY_RUN-}" ]; then
|
||||
cd "$CACHE_DIR/code-server-aur"
|
||||
fi
|
||||
sh_c makepkg -si
|
||||
|
||||
echo_systemd_postinstall
|
||||
}
|
||||
|
||||
install_standalone() {
|
||||
echoh "Installing standalone release archive v$VERSION from GitHub releases."
|
||||
echoh
|
||||
|
||||
fetch "https://github.com/cdr/code-server/releases/download/v$VERSION/code-server-$VERSION-$OS-$ARCH.tar.gz" \
|
||||
"$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
|
||||
|
||||
sh_c="sh_c"
|
||||
if [ ! -w "$STANDALONE_INSTALL_PREFIX" ]; then
|
||||
sh_c="sudo_sh_c"
|
||||
fi
|
||||
|
||||
if [ -e "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION" ]; then
|
||||
echoh
|
||||
echoh "code-server-$VERSION is already installed at $STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION"
|
||||
echoh "Remove it to reinstall."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
"$sh_c" mkdir -p "$STANDALONE_INSTALL_PREFIX/lib" "$STANDALONE_INSTALL_PREFIX/bin"
|
||||
"$sh_c" tar -C "$STANDALONE_INSTALL_PREFIX/lib" -xzf "$CACHE_DIR/code-server-$VERSION-$OS-$ARCH.tar.gz"
|
||||
"$sh_c" mv -f "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION-$OS-$ARCH" "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION"
|
||||
"$sh_c" ln -fs "$STANDALONE_INSTALL_PREFIX/lib/code-server-$VERSION/bin/code-server" "$STANDALONE_INSTALL_PREFIX/bin/code-server"
|
||||
|
||||
echo_standalone_postinstall
|
||||
}
|
||||
|
||||
install_npm() {
|
||||
if command_exists yarn; then
|
||||
sh_c="sh_c"
|
||||
if [ ! -w "$(yarn global bin)" ]; then
|
||||
sh_c="sudo_sh_c"
|
||||
fi
|
||||
echoh "Installing with yarn."
|
||||
echoh
|
||||
"$sh_c" yarn global add code-server --unsafe-perm
|
||||
return
|
||||
elif command_exists npm; then
|
||||
sh_c="sh_c"
|
||||
if [ ! -w "$(npm config get prefix)" ]; then
|
||||
sh_c="sudo_sh_c"
|
||||
fi
|
||||
echoh "Installing with npm."
|
||||
echoh
|
||||
"$sh_c" npm install -g code-server --unsafe-perm
|
||||
return
|
||||
fi
|
||||
echoh
|
||||
echoerr "Please install npm or yarn to install code-server!"
|
||||
echoerr "You will need at least node v12 and a few C dependencies."
|
||||
echoerr "See the docs https://github.com/cdr/code-server#yarn-npm"
|
||||
exit 1
|
||||
}
|
||||
|
||||
os() {
|
||||
case "$(uname)" in
|
||||
Linux)
|
||||
echo linux
|
||||
;;
|
||||
Darwin)
|
||||
echo macos
|
||||
;;
|
||||
FreeBSD)
|
||||
echo freebsd
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# distro prints the detected operating system including linux distros.
|
||||
#
|
||||
# Example outputs:
|
||||
# - macos
|
||||
# - debian, ubuntu, raspbian
|
||||
# - centos, fedora, rhel, opensuse
|
||||
# - alpine
|
||||
# - arch
|
||||
# - freebsd
|
||||
#
|
||||
# Inspired by https://github.com/docker/docker-install/blob/26ff363bcf3b3f5a00498ac43694bf1c7d9ce16c/install.sh#L111-L120.
|
||||
distro() {
|
||||
if [ "$OS" = "macos" ] || [ "$OS" = "freebsd" ]; then
|
||||
echo "$OS"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -f /etc/os-release ]; then
|
||||
(
|
||||
. /etc/os-release
|
||||
case "$ID" in opensuse-*)
|
||||
# opensuse's ID's look like opensuse-leap and opensuse-tumbleweed.
|
||||
echo "opensuse"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$ID"
|
||||
)
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
# os_name prints a pretty human readable name for the OS/Distro.
|
||||
distro_name() {
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
echo "macOS v$(sw_vers -productVersion)"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -f /etc/os-release ]; then
|
||||
(
|
||||
. /etc/os-release
|
||||
echo "$PRETTY_NAME"
|
||||
)
|
||||
return
|
||||
fi
|
||||
|
||||
# Prints something like: Linux 4.19.0-9-amd64
|
||||
uname -sr
|
||||
}
|
||||
|
||||
arch() {
|
||||
case "$(uname -m)" in
|
||||
aarch64)
|
||||
echo arm64
|
||||
;;
|
||||
x86_64)
|
||||
echo amd64
|
||||
;;
|
||||
amd64) # FreeBSD.
|
||||
echo amd64
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
command_exists() {
|
||||
command -v "$@" > /dev/null
|
||||
}
|
||||
|
||||
sh_c() {
|
||||
echoh "+ $*"
|
||||
if [ ! "${DRY_RUN-}" ]; then
|
||||
sh -c "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
sudo_sh_c() {
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
sh_c "$@"
|
||||
elif command_exists sudo; then
|
||||
sh_c "sudo $*"
|
||||
elif command_exists su; then
|
||||
sh_c "su -c '$*'"
|
||||
else
|
||||
echoh
|
||||
echoerr "This script needs to run the following command as root."
|
||||
echoerr " $*"
|
||||
echoerr "Please install sudo or su."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo_cache_dir() {
|
||||
if [ "${XDG_CACHE_HOME-}" ]; then
|
||||
echo "$XDG_CACHE_HOME/code-server"
|
||||
elif [ "${HOME-}" ]; then
|
||||
echo "$HOME/.cache/code-server"
|
||||
else
|
||||
echo "/tmp/code-server-cache"
|
||||
fi
|
||||
}
|
||||
|
||||
echoh() {
|
||||
echo "$@" | humanpath
|
||||
}
|
||||
|
||||
cath() {
|
||||
humanpath
|
||||
}
|
||||
|
||||
echoerr() {
|
||||
echoh "$@" >&2
|
||||
}
|
||||
|
||||
# humanpath replaces all occurances of " $HOME" with " ~"
|
||||
# and all occurances of '"$HOME' with the literal '"$HOME'.
|
||||
humanpath() {
|
||||
sed "s# $HOME# ~#g; s#\"$HOME#\"\$HOME#g"
|
||||
}
|
||||
|
||||
# We need to make sure we exit with a non zero exit if the command fails.
|
||||
# /bin/sh does not support -o pipefail unfortunately.
|
||||
prefix() {
|
||||
PREFIX="$1"
|
||||
shift
|
||||
fifo="$(mktemp -d)/fifo"
|
||||
mkfifo "$fifo"
|
||||
sed -e "s#^#$PREFIX: #" "$fifo" &
|
||||
"$@" > "$fifo" 2>&1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Submodule lib/vscode updated: 19c1c8ac0a...93c2f0fbf1
47
package.json
47
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-server",
|
||||
"license": "MIT",
|
||||
"version": "3.3.0",
|
||||
"version": "3.7.0",
|
||||
"description": "Run VS Code on a remote server.",
|
||||
"homepage": "https://github.com/cdr/code-server",
|
||||
"bugs": {
|
||||
@@ -16,48 +16,53 @@
|
||||
"build": "./ci/build/build-code-server.sh",
|
||||
"build:vscode": "./ci/build/build-vscode.sh",
|
||||
"release": "./ci/build/build-release.sh",
|
||||
"release:static": "./ci/build/build-static-release.sh",
|
||||
"release:standalone": "./ci/build/build-standalone-release.sh",
|
||||
"release:github-draft": "./ci/build/release-github-draft.sh",
|
||||
"release:github-assets": "./ci/build/release-github-assets.sh",
|
||||
"test:static-release": "./ci/build/test-static-release.sh",
|
||||
"test:standalone-release": "./ci/build/test-standalone-release.sh",
|
||||
"package": "./ci/build/build-packages.sh",
|
||||
"_____": "",
|
||||
"fmt": "./ci/dev/fmt.sh",
|
||||
"lint": "./ci/dev/lint.sh",
|
||||
"test": "./ci/dev/test.sh",
|
||||
"ci": "./ci/dev/ci.sh",
|
||||
"watch": "NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts"
|
||||
"watch": "VSCODE_IPC_HOOK_CLI= NODE_OPTIONS=--max_old_space_size=32384 ts-node ./ci/dev/watch.ts"
|
||||
},
|
||||
"main": "out/node/entry.js",
|
||||
"devDependencies": {
|
||||
"@types/adm-zip": "^0.4.32",
|
||||
"@types/body-parser": "^1.19.0",
|
||||
"@types/cookie-parser": "^1.4.2",
|
||||
"@types/express": "^4.17.8",
|
||||
"@types/fs-extra": "^8.0.1",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
"@types/js-yaml": "^3.12.3",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/mocha": "^8.0.3",
|
||||
"@types/node": "^12.12.7",
|
||||
"@types/parcel-bundler": "^1.12.1",
|
||||
"@types/pem": "^1.9.5",
|
||||
"@types/safe-compare": "^1.1.0",
|
||||
"@types/semver": "^7.1.0",
|
||||
"@types/tar-fs": "^1.16.2",
|
||||
"@types/tar-stream": "^1.6.1",
|
||||
"@types/ws": "^6.0.4",
|
||||
"@typescript-eslint/eslint-plugin": "^2.0.0",
|
||||
"@typescript-eslint/parser": "^2.0.0",
|
||||
"@types/split2": "^2.1.6",
|
||||
"@types/supertest": "^2.0.10",
|
||||
"@types/tar-fs": "^2.0.0",
|
||||
"@types/tar-stream": "^2.1.0",
|
||||
"@types/ws": "^7.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^4.7.0",
|
||||
"@typescript-eslint/parser": "^4.7.0",
|
||||
"doctoc": "^1.4.0",
|
||||
"eslint": "^6.2.0",
|
||||
"eslint": "^7.7.0",
|
||||
"eslint-config-prettier": "^6.0.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-prettier": "^3.1.0",
|
||||
"leaked-handles": "^5.2.0",
|
||||
"mocha": "^6.2.0",
|
||||
"mocha": "^8.1.2",
|
||||
"parcel-bundler": "^1.12.4",
|
||||
"prettier": "^2.0.5",
|
||||
"stylelint": "^13.0.0",
|
||||
"stylelint-config-recommended": "^3.0.0",
|
||||
"ts-node": "^8.4.1",
|
||||
"typescript": "3.7.2"
|
||||
"supertest": "^6.0.1",
|
||||
"ts-node": "^9.0.0",
|
||||
"typescript": "4.0.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "^12.12.7",
|
||||
@@ -65,17 +70,23 @@
|
||||
"vfile-message": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coder/logger": "1.1.11",
|
||||
"adm-zip": "^0.4.14",
|
||||
"@coder/logger": "1.1.16",
|
||||
"body-parser": "^1.19.0",
|
||||
"cookie-parser": "^1.4.5",
|
||||
"env-paths": "^2.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"express": "^5.0.0-alpha.8",
|
||||
"fs-extra": "^9.0.1",
|
||||
"http-proxy": "^1.18.0",
|
||||
"httpolyglot": "^0.1.2",
|
||||
"js-yaml": "^3.13.1",
|
||||
"limiter": "^1.1.5",
|
||||
"pem": "^1.14.2",
|
||||
"qs": "6.7.0",
|
||||
"rotating-file-stream": "^2.1.1",
|
||||
"safe-buffer": "^5.1.1",
|
||||
"safe-compare": "^1.1.4",
|
||||
"semver": "^7.1.3",
|
||||
"split2": "^3.2.2",
|
||||
"tar": "^6.0.1",
|
||||
"tar-fs": "^2.0.0",
|
||||
"ws": "^7.2.0",
|
||||
|
||||
@@ -7,32 +7,32 @@
|
||||
"description": "Run editors on a remote server.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-96.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-96.png",
|
||||
"type": "image/png",
|
||||
"sizes": "96x96"
|
||||
},
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-128.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-128.png",
|
||||
"type": "image/png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-192.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-256.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-256.png",
|
||||
"type": "image/png",
|
||||
"sizes": "256x256"
|
||||
},
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png",
|
||||
"type": "image/png",
|
||||
"sizes": "384x384"
|
||||
},
|
||||
{
|
||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-512.png",
|
||||
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="style-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||
/>
|
||||
<title>code-server</title>
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/pages/app.css" rel="stylesheet" />
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
</head>
|
||||
<body>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/pages/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,37 +0,0 @@
|
||||
import { getOptions, normalize } from "../../common/util"
|
||||
import { ApiEndpoint } from "../../common/http"
|
||||
|
||||
import "./error.css"
|
||||
import "./global.css"
|
||||
import "./home.css"
|
||||
import "./login.css"
|
||||
import "./update.css"
|
||||
|
||||
const options = getOptions()
|
||||
|
||||
const isInput = (el: Element): el is HTMLInputElement => {
|
||||
return !!(el as HTMLInputElement).name
|
||||
}
|
||||
|
||||
document.querySelectorAll("form").forEach((form) => {
|
||||
if (!form.classList.contains("-x11")) {
|
||||
return
|
||||
}
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault()
|
||||
const values: { [key: string]: string } = {}
|
||||
Array.from(form.elements).forEach((element) => {
|
||||
if (isInput(element)) {
|
||||
values[element.name] = element.value
|
||||
}
|
||||
})
|
||||
fetch(normalize(`${options.base}/api/${ApiEndpoint.process}`), {
|
||||
method: "POST",
|
||||
body: JSON.stringify(values),
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// TEMP: Until we can get the real ready event.
|
||||
const event = new CustomEvent("ide-ready")
|
||||
window.dispatchEvent(event)
|
||||
@@ -11,28 +11,22 @@
|
||||
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||
/>
|
||||
<title>{{ERROR_TITLE}} - code-server</title>
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/pages/app.css" rel="stylesheet" />
|
||||
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{CS_STATIC_BASE}}/dist/register.css" rel="stylesheet" />
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="center-container">
|
||||
<div class="error-display">
|
||||
<h2 class="header">{{ERROR_HEADER}}</h2>
|
||||
<div class="body">
|
||||
{{ERROR_BODY}}
|
||||
</div>
|
||||
<div class="body">{{ERROR_BODY}}</div>
|
||||
<div class="links">
|
||||
<a class="link" href="{{BASE}}{{TO}}">go home</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
.block-row {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.block-row > .item {
|
||||
flex: 1;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.block-row > button.item {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.block-row > .item > .sub {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.block-row .-link {
|
||||
color: rgb(87, 114, 245);
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.block-row .-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.block-row > .item > .icon {
|
||||
height: 1rem;
|
||||
margin-right: 5px;
|
||||
vertical-align: top;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.block-row > .item > .icon.-missing {
|
||||
background-color: rgba(87, 114, 245, 0.2);
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kill-form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.kill-form > .kill {
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="style-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||
/>
|
||||
<title>code-server</title>
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/pages/app.css" rel="stylesheet" />
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="center-container">
|
||||
<div class="card-box">
|
||||
<div class="header">
|
||||
<h2 class="main">Editors</h2>
|
||||
<div class="sub">Choose an editor to launch below.</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{APP_LIST:EDITORS}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-box">
|
||||
<div class="header">
|
||||
<h2 class="main">Other</h2>
|
||||
<div class="sub">Choose an application to launch below.</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{APP_LIST:OTHER}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-box">
|
||||
<div class="header">
|
||||
<h2 class="main">Version</h2>
|
||||
<div class="sub">Version information and updates.</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{UPDATE:NAME}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/pages/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,14 +11,10 @@
|
||||
content="style-src 'self'; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||
/>
|
||||
<title>code-server login</title>
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/pages/app.css" rel="stylesheet" />
|
||||
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{CS_STATIC_BASE}}/dist/register.css" rel="stylesheet" />
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
</head>
|
||||
<body>
|
||||
@@ -50,11 +46,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
<script>
|
||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||
parts[parts.length - 1] = "{{BASE}}"
|
||||
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
||||
document.getElementById("base").value = url.pathname
|
||||
</script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/pages/login.js"></script>
|
||||
</html>
|
||||
|
||||
7
src/browser/pages/login.ts
Normal file
7
src/browser/pages/login.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { getOptions } from "../../common/util"
|
||||
|
||||
const options = getOptions()
|
||||
const el = document.getElementById("base") as HTMLInputElement
|
||||
if (el) {
|
||||
el.value = options.base
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||
/>
|
||||
<title>code-server</title>
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/pages/app.css" rel="stylesheet" />
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="center-container">
|
||||
<div class="card-box">
|
||||
<div class="header">
|
||||
<h1 class="main">Update</h1>
|
||||
<div class="sub">Update code-server.</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<form class="update-form" action="{{BASE}}/update/apply">
|
||||
{{UPDATE_STATUS}} {{ERROR}}
|
||||
<div class="links">
|
||||
<a class="link" href="{{BASE}}{{TO}}">go home</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,12 +2,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<script>
|
||||
globalThis.MonacoPerformanceMarks = globalThis.MonacoPerformanceMarks || []
|
||||
globalThis.MonacoPerformanceMarks.push("renderer/started", Date.now())
|
||||
</script>
|
||||
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="font-src 'self' data:; connect-src ws: wss: 'self' https:; default-src ws: wss: 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; manifest-src 'self'; img-src 'self' data: https:;"
|
||||
/>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<!-- Disable pinch zooming -->
|
||||
<meta
|
||||
@@ -24,21 +24,17 @@
|
||||
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
|
||||
|
||||
<!-- Workbench Icon/Manifest/CSS -->
|
||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link
|
||||
rel="manifest"
|
||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
||||
crossorigin="use-credentials"
|
||||
/>
|
||||
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||
<!-- PROD_ONLY
|
||||
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.css">
|
||||
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.css">
|
||||
END_PROD_ONLY -->
|
||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
||||
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
|
||||
<!-- Prefetch to avoid waterfall -->
|
||||
<!-- PROD_ONLY
|
||||
<link rel="prefetch" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/node_modules/semver-umd/lib/semver-umd.js">
|
||||
<link rel="prefetch" href="{{CS_STATIC_BASE}}/lib/vscode/node_modules/semver-umd/lib/semver-umd.js">
|
||||
END_PROD_ONLY -->
|
||||
|
||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||
@@ -47,64 +43,17 @@
|
||||
<body aria-label=""></body>
|
||||
|
||||
<!-- Startup (do not modify order of script tags!) -->
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/pages/vscode.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/loader.js"></script>
|
||||
<script>
|
||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||
parts[parts.length - 1] = "{{BASE}}"
|
||||
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
||||
const staticBase = url.href.replace(/\/+$/, "") + "/static/{{COMMIT}}/lib/vscode"
|
||||
let nlsConfig
|
||||
try {
|
||||
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
|
||||
if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
||||
const bundles = Object.create(null)
|
||||
nlsConfig.loadBundle = (bundle, language, cb) => {
|
||||
let result = bundles[bundle]
|
||||
if (result) {
|
||||
return cb(undefined, result)
|
||||
}
|
||||
// FIXME: Only works if path separators are /.
|
||||
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
|
||||
fetch(`${url.href}/resource/?path=${encodeURIComponent(path)}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
bundles[bundle] = json
|
||||
cb(undefined, json)
|
||||
})
|
||||
.catch(cb)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
/* Probably fine. */
|
||||
}
|
||||
self.require = {
|
||||
baseUrl: `${staticBase}/out`,
|
||||
paths: {
|
||||
"vscode-textmate": `${staticBase}/node_modules/vscode-textmate/release/main`,
|
||||
"vscode-oniguruma": `${staticBase}/node_modules/vscode-oniguruma/release/main`,
|
||||
xterm: `${staticBase}/node_modules/xterm/lib/xterm.js`,
|
||||
"xterm-addon-search": `${staticBase}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||
"xterm-addon-unicode11": `${staticBase}/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
"xterm-addon-web-links": `${staticBase}/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`,
|
||||
"xterm-addon-webgl": `${staticBase}/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
"semver-umd": `${staticBase}/node_modules/semver-umd/lib/semver-umd.js`,
|
||||
},
|
||||
"vs/nls": nlsConfig,
|
||||
}
|
||||
globalThis.MonacoPerformanceMarks.push("willLoadWorkbenchMain", Date.now())
|
||||
</script>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/loader.js"></script>
|
||||
<!-- PROD_ONLY
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.js"></script>
|
||||
END_PROD_ONLY -->
|
||||
<script>
|
||||
require(["vs/code/browser/workbench/workbench"], function () {})
|
||||
</script>
|
||||
<script>
|
||||
try {
|
||||
document.body.style.background = JSON.parse(localStorage.getItem("colorThemeData")).colorMap["editor.background"]
|
||||
} catch (error) {
|
||||
// Oh well.
|
||||
}
|
||||
</script>
|
||||
</html>
|
||||
|
||||
56
src/browser/pages/vscode.ts
Normal file
56
src/browser/pages/vscode.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { getOptions } from "../../common/util"
|
||||
|
||||
const options = getOptions()
|
||||
|
||||
// TODO: Add proper types.
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
let nlsConfig: any
|
||||
try {
|
||||
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration")!.getAttribute("data-settings")!)
|
||||
if (nlsConfig._resolvedLanguagePackCoreLocation) {
|
||||
const bundles = Object.create(null)
|
||||
nlsConfig.loadBundle = (bundle: any, _language: any, cb: any): void => {
|
||||
const result = bundles[bundle]
|
||||
if (result) {
|
||||
return cb(undefined, result)
|
||||
}
|
||||
// FIXME: Only works if path separators are /.
|
||||
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
|
||||
fetch(`${options.base}/vscode/resource/?path=${encodeURIComponent(path)}`)
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
bundles[bundle] = json
|
||||
cb(undefined, json)
|
||||
})
|
||||
.catch(cb)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
/* Probably fine. */
|
||||
}
|
||||
|
||||
;(self.require as any) = {
|
||||
// Without the full URL VS Code will try to load file://.
|
||||
baseUrl: `${window.location.origin}${options.csStaticBase}/lib/vscode/out`,
|
||||
recordStats: true,
|
||||
paths: {
|
||||
"vscode-textmate": `../node_modules/vscode-textmate/release/main`,
|
||||
"vscode-oniguruma": `../node_modules/vscode-oniguruma/release/main`,
|
||||
xterm: `../node_modules/xterm/lib/xterm.js`,
|
||||
"xterm-addon-search": `../node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||
"xterm-addon-unicode11": `../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
"xterm-addon-webgl": `../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
"semver-umd": `../node_modules/semver-umd/lib/semver-umd.js`,
|
||||
"tas-client-umd": `../node_modules/tas-client-umd/lib/tas-client-umd.js`,
|
||||
"iconv-lite-umd": `../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
jschardet: `../node_modules/jschardet/dist/jschardet.min.js`,
|
||||
},
|
||||
"vs/nls": nlsConfig,
|
||||
}
|
||||
|
||||
try {
|
||||
document.body.style.background = JSON.parse(localStorage.getItem("colorThemeData")!).colorMap["editor.background"]
|
||||
} catch (error) {
|
||||
// Oh well.
|
||||
}
|
||||
@@ -2,13 +2,17 @@ import { getOptions, normalize } from "../common/util"
|
||||
|
||||
const options = getOptions()
|
||||
|
||||
import "./pages/error.css"
|
||||
import "./pages/global.css"
|
||||
import "./pages/login.css"
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
const path = normalize(`${options.base}/static/${options.commit}/dist/serviceWorker.js`)
|
||||
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
|
||||
navigator.serviceWorker
|
||||
.register(path, {
|
||||
scope: options.base || "/",
|
||||
scope: (options.base ?? "") + "/",
|
||||
})
|
||||
.then(function () {
|
||||
.then(() => {
|
||||
console.log("[Service Worker] registered")
|
||||
})
|
||||
}
|
||||
|
||||
2
src/browser/robots.txt
Normal file
2
src/browser/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
@@ -8,17 +8,6 @@ self.addEventListener("activate", (event: any) => {
|
||||
event.waitUntil((self as any).clients.claim())
|
||||
})
|
||||
|
||||
self.addEventListener("fetch", (event: any) => {
|
||||
if (!navigator.onLine) {
|
||||
event.respondWith(
|
||||
new Promise((resolve) => {
|
||||
resolve(
|
||||
new Response("OFFLINE", {
|
||||
status: 200,
|
||||
statusText: "OK",
|
||||
}),
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
self.addEventListener("fetch", () => {
|
||||
// Without this event handler we won't be recognized as a PWA.
|
||||
})
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
export interface Application {
|
||||
readonly categories?: string[]
|
||||
readonly comment?: string
|
||||
readonly directory?: string
|
||||
readonly exec?: string
|
||||
readonly genericName?: string
|
||||
readonly icon?: string
|
||||
readonly installed?: boolean
|
||||
readonly name: string
|
||||
/**
|
||||
* Path if this is a browser app (like VS Code).
|
||||
*/
|
||||
readonly path?: string
|
||||
/**
|
||||
* PID if this is a process.
|
||||
*/
|
||||
readonly pid?: number
|
||||
readonly version?: string
|
||||
}
|
||||
|
||||
export interface ApplicationsResponse {
|
||||
readonly applications: ReadonlyArray<Application>
|
||||
}
|
||||
|
||||
export enum SessionError {
|
||||
FailedToStart = 4000,
|
||||
Starting = 4001,
|
||||
InvalidState = 4002,
|
||||
Unknown = 4003,
|
||||
}
|
||||
|
||||
export interface SessionResponse {
|
||||
/**
|
||||
* Whether the process was spawned or an existing one was returned.
|
||||
*/
|
||||
created: boolean
|
||||
pid: number
|
||||
}
|
||||
|
||||
export interface RecentResponse {
|
||||
readonly paths: string[]
|
||||
readonly workspaces: string[]
|
||||
}
|
||||
|
||||
export interface HealthRequest {
|
||||
readonly event: "health"
|
||||
}
|
||||
|
||||
export type ClientMessage = HealthRequest
|
||||
|
||||
export interface HealthResponse {
|
||||
readonly event: "health"
|
||||
readonly connections: number
|
||||
}
|
||||
|
||||
export type ServerMessage = HealthResponse
|
||||
|
||||
export interface ReadyMessage {
|
||||
protocol: string
|
||||
}
|
||||
@@ -1,19 +1,27 @@
|
||||
import { logger } from "@coder/logger"
|
||||
|
||||
/**
|
||||
* Event emitter callback. Called with the emitted value and a promise that
|
||||
* resolves when all emitters have finished.
|
||||
*/
|
||||
export type Callback<T, R = void | Promise<void>> = (t: T, p: Promise<void>) => R
|
||||
|
||||
export interface Disposable {
|
||||
dispose(): void
|
||||
}
|
||||
|
||||
export interface Event<T> {
|
||||
(listener: (value: T) => void): Disposable
|
||||
(listener: Callback<T>): Disposable
|
||||
}
|
||||
|
||||
/**
|
||||
* Emitter typecasts for a single event type.
|
||||
*/
|
||||
export class Emitter<T> {
|
||||
private listeners: Array<(value: T) => void> = []
|
||||
private listeners: Array<Callback<T>> = []
|
||||
|
||||
public get event(): Event<T> {
|
||||
return (cb: (value: T) => void): Disposable => {
|
||||
return (cb: Callback<T>): Disposable => {
|
||||
this.listeners.push(cb)
|
||||
|
||||
return {
|
||||
@@ -30,8 +38,21 @@ export class Emitter<T> {
|
||||
/**
|
||||
* Emit an event with a value.
|
||||
*/
|
||||
public emit(value: T): void {
|
||||
this.listeners.forEach((cb) => cb(value))
|
||||
public async emit(value: T): Promise<void> {
|
||||
let resolve: () => void
|
||||
const promise = new Promise<void>((r) => (resolve = r))
|
||||
|
||||
await Promise.all(
|
||||
this.listeners.map(async (cb) => {
|
||||
try {
|
||||
await cb(value, promise)
|
||||
} catch (error) {
|
||||
logger.error(error.message)
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
resolve!()
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
@@ -8,17 +8,13 @@ export enum HttpCode {
|
||||
ServerError = 500,
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an error with a message and an HTTP status code. This code will be
|
||||
* used in the HTTP response.
|
||||
*/
|
||||
export class HttpError extends Error {
|
||||
public constructor(message: string, public readonly code: number) {
|
||||
public constructor(message: string, public readonly status: HttpCode, public readonly details?: object) {
|
||||
super(message)
|
||||
this.name = this.constructor.name
|
||||
}
|
||||
}
|
||||
|
||||
export enum ApiEndpoint {
|
||||
applications = "/applications",
|
||||
process = "/process",
|
||||
recent = "/recent",
|
||||
run = "/run",
|
||||
status = "/status",
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ import { logger, field } from "@coder/logger"
|
||||
|
||||
export interface Options {
|
||||
base: string
|
||||
commit: string
|
||||
csStaticBase: string
|
||||
logLevel: number
|
||||
pid?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,11 @@ export const split = (str: string, delimiter: string): [string, string] => {
|
||||
return index !== -1 ? [str.substring(0, index).trim(), str.substring(index + 1)] : [str, ""]
|
||||
}
|
||||
|
||||
export const plural = (count: number): string => (count === 1 ? "" : "s")
|
||||
/**
|
||||
* Appends an 's' to the provided string if count is greater than one;
|
||||
* otherwise the string is returned
|
||||
*/
|
||||
export const plural = (count: number, str: string): string => (count === 1 ? str : `${str}s`)
|
||||
|
||||
export const generateUuid = (length = 24): string => {
|
||||
const possible = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
@@ -33,21 +36,35 @@ export const normalize = (url: string, keepTrailing = false): string => {
|
||||
return url.replace(/\/\/+/g, "/").replace(/\/+$/, keepTrailing ? "/" : "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove leading and trailing slashes.
|
||||
*/
|
||||
export const trimSlashes = (url: string): string => {
|
||||
return url.replace(/^\/+|\/+$/g, "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a relative base against the window location. This is used for
|
||||
* anything that doesn't work with a relative path.
|
||||
*/
|
||||
export const resolveBase = (base?: string): string => {
|
||||
// After resolving the base will either start with / or be an empty string.
|
||||
if (!base || base.startsWith("/")) {
|
||||
return base ?? ""
|
||||
}
|
||||
const parts = location.pathname.split("/")
|
||||
parts[parts.length - 1] = base
|
||||
const url = new URL(location.origin + "/" + parts.join("/"))
|
||||
return normalize(url.pathname)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options embedded in the HTML or query params.
|
||||
*/
|
||||
export const getOptions = <T extends Options>(): T => {
|
||||
let options: T
|
||||
try {
|
||||
const el = document.getElementById("coder-options")
|
||||
if (!el) {
|
||||
throw new Error("no options element")
|
||||
}
|
||||
const value = el.getAttribute("data-settings")
|
||||
if (!value) {
|
||||
throw new Error("no options value")
|
||||
}
|
||||
options = JSON.parse(value)
|
||||
options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
|
||||
} catch (error) {
|
||||
options = {} as T
|
||||
}
|
||||
@@ -61,17 +78,26 @@ export const getOptions = <T extends Options>(): T => {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof options.logLevel !== "undefined") {
|
||||
logger.level = options.logLevel
|
||||
}
|
||||
if (options.base) {
|
||||
const parts = location.pathname.replace(/^\//g, "").split("/")
|
||||
parts[parts.length - 1] = options.base
|
||||
const url = new URL(location.origin + "/" + parts.join("/"))
|
||||
options.base = normalize(url.pathname, true)
|
||||
}
|
||||
logger.level = options.logLevel
|
||||
|
||||
options.base = resolveBase(options.base)
|
||||
options.csStaticBase = resolveBase(options.csStaticBase)
|
||||
|
||||
logger.debug("got options", field("options", options))
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the value in an array if it's not already an array. If the value is
|
||||
* undefined return an empty array.
|
||||
*/
|
||||
export const arrayify = <T>(value?: T | T[]): T[] => {
|
||||
if (Array.isArray(value)) {
|
||||
return value
|
||||
}
|
||||
if (typeof value === "undefined") {
|
||||
return []
|
||||
}
|
||||
return [value]
|
||||
}
|
||||
|
||||
61
src/node/app.ts
Normal file
61
src/node/app.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { logger } from "@coder/logger"
|
||||
import express, { Express } from "express"
|
||||
import { promises as fs } from "fs"
|
||||
import http from "http"
|
||||
import * as httpolyglot from "httpolyglot"
|
||||
import { DefaultedArgs } from "./cli"
|
||||
import { handleUpgrade } from "./wsRouter"
|
||||
|
||||
/**
|
||||
* Create an Express app and an HTTP/S server to serve it.
|
||||
*/
|
||||
export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, http.Server]> => {
|
||||
const app = express()
|
||||
|
||||
const server = args.cert
|
||||
? httpolyglot.createServer(
|
||||
{
|
||||
cert: args.cert && (await fs.readFile(args.cert.value)),
|
||||
key: args["cert-key"] && (await fs.readFile(args["cert-key"])),
|
||||
},
|
||||
app,
|
||||
)
|
||||
: http.createServer(app)
|
||||
|
||||
await new Promise<http.Server>(async (resolve, reject) => {
|
||||
server.on("error", reject)
|
||||
if (args.socket) {
|
||||
try {
|
||||
await fs.unlink(args.socket)
|
||||
} catch (error) {
|
||||
if (error.code !== "ENOENT") {
|
||||
logger.error(error.message)
|
||||
}
|
||||
}
|
||||
server.listen(args.socket, resolve)
|
||||
} else {
|
||||
// [] is the correct format when using :: but Node errors with them.
|
||||
server.listen(args.port, args.host.replace(/^\[|\]$/g, ""), resolve)
|
||||
}
|
||||
})
|
||||
|
||||
const wsApp = express()
|
||||
handleUpgrade(wsApp, server)
|
||||
|
||||
return [app, wsApp, server]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of a server as a string (protocol *is* included) while
|
||||
* ensuring there is one (will throw if there isn't).
|
||||
*/
|
||||
export const ensureAddress = (server: http.Server): string => {
|
||||
const addr = server.address()
|
||||
if (!addr) {
|
||||
throw new Error("server has no address")
|
||||
}
|
||||
if (typeof addr !== "string") {
|
||||
return `http://${addr.address}:${addr.port}`
|
||||
}
|
||||
return addr
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
import { field, logger } from "@coder/logger"
|
||||
import * as cp from "child_process"
|
||||
import * as fs from "fs-extra"
|
||||
import * as http from "http"
|
||||
import * as net from "net"
|
||||
import * as path from "path"
|
||||
import * as url from "url"
|
||||
import * as WebSocket from "ws"
|
||||
import {
|
||||
Application,
|
||||
ApplicationsResponse,
|
||||
ClientMessage,
|
||||
RecentResponse,
|
||||
ServerMessage,
|
||||
SessionError,
|
||||
SessionResponse,
|
||||
} from "../../common/api"
|
||||
import { ApiEndpoint, HttpCode, HttpError } from "../../common/http"
|
||||
import { HttpProvider, HttpProviderOptions, HttpResponse, HttpServer, Route } from "../http"
|
||||
import { findApplications, findWhitelistedApplications, Vscode } from "./bin"
|
||||
import { VscodeHttpProvider } from "./vscode"
|
||||
|
||||
interface VsRecents {
|
||||
[key: string]: (string | { configURIPath: string })[]
|
||||
}
|
||||
|
||||
type VsSettings = [string, string][]
|
||||
|
||||
/**
|
||||
* API HTTP provider.
|
||||
*/
|
||||
export class ApiHttpProvider extends HttpProvider {
|
||||
private readonly ws = new WebSocket.Server({ noServer: true })
|
||||
|
||||
public constructor(
|
||||
options: HttpProviderOptions,
|
||||
private readonly server: HttpServer,
|
||||
private readonly vscode: VscodeHttpProvider,
|
||||
private readonly dataDir?: string,
|
||||
) {
|
||||
super(options)
|
||||
}
|
||||
|
||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
this.ensureAuthenticated(request)
|
||||
if (!this.isRoot(route)) {
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
switch (route.base) {
|
||||
case ApiEndpoint.applications:
|
||||
this.ensureMethod(request)
|
||||
return {
|
||||
mime: "application/json",
|
||||
content: {
|
||||
applications: await this.applications(),
|
||||
},
|
||||
} as HttpResponse<ApplicationsResponse>
|
||||
case ApiEndpoint.process:
|
||||
return this.process(request)
|
||||
case ApiEndpoint.recent:
|
||||
this.ensureMethod(request)
|
||||
return {
|
||||
mime: "application/json",
|
||||
content: await this.recent(),
|
||||
} as HttpResponse<RecentResponse>
|
||||
}
|
||||
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
public async handleWebSocket(
|
||||
route: Route,
|
||||
request: http.IncomingMessage,
|
||||
socket: net.Socket,
|
||||
head: Buffer,
|
||||
): Promise<void> {
|
||||
if (!this.authenticated(request)) {
|
||||
throw new Error("not authenticated")
|
||||
}
|
||||
switch (route.base) {
|
||||
case ApiEndpoint.status:
|
||||
return this.handleStatusSocket(request, socket, head)
|
||||
case ApiEndpoint.run:
|
||||
return this.handleRunSocket(route, request, socket, head)
|
||||
}
|
||||
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
private async handleStatusSocket(request: http.IncomingMessage, socket: net.Socket, head: Buffer): Promise<void> {
|
||||
const getMessageResponse = async (event: "health"): Promise<ServerMessage> => {
|
||||
switch (event) {
|
||||
case "health":
|
||||
return { event, connections: await this.server.getConnections() }
|
||||
default:
|
||||
throw new Error("unexpected message")
|
||||
}
|
||||
}
|
||||
|
||||
await new Promise<WebSocket>((resolve) => {
|
||||
this.ws.handleUpgrade(request, socket, head, (ws) => {
|
||||
const send = (event: ServerMessage): void => {
|
||||
ws.send(JSON.stringify(event))
|
||||
}
|
||||
ws.on("message", (data) => {
|
||||
logger.trace("got message", field("message", data))
|
||||
try {
|
||||
const message: ClientMessage = JSON.parse(data.toString())
|
||||
getMessageResponse(message.event).then(send)
|
||||
} catch (error) {
|
||||
logger.error(error.message, field("message", data))
|
||||
}
|
||||
})
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* A socket that connects to the process.
|
||||
*/
|
||||
private async handleRunSocket(
|
||||
_route: Route,
|
||||
request: http.IncomingMessage,
|
||||
socket: net.Socket,
|
||||
head: Buffer,
|
||||
): Promise<void> {
|
||||
logger.debug("connecting to process")
|
||||
const ws = await new Promise<WebSocket>((resolve, reject) => {
|
||||
this.ws.handleUpgrade(request, socket, head, (socket) => {
|
||||
socket.binaryType = "arraybuffer"
|
||||
|
||||
socket.on("error", (error) => {
|
||||
socket.close(SessionError.FailedToStart)
|
||||
logger.error("got error while connecting socket", field("error", error))
|
||||
reject(error)
|
||||
})
|
||||
|
||||
resolve(socket as WebSocket)
|
||||
})
|
||||
})
|
||||
|
||||
logger.debug("connected to process")
|
||||
|
||||
// Send ready message.
|
||||
ws.send(
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
protocol: "TODO",
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whitelisted applications.
|
||||
*/
|
||||
public async applications(): Promise<ReadonlyArray<Application>> {
|
||||
return findWhitelistedApplications()
|
||||
}
|
||||
|
||||
/**
|
||||
* Return installed applications.
|
||||
*/
|
||||
public async installedApplications(): Promise<ReadonlyArray<Application>> {
|
||||
return findApplications()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle /process endpoint.
|
||||
*/
|
||||
private async process(request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
this.ensureMethod(request, ["DELETE", "POST"])
|
||||
|
||||
const data = await this.getData(request)
|
||||
if (!data) {
|
||||
throw new HttpError("No data was provided", HttpCode.BadRequest)
|
||||
}
|
||||
|
||||
const parsed: Application = JSON.parse(data)
|
||||
|
||||
switch (request.method) {
|
||||
case "DELETE":
|
||||
if (parsed.pid) {
|
||||
await this.killProcess(parsed.pid)
|
||||
} else if (parsed.path) {
|
||||
await this.killProcess(parsed.path)
|
||||
} else {
|
||||
throw new Error("No pid or path was provided")
|
||||
}
|
||||
return {
|
||||
mime: "application/json",
|
||||
code: HttpCode.Ok,
|
||||
}
|
||||
case "POST": {
|
||||
if (!parsed.exec) {
|
||||
throw new Error("No exec was provided")
|
||||
}
|
||||
return {
|
||||
mime: "application/json",
|
||||
content: {
|
||||
created: true,
|
||||
pid: await this.spawnProcess(parsed.exec),
|
||||
},
|
||||
} as HttpResponse<SessionResponse>
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill a process identified by pid or path if a web app.
|
||||
*/
|
||||
public async killProcess(pid: number | string): Promise<void> {
|
||||
if (typeof pid === "string") {
|
||||
switch (pid) {
|
||||
case Vscode.path:
|
||||
await this.vscode.dispose()
|
||||
break
|
||||
default:
|
||||
throw new Error(`Process "${pid}" does not exist`)
|
||||
}
|
||||
} else {
|
||||
process.kill(pid)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn a process and return the pid.
|
||||
*/
|
||||
public async spawnProcess(exec: string): Promise<number> {
|
||||
const proc = cp.spawn(exec, {
|
||||
shell: process.env.SHELL || true,
|
||||
env: {
|
||||
...process.env,
|
||||
},
|
||||
})
|
||||
|
||||
proc.on("error", (error) => logger.error("process errored", field("pid", proc.pid), field("error", error)))
|
||||
proc.on("exit", () => logger.debug("process exited", field("pid", proc.pid)))
|
||||
|
||||
logger.debug("started process", field("pid", proc.pid))
|
||||
|
||||
return proc.pid
|
||||
}
|
||||
|
||||
/**
|
||||
* Return VS Code's recent paths.
|
||||
*/
|
||||
public async recent(): Promise<RecentResponse> {
|
||||
try {
|
||||
if (!this.dataDir) {
|
||||
throw new Error("data directory is not set")
|
||||
}
|
||||
|
||||
const state: VsSettings = JSON.parse(await fs.readFile(path.join(this.dataDir, "User/state/global.json"), "utf8"))
|
||||
const setting = Array.isArray(state) && state.find((item) => item[0] === "recently.opened")
|
||||
if (!setting) {
|
||||
return { paths: [], workspaces: [] }
|
||||
}
|
||||
|
||||
const pathPromises: { [key: string]: Promise<string> } = {}
|
||||
const workspacePromises: { [key: string]: Promise<string> } = {}
|
||||
Object.values(JSON.parse(setting[1]) as VsRecents).forEach((recents) => {
|
||||
recents.forEach((recent) => {
|
||||
try {
|
||||
const target = typeof recent === "string" ? pathPromises : workspacePromises
|
||||
const pathname = url.parse(typeof recent === "string" ? recent : recent.configURIPath).pathname
|
||||
if (pathname && !target[pathname]) {
|
||||
target[pathname] = new Promise<string>((resolve) => {
|
||||
fs.stat(pathname)
|
||||
.then(() => resolve(pathname))
|
||||
.catch(() => resolve())
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug("invalid path", field("path", recent))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const [paths, workspaces] = await Promise.all([
|
||||
Promise.all(Object.values(pathPromises)),
|
||||
Promise.all(Object.values(workspacePromises)),
|
||||
])
|
||||
|
||||
return {
|
||||
paths: paths.filter((p) => !!p),
|
||||
workspaces: workspaces.filter((p) => !!p),
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code !== "ENOENT") {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
return { paths: [], workspaces: [] }
|
||||
}
|
||||
|
||||
/**
|
||||
* For these, just return the error message since they'll be requested as
|
||||
* JSON.
|
||||
*/
|
||||
public async getErrorRoot(_route: Route, _title: string, _header: string, error: string): Promise<HttpResponse> {
|
||||
return {
|
||||
mime: "application/json",
|
||||
content: JSON.stringify({ error }),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { Application } from "../../common/api"
|
||||
|
||||
const getVscodeVersion = (): string => {
|
||||
try {
|
||||
return require(path.resolve(__dirname, "../../../lib/vscode/package.json")).version
|
||||
} catch (error) {
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
export const Vscode: Application = {
|
||||
categories: ["Editor"],
|
||||
icon: fs.readFileSync(path.resolve(__dirname, "../../../lib/vscode/resources/linux/code.png")).toString("base64"),
|
||||
installed: true,
|
||||
name: "VS Code",
|
||||
path: "/",
|
||||
version: getVscodeVersion(),
|
||||
}
|
||||
|
||||
export const findApplications = async (): Promise<ReadonlyArray<Application>> => {
|
||||
const apps: Application[] = [Vscode]
|
||||
|
||||
return apps.sort((a, b): number => a.name.localeCompare(b.name))
|
||||
}
|
||||
|
||||
export const findWhitelistedApplications = async (): Promise<ReadonlyArray<Application>> => {
|
||||
return [Vscode]
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
import * as http from "http"
|
||||
import * as querystring from "querystring"
|
||||
import { Application } from "../../common/api"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { normalize } from "../../common/util"
|
||||
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
|
||||
import { ApiHttpProvider } from "./api"
|
||||
import { UpdateHttpProvider } from "./update"
|
||||
|
||||
/**
|
||||
* Dashboard HTTP provider.
|
||||
*/
|
||||
export class DashboardHttpProvider extends HttpProvider {
|
||||
public constructor(
|
||||
options: HttpProviderOptions,
|
||||
private readonly api: ApiHttpProvider,
|
||||
private readonly update: UpdateHttpProvider,
|
||||
) {
|
||||
super(options)
|
||||
}
|
||||
|
||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
if (!this.isRoot(route)) {
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
switch (route.base) {
|
||||
case "/spawn": {
|
||||
this.ensureAuthenticated(request)
|
||||
this.ensureMethod(request, "POST")
|
||||
const data = await this.getData(request)
|
||||
const app = data ? querystring.parse(data) : {}
|
||||
if (app.path) {
|
||||
return { redirect: Array.isArray(app.path) ? app.path[0] : app.path }
|
||||
}
|
||||
if (!app.exec) {
|
||||
throw new Error("No exec was provided")
|
||||
}
|
||||
this.api.spawnProcess(Array.isArray(app.exec) ? app.exec[0] : app.exec)
|
||||
return { redirect: this.options.base }
|
||||
}
|
||||
case "/app":
|
||||
case "/": {
|
||||
this.ensureMethod(request)
|
||||
if (!this.authenticated(request)) {
|
||||
return { redirect: "/login", query: { to: this.options.base } }
|
||||
}
|
||||
return route.base === "/" ? this.getRoot(route) : this.getAppRoot(route)
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
public async getRoot(route: Route): Promise<HttpResponse> {
|
||||
const base = this.base(route)
|
||||
const apps = await this.api.installedApplications()
|
||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/home.html")
|
||||
response.content = response.content
|
||||
.replace(/{{UPDATE:NAME}}/, await this.getUpdate(base))
|
||||
.replace(
|
||||
/{{APP_LIST:EDITORS}}/,
|
||||
this.getAppRows(
|
||||
base,
|
||||
apps.filter((app) => app.categories && app.categories.includes("Editor")),
|
||||
),
|
||||
)
|
||||
.replace(
|
||||
/{{APP_LIST:OTHER}}/,
|
||||
this.getAppRows(
|
||||
base,
|
||||
apps.filter((app) => !app.categories || !app.categories.includes("Editor")),
|
||||
),
|
||||
)
|
||||
return this.replaceTemplates(route, response)
|
||||
}
|
||||
|
||||
public async getAppRoot(route: Route): Promise<HttpResponse> {
|
||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/app.html")
|
||||
return this.replaceTemplates(route, response)
|
||||
}
|
||||
|
||||
private getAppRows(base: string, apps: ReadonlyArray<Application>): string {
|
||||
return apps.length > 0
|
||||
? apps.map((app) => this.getAppRow(base, app)).join("\n")
|
||||
: `<div class="none">No applications found.</div>`
|
||||
}
|
||||
|
||||
private getAppRow(base: string, app: Application): string {
|
||||
return `<form class="block-row${app.exec ? " -x11" : ""}" method="post" action="${normalize(
|
||||
`${base}${this.options.base}/spawn`,
|
||||
)}">
|
||||
<button class="item -row -link">
|
||||
<input type="hidden" name="path" value="${app.path || ""}">
|
||||
<input type="hidden" name="exec" value="${app.exec || ""}">
|
||||
${
|
||||
app.icon
|
||||
? `<img class="icon" src="data:image/png;base64,${app.icon}"></img>`
|
||||
: `<span class="icon -missing"></span>`
|
||||
}
|
||||
<span class="name">${app.name}</span>
|
||||
</button>
|
||||
</form>`
|
||||
}
|
||||
|
||||
private async getUpdate(base: string): Promise<string> {
|
||||
if (!this.update.enabled) {
|
||||
return `<div class="block-row"><div class="item"><div class="sub">Updates are disabled</div></div></div>`
|
||||
}
|
||||
|
||||
const humanize = (time: number): string => {
|
||||
const d = new Date(time)
|
||||
const pad = (t: number): string => (t < 10 ? "0" : "") + t
|
||||
return (
|
||||
`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +
|
||||
` ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
)
|
||||
}
|
||||
|
||||
const update = await this.update.getUpdate()
|
||||
if (this.update.isLatestVersion(update)) {
|
||||
return `<div class="block-row">
|
||||
<div class="item">
|
||||
Latest: ${update.version}
|
||||
<div class="sub">Up to date</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
${humanize(update.checked)}
|
||||
<a class="sub -link" href="${base}/update/check?to=${this.options.base}">Check now</a>
|
||||
</div>
|
||||
<div class="item" >Current: ${this.update.currentVersion}</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
return `<div class="block-row">
|
||||
<div class="item">
|
||||
Latest: ${update.version}
|
||||
<div class="sub">Out of date</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
${humanize(update.checked)}
|
||||
<a class="sub -link" href="${base}/update?to=${this.options.base}">Update now</a>
|
||||
</div>
|
||||
<div class="item" >Current: ${this.update.currentVersion}</div>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
import * as http from "http"
|
||||
import * as limiter from "limiter"
|
||||
import * as querystring from "querystring"
|
||||
import { HttpCode, HttpError } from "../../common/http"
|
||||
import { AuthType, HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
|
||||
import { hash, humanPath } from "../util"
|
||||
|
||||
interface LoginPayload {
|
||||
password?: string
|
||||
/**
|
||||
* Since we must set a cookie with an absolute path, we need to know the full
|
||||
* base path.
|
||||
*/
|
||||
base?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Login HTTP provider.
|
||||
*/
|
||||
export class LoginHttpProvider extends HttpProvider {
|
||||
public constructor(
|
||||
options: HttpProviderOptions,
|
||||
private readonly configFile: string,
|
||||
private readonly envPassword: boolean,
|
||||
) {
|
||||
super(options)
|
||||
}
|
||||
|
||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
if (this.options.auth !== AuthType.Password || !this.isRoot(route)) {
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
switch (route.base) {
|
||||
case "/":
|
||||
switch (request.method) {
|
||||
case "POST":
|
||||
this.ensureMethod(request, ["GET", "POST"])
|
||||
return this.tryLogin(route, request)
|
||||
default:
|
||||
this.ensureMethod(request)
|
||||
if (this.authenticated(request)) {
|
||||
return {
|
||||
redirect: (Array.isArray(route.query.to) ? route.query.to[0] : route.query.to) || "/",
|
||||
query: { to: undefined },
|
||||
}
|
||||
}
|
||||
return this.getRoot(route)
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpError("Not found", HttpCode.NotFound)
|
||||
}
|
||||
|
||||
public async getRoot(route: Route, error?: Error): Promise<HttpResponse> {
|
||||
const response = await this.getUtf8Resource(this.rootPath, "src/browser/pages/login.html")
|
||||
response.content = response.content.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
|
||||
let passwordMsg = `Check the config file at ${humanPath(this.configFile)} for the password.`
|
||||
if (this.envPassword) {
|
||||
passwordMsg = "Password was set from $PASSWORD."
|
||||
}
|
||||
response.content = response.content.replace(/{{PASSWORD_MSG}}/g, passwordMsg)
|
||||
return this.replaceTemplates(route, response)
|
||||
}
|
||||
|
||||
private readonly limiter = new RateLimiter()
|
||||
|
||||
/**
|
||||
* Try logging in. On failure, show the login page with an error.
|
||||
*/
|
||||
private async tryLogin(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
// Already authenticated via cookies?
|
||||
const providedPassword = this.authenticated(request)
|
||||
if (providedPassword) {
|
||||
return { code: HttpCode.Ok }
|
||||
}
|
||||
|
||||
try {
|
||||
if (!this.limiter.try()) {
|
||||
throw new Error("Login rate limited!")
|
||||
}
|
||||
|
||||
const data = await this.getData(request)
|
||||
const payload = data ? querystring.parse(data) : {}
|
||||
return await this.login(payload, route, request)
|
||||
} catch (error) {
|
||||
return this.getRoot(route, error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a cookie if the user is authenticated otherwise throw an error.
|
||||
*/
|
||||
private async login(payload: LoginPayload, route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||
const password = this.authenticated(request, {
|
||||
key: typeof payload.password === "string" ? [hash(payload.password)] : undefined,
|
||||
})
|
||||
|
||||
if (password) {
|
||||
return {
|
||||
redirect: (Array.isArray(route.query.to) ? route.query.to[0] : route.query.to) || "/",
|
||||
query: { to: undefined },
|
||||
cookie:
|
||||
typeof password === "string"
|
||||
? {
|
||||
key: "key",
|
||||
value: password,
|
||||
path: payload.base,
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
// Only log if it was an actual login attempt.
|
||||
if (payload && payload.password) {
|
||||
console.error(
|
||||
"Failed login attempt",
|
||||
JSON.stringify({
|
||||
xForwardedFor: request.headers["x-forwarded-for"],
|
||||
remoteAddress: request.connection.remoteAddress,
|
||||
userAgent: request.headers["user-agent"],
|
||||
timestamp: Math.floor(new Date().getTime() / 1000),
|
||||
}),
|
||||
)
|
||||
|
||||
throw new Error("Incorrect password")
|
||||
}
|
||||
|
||||
throw new Error("Missing password")
|
||||
}
|
||||
}
|
||||
|
||||
// RateLimiter wraps around the limiter library for logins.
|
||||
// It allows 2 logins every minute and 12 logins every hour.
|
||||
class RateLimiter {
|
||||
private readonly minuteLimiter = new limiter.RateLimiter(2, "minute")
|
||||
private readonly hourLimiter = new limiter.RateLimiter(12, "hour")
|
||||
|
||||
public try(): boolean {
|
||||
if (this.minuteLimiter.tryRemoveTokens(1)) {
|
||||
return true
|
||||
}
|
||||
return this.hourLimiter.tryRemoveTokens(1)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user