howcode 0.1.65 → 0.1.67-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/howcode.js +56 -7
- package/package.json +3 -2
package/lib/howcode.js
CHANGED
|
@@ -12,6 +12,13 @@ const packageJson = require('../package.json')
|
|
|
12
12
|
|
|
13
13
|
const APP_NAME = packageJson.howcode.appName
|
|
14
14
|
const RELEASE_BASE_URL = process.env.HOWCODE_BASE_URL || packageJson.howcode.releaseBaseUrl
|
|
15
|
+
const RELEASE_CHANNEL =
|
|
16
|
+
process.env.HOWCODE_RELEASE_CHANNEL || packageJson.howcode.releaseChannel || 'main'
|
|
17
|
+
const CHANNEL_RELEASE_TAGS = { main: 'channel-main', dev: 'channel-dev' }
|
|
18
|
+
const trailingSlashesPattern = /\/+$/
|
|
19
|
+
const trailingChannelPattern = /\/(?:main|dev|channel-main|channel-dev)$/i
|
|
20
|
+
const releaseTagPlaceholderPattern = /\{releaseTag\}/g
|
|
21
|
+
const channelPlaceholderPattern = /\{channel\}/g
|
|
15
22
|
const FETCH_METADATA_TIMEOUT_MS = 30_000
|
|
16
23
|
const DOWNLOAD_IDLE_TIMEOUT_MS = 60_000
|
|
17
24
|
|
|
@@ -84,15 +91,35 @@ function getCacheRoot() {
|
|
|
84
91
|
return path.join(process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache'), APP_NAME)
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
function getReleaseChannel() {
|
|
95
|
+
if (RELEASE_CHANNEL === 'main' || RELEASE_CHANNEL === 'dev') return RELEASE_CHANNEL
|
|
96
|
+
throw new Error(`Unsupported release channel: ${RELEASE_CHANNEL}`)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getChannelReleaseTag(channel) {
|
|
100
|
+
return CHANNEL_RELEASE_TAGS[channel]
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getReleaseBaseUrl(channel = getReleaseChannel()) {
|
|
104
|
+
const releaseTag = getChannelReleaseTag(channel)
|
|
105
|
+
const baseUrl = RELEASE_BASE_URL.replace(trailingSlashesPattern, '')
|
|
106
|
+
|
|
107
|
+
if (baseUrl.includes('{releaseTag}'))
|
|
108
|
+
return baseUrl.replace(releaseTagPlaceholderPattern, releaseTag)
|
|
109
|
+
if (baseUrl.includes('{channel}')) return baseUrl.replace(channelPlaceholderPattern, releaseTag)
|
|
110
|
+
|
|
111
|
+
return baseUrl.replace(trailingChannelPattern, `/${releaseTag}`)
|
|
112
|
+
}
|
|
113
|
+
|
|
87
114
|
function getPaths(target, releaseInfo) {
|
|
88
115
|
const cacheRoot = getCacheRoot()
|
|
89
116
|
const versionsRoot = path.join(cacheRoot, 'versions')
|
|
90
|
-
const releaseKey = `${releaseInfo.version}-${releaseInfo.hash}`
|
|
117
|
+
const releaseKey = `${releaseInfo.channel}-${releaseInfo.version}-${releaseInfo.hash}`
|
|
91
118
|
const installDir = path.join(versionsRoot, releaseKey)
|
|
92
119
|
const launcherWorkingDirectory = path.dirname(path.join(installDir, target.executable))
|
|
93
120
|
return {
|
|
94
121
|
cacheRoot,
|
|
95
|
-
currentFile: path.join(cacheRoot,
|
|
122
|
+
currentFile: path.join(cacheRoot, `current-${releaseInfo.channel}.json`),
|
|
96
123
|
windowsCommandFile: path.join(cacheRoot, `${APP_NAME}.cmd`),
|
|
97
124
|
launcherWorkingDirectory,
|
|
98
125
|
installDir,
|
|
@@ -344,16 +371,22 @@ async function sha256File(filePath) {
|
|
|
344
371
|
}
|
|
345
372
|
|
|
346
373
|
async function resolveLatestRelease(target) {
|
|
347
|
-
const
|
|
374
|
+
const channel = getReleaseChannel()
|
|
375
|
+
const releaseBaseUrl = getReleaseBaseUrl(channel)
|
|
376
|
+
const updateUrl = `${releaseBaseUrl}/stable-${target.os}-${target.arch}-update.json`
|
|
348
377
|
const metadata = await fetchJson(updateUrl)
|
|
349
378
|
if (!metadata || typeof metadata.version !== 'string' || typeof metadata.hash !== 'string') {
|
|
350
379
|
throw new Error(`Invalid release metadata from ${updateUrl}`)
|
|
351
380
|
}
|
|
352
381
|
|
|
353
382
|
return {
|
|
383
|
+
channel,
|
|
354
384
|
version: metadata.version,
|
|
355
385
|
hash: metadata.hash,
|
|
356
|
-
assetUrl:
|
|
386
|
+
assetUrl:
|
|
387
|
+
typeof metadata.assetUrl === 'string' && metadata.assetUrl.length > 0
|
|
388
|
+
? metadata.assetUrl
|
|
389
|
+
: `${releaseBaseUrl}/${APP_NAME}-${target.os}-${target.arch}.tar.gz`,
|
|
357
390
|
}
|
|
358
391
|
}
|
|
359
392
|
|
|
@@ -399,6 +432,7 @@ async function installRelease(target, releaseInfo, paths) {
|
|
|
399
432
|
JSON.stringify(
|
|
400
433
|
{
|
|
401
434
|
version: releaseInfo.version,
|
|
435
|
+
channel: releaseInfo.channel,
|
|
402
436
|
hash: releaseInfo.hash,
|
|
403
437
|
installDir: paths.installDir,
|
|
404
438
|
executablePath: paths.executablePath,
|
|
@@ -409,8 +443,22 @@ async function installRelease(target, releaseInfo, paths) {
|
|
|
409
443
|
)
|
|
410
444
|
}
|
|
411
445
|
|
|
446
|
+
async function getPruneKeepDirs(cacheRoot, keepDir) {
|
|
447
|
+
const keepDirs = new Set([keepDir])
|
|
448
|
+
|
|
449
|
+
for (const channel of Object.keys(CHANNEL_RELEASE_TAGS)) {
|
|
450
|
+
const record = readJsonIfPresent(path.join(cacheRoot, `current-${channel}.json`))
|
|
451
|
+
if (record?.installDir) {
|
|
452
|
+
keepDirs.add(record.installDir)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return keepDirs
|
|
457
|
+
}
|
|
458
|
+
|
|
412
459
|
async function pruneOldVersions(cacheRoot, keepDir) {
|
|
413
460
|
const versionsRoot = path.join(cacheRoot, 'versions')
|
|
461
|
+
const keepDirs = await getPruneKeepDirs(cacheRoot, keepDir)
|
|
414
462
|
let entries = []
|
|
415
463
|
|
|
416
464
|
try {
|
|
@@ -423,7 +471,7 @@ async function pruneOldVersions(cacheRoot, keepDir) {
|
|
|
423
471
|
entries
|
|
424
472
|
.filter((entry) => entry.isDirectory())
|
|
425
473
|
.map((entry) => path.join(versionsRoot, entry.name))
|
|
426
|
-
.filter((dirPath) => dirPath
|
|
474
|
+
.filter((dirPath) => !keepDirs.has(dirPath))
|
|
427
475
|
.map((dirPath) => fsp.rm(dirPath, { recursive: true, force: true })),
|
|
428
476
|
)
|
|
429
477
|
}
|
|
@@ -456,7 +504,8 @@ async function main() {
|
|
|
456
504
|
const cacheRoot = getCacheRoot()
|
|
457
505
|
await fsp.mkdir(cacheRoot, { recursive: true })
|
|
458
506
|
|
|
459
|
-
const
|
|
507
|
+
const channel = getReleaseChannel()
|
|
508
|
+
const current = readJsonIfPresent(path.join(cacheRoot, `current-${channel}.json`))
|
|
460
509
|
|
|
461
510
|
let releaseInfo = null
|
|
462
511
|
try {
|
|
@@ -465,7 +514,7 @@ async function main() {
|
|
|
465
514
|
if (current?.executablePath) {
|
|
466
515
|
const currentPaths = {
|
|
467
516
|
cacheRoot,
|
|
468
|
-
currentFile: path.join(cacheRoot,
|
|
517
|
+
currentFile: path.join(cacheRoot, `current-${channel}.json`),
|
|
469
518
|
windowsCommandFile: path.join(cacheRoot, `${APP_NAME}.cmd`),
|
|
470
519
|
installDir: current.installDir || path.dirname(path.dirname(current.executablePath)),
|
|
471
520
|
launcherWorkingDirectory: path.dirname(current.executablePath),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "howcode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.67-dev.0",
|
|
4
4
|
"description": "Desktop coding app for Pi with projects, terminal, git, and diff workflows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Igor Warzocha",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"howcode": {
|
|
40
40
|
"appName": "howcode",
|
|
41
|
-
"
|
|
41
|
+
"releaseChannel": "dev",
|
|
42
|
+
"releaseBaseUrl": "https://github.com/IgorWarzocha/howcode/releases/download/channel-dev"
|
|
42
43
|
}
|
|
43
44
|
}
|