Skip to content

Commit db54f78

Browse files
committed
Implement automatic updates
1 parent b8fa7da commit db54f78

File tree

14 files changed

+531
-36
lines changed

14 files changed

+531
-36
lines changed

package.json

+6-3
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
},
2222
"devDependencies": {
2323
"@coder/nbin": "^1.2.7",
24+
"@types/adm-zip": "^0.4.32",
2425
"@types/fs-extra": "^8.0.1",
2526
"@types/mocha": "^5.2.7",
2627
"@types/node": "^12.12.7",
2728
"@types/parcel-bundler": "^1.12.1",
2829
"@types/pem": "^1.9.5",
2930
"@types/safe-compare": "^1.1.0",
30-
"@types/tar-fs": "^1.16.1",
31-
"@types/tar-stream": "^1.6.1",
31+
"@types/semver": "^7.1.0",
32+
"@types/tar-fs": "^1.16.2",
3233
"@types/ws": "^6.0.4",
3334
"@typescript-eslint/eslint-plugin": "^2.0.0",
3435
"@typescript-eslint/parser": "^2.0.0",
@@ -52,12 +53,14 @@
5253
},
5354
"dependencies": {
5455
"@coder/logger": "1.1.11",
56+
"adm-zip": "^0.4.14",
5557
"fs-extra": "^8.1.0",
5658
"httpolyglot": "^0.1.2",
5759
"pem": "^1.14.2",
5860
"safe-compare": "^1.1.4",
61+
"semver": "^7.1.3",
62+
"tar": "^6.0.1",
5963
"tar-fs": "^2.0.0",
60-
"tar-stream": "^2.1.0",
6164
"ws": "^7.2.0"
6265
}
6366
}

src/browser/pages/app.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import "./error.css"
55
import "./global.css"
66
import "./home.css"
77
import "./login.css"
8+
import "./update.css"
89

910
const options = getOptions()
1011
const parts = window.location.pathname.replace(/^\//g, "").split("/")

src/browser/pages/global.css

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ body {
1616

1717
button {
1818
font-family: inherit;
19+
font-size: inherit;
1920
}
2021

2122
.center-container {

src/browser/pages/home.css

+17-13
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,54 @@
1-
.app-lists {
2-
max-width: 400px;
1+
.info-blocks {
2+
max-width: 500px;
33
width: 100%;
44
}
55

6-
.app-list > .header {
7-
margin: 1rem 0;
6+
.info-block > .header {
7+
font-size: 1.3rem;
8+
margin: 1.5rem 0;
89
}
910

10-
.app-list > .none {
11+
.info-block > .none {
1112
color: #b6b6b6;
1213
}
1314

14-
.app-list + .app-list {
15+
.info-block + .info-block {
1516
border-top: 1px solid #666;
1617
margin-top: 1rem;
1718
}
1819

19-
.app-row {
20+
.block-row {
2021
display: flex;
2122
}
2223

23-
.app-row > .open {
24+
.block-row > .item {
2425
color: #b6b6b6;
25-
cursor: pointer;
2626
display: flex;
2727
flex: 1;
2828
text-decoration: none;
2929
}
3030

31-
.app-row > .open:hover {
31+
.block-row > .item.-link {
32+
cursor: pointer;
33+
}
34+
35+
.block-row > .item.-link:hover {
3236
color: #fafafa;
3337
}
3438

35-
.app-row > .open > .icon {
39+
.block-row > .item > .icon {
3640
height: 1rem;
3741
margin-right: 5px;
3842
width: 1rem;
3943
}
4044

41-
.app-row > .open > .icon.-missing {
45+
.block-row > .item > .icon.-missing {
4246
background-color: #eee;
4347
color: #b6b6b6;
4448
text-align: center;
4549
}
4650

47-
.app-row > .open > .icon.-missing::after {
51+
.block-row > .item > .icon.-missing::after {
4852
content: "?";
4953
font-size: 0.7rem;
5054
vertical-align: middle;

src/browser/pages/home.html

+9-4
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@
1313
</head>
1414
<body>
1515
<div class="center-container">
16-
<div class="app-lists">
17-
<div class="app-list">
16+
<div class="info-blocks">
17+
<div class="info-block">
1818
<h2 class="header">Running Applications</h2>
1919
{{APP_LIST:RUNNING}}
2020
</div>
2121

22-
<div class="app-list">
22+
<div class="info-block">
23+
<h2 class="header">Update</h2>
24+
{{UPDATE:NAME}}
25+
</div>
26+
27+
<div class="info-block">
2328
<h2 class="header">Editors</h2>
2429
{{APP_LIST:EDITORS}}
2530
</div>
2631

27-
<div class="app-list">
32+
<div class="info-block">
2833
<h2 class="header">Other</h2>
2934
{{APP_LIST:OTHER}}
3035
</div>

src/browser/pages/update.css

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
.update-form {
2+
text-align: center;
3+
}
4+
5+
.update-form > .apply {
6+
background-color: transparent;
7+
color: #b6b6b6;
8+
cursor: pointer;
9+
border: 1px solid #b6b6b6;
10+
box-sizing: border-box;
11+
padding: 1rem 2rem;
12+
}
13+
14+
.update-form > .apply:hover {
15+
color: #fafafa;
16+
border-color: #fafafa;
17+
}
18+
19+
.update-form > .current {
20+
margin-top: 1rem;
21+
}
22+
23+
.update-form > .links {
24+
margin-top: 1rem;
25+
}
26+
27+
.update-form > .links > .link {
28+
color: #b6b6b6;
29+
text-decoration: none;
30+
}
31+
32+
.update-form > .links > .link:hover {
33+
color: #fcfcfc;
34+
text-decoration: underline;
35+
}
36+
37+
.update-form > .error {
38+
color: red;
39+
margin-top: 1rem;
40+
}

src/browser/pages/update.html

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
6+
<meta http-equiv="Content-Security-Policy" content="style-src 'self'; manifest-src 'self'; img-src 'self' data:;">
7+
<title>code-server</title>
8+
<link rel="icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
9+
<link rel="manifest" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/manifest.json" crossorigin="use-credentials">
10+
<link rel="apple-touch-icon" href="{{BASE}}/static-{{COMMIT}}/src/browser/media/code-server.png" />
11+
<link href="{{BASE}}/static-{{COMMIT}}/dist/app.css" rel="stylesheet">
12+
</head>
13+
<body>
14+
<div class="center-container">
15+
<form class="update-form" method="post">
16+
<h2 class="header">Update</h2>
17+
{{UPDATE_STATUS}}
18+
{{ERROR}}
19+
<div class="links">
20+
<a class="link" href="{{BASE}}">go home</a>
21+
</div>
22+
</form>
23+
</div>
24+
</body>
25+
</html>

src/node/app/app.ts

+33-8
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ import { HttpCode, HttpError } from "../../common/http"
66
import { Options } from "../../common/util"
77
import { HttpProvider, HttpProviderOptions, HttpResponse, Route } from "../http"
88
import { ApiHttpProvider } from "./api"
9+
import { UpdateHttpProvider } from "./update"
910

1011
/**
1112
* Top-level and fallback HTTP provider.
1213
*/
1314
export class MainHttpProvider extends HttpProvider {
14-
public constructor(options: HttpProviderOptions, private readonly api: ApiHttpProvider) {
15+
public constructor(
16+
options: HttpProviderOptions,
17+
private readonly api: ApiHttpProvider,
18+
private readonly update: UpdateHttpProvider
19+
) {
1520
super(options)
1621
}
1722

@@ -77,13 +82,14 @@ export class MainHttpProvider extends HttpProvider {
7782
response.content = response.content
7883
.replace(/{{COMMIT}}/g, this.options.commit)
7984
.replace(/{{BASE}}/g, this.base(route))
80-
.replace(/{{APP_LIST:RUNNING}}/g, this.getAppRows(recent.running))
85+
.replace(/{{UPDATE:NAME}}/, await this.getUpdate())
86+
.replace(/{{APP_LIST:RUNNING}}/, this.getAppRows(recent.running))
8187
.replace(
82-
/{{APP_LIST:EDITORS}}/g,
88+
/{{APP_LIST:EDITORS}}/,
8389
this.getAppRows(apps.filter((app) => app.categories && app.categories.includes("Editor")))
8490
)
8591
.replace(
86-
/{{APP_LIST:OTHER}}/g,
92+
/{{APP_LIST:OTHER}}/,
8793
this.getAppRows(apps.filter((app) => !app.categories || !app.categories.includes("Editor")))
8894
)
8995
return response
@@ -94,8 +100,8 @@ export class MainHttpProvider extends HttpProvider {
94100
response.content = response.content
95101
.replace(/{{COMMIT}}/g, this.options.commit)
96102
.replace(/{{BASE}}/g, this.base(route))
97-
.replace(/{{APP_NAME}}/g, name)
98-
.replace(/"{{OPTIONS}}"/g, `'${JSON.stringify(options)}'`)
103+
.replace(/{{APP_NAME}}/, name)
104+
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
99105
return response
100106
}
101107

@@ -108,8 +114,8 @@ export class MainHttpProvider extends HttpProvider {
108114
}
109115

110116
private getAppRow(app: Application): string {
111-
return `<div class="app-row">
112-
<a class="open" href=".${app.path}">
117+
return `<div class="block-row">
118+
<a class="item -link" href=".${app.path}">
113119
${
114120
app.icon
115121
? `<img class="icon" src="data:image/png;base64,${app.icon}"></img>`
@@ -127,4 +133,23 @@ export class MainHttpProvider extends HttpProvider {
127133
}
128134
</div>`
129135
}
136+
137+
private async getUpdate(): Promise<string> {
138+
if (!this.update.enabled) {
139+
return "Updates are disabled"
140+
}
141+
142+
const update = await this.update.getUpdate()
143+
if (!update) {
144+
return `<div class="block-row">
145+
<span class="item">No updates available</span>
146+
<span class="current" >Current: ${this.update.currentVersion}</span>
147+
</div>`
148+
}
149+
150+
return `<div class="block-row">
151+
<a class="item -link" href="./update">Update available: ${update.version}</a>
152+
<span class="current" >Current: ${this.update.currentVersion}</span>
153+
</div>`
154+
}
130155
}

src/node/app/login.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ export class LoginHttpProvider extends HttpProvider {
5050
response.content = response.content
5151
.replace(/{{COMMIT}}/g, this.options.commit)
5252
.replace(/{{BASE}}/g, this.base(route))
53-
.replace(/{{VALUE}}/g, value || "")
54-
.replace(/{{ERROR}}/g, error ? `<div class="error">${error.message}</div>` : "")
53+
.replace(/{{VALUE}}/, value || "")
54+
.replace(/{{ERROR}}/, error ? `<div class="error">${error.message}</div>` : "")
5555
return response
5656
}
5757

0 commit comments

Comments
 (0)