standardnotes-app/packages/components/scripts/package.mjs
Mo 12a2369d17
refactor: mobile components (#1113)
* fix(mobile): freeze web-server assets to zips for mobile 3.23.3

Mobile 3.23.3 fetches components zips from the web-server cdn. This however causes upgraded cdn versions to fail when downloading from older mobile versions. This commit instead fetches versioned zips from an external cdn based on the static version of the app requesting the asset.

Since web-server is no longer needed as a cdn, we will temporarily freeze its zip assets to those that would be requested by Mobile 3.23.3, and commit them to source control so they remain unchanged.

web-server/public/components/assets will remain as-is (dynamically copied during build time of server), and not commited to source control. This cdn directory is only used by the web app.

* chore: disable commitlint length rule

* chore: clear git cache

* refactor: use package name from package file
2022-06-17 16:12:12 -05:00

171 lines
5.3 KiB
JavaScript

import fs from 'fs'
import path from 'path'
import crypto from 'crypto'
import { spawnSync as spawn } from 'child_process'
import { GetFeatures } from '@standardnotes/features/dist/Domain/Feature/Features.js'
import { GetDeprecatedFeatures } from '@standardnotes/features/dist/Domain/Feature/Lists/DeprecatedFeatures.js'
import zip from '@standardnotes/deterministic-zip'
import minimatch from 'minimatch'
import { fileURLToPath } from 'url'
import { ensureDirExists, doesDirExist, emptyExistingDir } from '../../../scripts/ScriptUtils.mjs'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
console.log('Beginning packaging procedure...')
const SourceFilesPath = path.join(__dirname, '../src/packages')
const DistDir = path.join(__dirname, '../dist')
const TmpDir = path.join(__dirname, '../tmp')
const ZipsDir = path.join(DistDir, '/zips')
const AssetsDir = path.join(DistDir, '/assets')
const ChecksumsSrcPath = path.join(ZipsDir, 'checksums.json')
const ChecksumsDistPath = path.join(ZipsDir, 'checksums.json')
const Checksums = JSON.parse(fs.readFileSync(ChecksumsSrcPath).toString())
console.log('Loaded existing checksums from', ChecksumsSrcPath)
async function zipDirectory(sourceDir, outPath) {
return new Promise((resolve) => {
zip(sourceDir, outPath, { cwd: sourceDir }, (err) => {
console.log(`Zipped to ${outPath}`)
resolve(outPath)
})
})
}
const copyFileOrDir = (src, dest, exludedFilesGlob) => {
const isDir = fs.lstatSync(src).isDirectory()
if (isDir) {
ensureDirExists(dest)
const entries = fs.readdirSync(src, { withFileTypes: true })
for (const entry of entries) {
const srcPath = path.join(src, entry.name)
const excluded = exludedFilesGlob && minimatch(srcPath, exludedFilesGlob)
if (excluded) {
console.log('Excluding file', srcPath)
continue
}
const destPath = path.join(dest, entry.name)
entry.isDirectory() ? copyFileOrDir(srcPath, destPath) : fs.copyFileSync(srcPath, destPath)
}
} else {
const excluded = exludedFilesGlob && minimatch(src, exludedFilesGlob)
if (excluded) {
console.log('Excluding file', src)
return
}
fs.copyFileSync(src, dest)
}
}
const getComponentSrcPath = (feature) => {
return path.join(SourceFilesPath, feature.identifier)
}
const copyComponentAssets = async (feature, destination, exludedFilesGlob) => {
const srcComponentPath = getComponentSrcPath(feature)
if (!doesDirExist(srcComponentPath)) {
return false
}
emptyExistingDir(destination)
ensureDirExists(destination)
for (const file of feature.static_files) {
const srcFilePath = path.join(srcComponentPath, file)
if (!fs.existsSync(srcFilePath)) {
continue
}
const targetFilePath = path.join(destination, file)
copyFileOrDir(srcFilePath, targetFilePath, exludedFilesGlob)
}
return true
}
const computeChecksum = async (zipPath, version) => {
const zipData = fs.readFileSync(zipPath, 'base64')
const base64 = crypto.createHash('sha256').update(zipData).digest('hex')
const checksumProcess = spawn('sha256sum', [zipPath])
const checksumString = checksumProcess.stdout.toString()
const binary = checksumString.split(' ')[0]
return {
version,
base64,
binary,
}
}
const packageFeature = async ({ feature, noZip }) => {
console.log('Processing feature', feature.identifier, '...')
const assetsLocation = `${path.join(AssetsDir, feature.identifier)}`
const assetsSuccess = await copyComponentAssets(feature, assetsLocation, '**/package.json')
if (!assetsSuccess) {
console.log('Failed to copy assets for', feature.identifier)
return
}
if (noZip) {
console.log('Input arg noZip detected; not zipping asset.')
return
}
const zipAssetsTmpLocation = `${path.join(TmpDir, feature.identifier)}`
const zipAssetsSuccess = await copyComponentAssets(feature, zipAssetsTmpLocation)
if (!zipAssetsSuccess) {
console.log('Failed to copy zip assets for', feature.identifier)
return
}
const zipDestination = `${ZipsDir}/${feature.identifier}.zip`
await zipDirectory(zipAssetsTmpLocation, zipDestination)
const packageJsonFilePath = path.join(getComponentSrcPath(feature), 'package.json')
const packageJsonFile = JSON.parse(fs.readFileSync(packageJsonFilePath).toString())
const checksum = await computeChecksum(zipDestination, packageJsonFile.version)
Checksums[feature.identifier] = checksum
console.log(`Computed checksums for ${feature.identifier}:`, checksum)
}
await (async () => {
const args = process.argv[2]
const noZip = args.includes('--no-zip')
const featuresToProcess = GetFeatures().concat(GetDeprecatedFeatures())
let index = 0
for (const feature of featuresToProcess) {
if (index === 0) {
console.log('\n---\n')
}
if (['SN|Component', 'SN|Theme'].includes(feature.content_type)) {
await packageFeature({ feature, noZip })
} else {
console.log('Feature is not component, not packaging', feature.identifier)
}
if (index !== featuresToProcess.length - 1) {
console.log('\n---\n')
}
index++
}
fs.writeFileSync(ChecksumsSrcPath, JSON.stringify(Checksums, undefined, 2))
copyFileOrDir(ChecksumsSrcPath, ChecksumsDistPath)
console.log('Succesfully wrote checksums to', ChecksumsSrcPath)
emptyExistingDir(TmpDir)
})()