Skip to content

Commit

Permalink
fix(app): cache robot releases manifest for offline usage (#6494)
Browse files Browse the repository at this point in the history
Fixes #5992
  • Loading branch information
mcous authored Sep 14, 2020
1 parent 2bf776b commit 5308562
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 13 deletions.
16 changes: 16 additions & 0 deletions app-shell/src/buildroot/__tests__/release-files.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ describe('buildroot release files utilities', () => {
})
})

it('should leave support files alone', () => {
const dir = makeEmptyDir()
const releaseDir = path.join(dir, '4.0.0')
const releaseManifest = path.join(dir, 'releases.json')

return Promise.all([
fs.mkdir(releaseDir),
fse.writeJson(releaseManifest, { hello: 'world' }),
])
.then(() => cleanupReleaseFiles(dir, '4.0.0'))
.then(() => fs.readdir(dir))
.then(files => {
expect(files).toEqual(['4.0.0', 'releases.json'])
})
})

it('should delete other directories', () => {
const dir = makeEmptyDir()
const releaseDir = path.join(dir, '4.0.0')
Expand Down
57 changes: 57 additions & 0 deletions app-shell/src/buildroot/__tests__/release-manifest.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @flow
import fse from 'fs-extra'
import tempy from 'tempy'
import * as Http from '../../http'
import { downloadManifest } from '../release-manifest'

jest.mock('../../http')

const fetchJson: JestMockFn<[string], mixed> = Http.fetchJson

describe('release manifest utilities', () => {
let manifestFile

beforeEach(() => {
manifestFile = tempy.file({ extension: 'json' })
})

afterEach(() => {
return fse.remove(manifestFile)
})

it('should download the manifest from a url', () => {
const result = { mockResult: true }
const manifestUrl = 'http://example.com/releases.json'

fetchJson.mockImplementation(url => {
if (url === manifestUrl) return Promise.resolve(result)
})

return expect(downloadManifest(manifestUrl, manifestFile)).resolves.toBe(
result
)
})

it('should save the manifest to the given path', () => {
const result = { mockResult: true }
const manifestUrl = 'http://example.com/releases.json'

fetchJson.mockResolvedValue(result)

return downloadManifest(manifestUrl, manifestFile)
.then(() => fse.readJson(manifestFile))
.then(file => expect(file).toEqual(result))
})

it('should pull the manifest from the file if the manifest download fails', () => {
const manifest = { mockResult: true }
const manifestUrl = 'http://example.com/releases.json'

fse.writeJsonSync(manifestFile, manifest)
fetchJson.mockRejectedValue(new Error('AH'))

return downloadManifest(manifestUrl, manifestFile).then(result =>
expect(result).toEqual(manifest)
)
})
})
26 changes: 18 additions & 8 deletions app-shell/src/buildroot/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {
const log = createLogger('buildroot/index')

const DIRECTORY = path.join(app.getPath('userData'), '__ot_buildroot__')
const MANIFEST_CACHE = path.join(DIRECTORY, 'releases.json')

let checkingForUpdates = false
let updateSet: ReleaseSetFilepaths | null = null
Expand Down Expand Up @@ -119,18 +120,27 @@ export function registerBuildrootUpdate(dispatch: Dispatch): Action => void {
export function getBuildrootUpdateUrls(): Promise<ReleaseSetUrls | null> {
const manifestUrl: string = getConfig('buildroot').manifestUrl

return downloadManifest(manifestUrl).then(manifest => {
const urls = getReleaseSet(manifest, CURRENT_VERSION)
return downloadManifest(manifestUrl, MANIFEST_CACHE)
.then(manifest => {
const urls = getReleaseSet(manifest, CURRENT_VERSION)

if (urls === null) {
log.debug('No release files in manifest', {
if (urls === null) {
log.warn('No release files in manifest', {
version: CURRENT_VERSION,
manifest,
})
}

return urls
})
.catch((error: Error) => {
log.warn('Error retrieving release manifest', {
version: CURRENT_VERSION,
manifest,
error,
})
}

return urls
})
return null
})
}

// check for a buildroot update matching the current app version
Expand Down
6 changes: 3 additions & 3 deletions app-shell/src/buildroot/release-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ export function cleanupReleaseFiles(
downloadsDir: string,
currentRelease: string
): void {
return readdir(downloadsDir)
return readdir(downloadsDir, { withFileTypes: true })
.then(files => {
return files
.filter(f => f !== currentRelease)
.map(f => path.join(downloadsDir, f))
.filter(f => f.isDirectory() && f.name !== currentRelease)
.map(f => path.join(downloadsDir, f.name))
})
.then(removals => Promise.all(removals.map(f => remove(f))))
}
9 changes: 7 additions & 2 deletions app-shell/src/buildroot/release-manifest.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// @flow
// functions and utilities for retrieving the releases manifest
import fse from 'fs-extra'
import { fetchJson } from '../http'
import type { ReleaseManifest, ReleaseSetUrls } from './types'

// TODO(mc, 2019-07-02): cache downloaded manifest
export function downloadManifest(
manifestUrl: string
manifestUrl: string,
cacheFilePath: string
): Promise<ReleaseManifest> {
return fetchJson(manifestUrl)
.then(result => {
return fse.writeJson(cacheFilePath, result).then(() => result)
})
.catch(() => fse.readJson(cacheFilePath))
}

// TODO(mc, 2019-07-02): retrieve something other than "production"
Expand Down

0 comments on commit 5308562

Please sign in to comment.