mirror of
https://github.com/zen-browser/surfer.git
synced 2025-07-13 11:45:32 +02:00
182 lines
5.2 KiB
TypeScript
182 lines
5.2 KiB
TypeScript
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
import { existsSync } from 'fs'
|
|
import {
|
|
copyFile,
|
|
mkdir,
|
|
readdir,
|
|
readFile,
|
|
stat,
|
|
unlink,
|
|
writeFile,
|
|
} from 'fs/promises'
|
|
import { dirname, join, resolve } from 'path'
|
|
import { parse } from 'ini'
|
|
import { create } from 'xmlbuilder2'
|
|
import { createHash } from 'crypto'
|
|
import { isAppleSilicon } from 'is-apple-silicon'
|
|
|
|
import { bin_name, config } from '..'
|
|
import { DIST_DIR, ENGINE_DIR, OBJ_DIR } from '../constants'
|
|
import { log } from '../log'
|
|
import {
|
|
configDispatch,
|
|
dispatch,
|
|
dynamicConfig,
|
|
ensureEmpty,
|
|
ReleaseInfo,
|
|
windowsPathToUnix,
|
|
} from '../utils'
|
|
import { generateBrowserUpdateFiles } from './updates/browser'
|
|
|
|
const machPath = resolve(ENGINE_DIR, 'mach')
|
|
|
|
export const melonPackage = async () => {
|
|
const brandingKey = dynamicConfig.get('brand') as string
|
|
const brandingDetails = config.brands[brandingKey]
|
|
|
|
const version = brandingDetails.release.displayVersion
|
|
const channel = brandingKey || 'unofficial'
|
|
|
|
// The engine directory must have been downloaded for this to be valid
|
|
// TODO: Make this a reusable function that can be used by everything
|
|
if (!existsSync(ENGINE_DIR)) {
|
|
log.error(
|
|
`Unable to locate any source directories.\nRun |${bin_name} download| to generate the source directory.`
|
|
)
|
|
}
|
|
|
|
if (!existsSync(machPath)) {
|
|
log.error(`Cannot locate the 'mach' binary within ${ENGINE_DIR}`)
|
|
}
|
|
|
|
const args = ['package']
|
|
|
|
log.info(
|
|
`Packaging \`${config.binaryName}\` with args ${JSON.stringify(
|
|
args.slice(1, 0)
|
|
)}...`
|
|
)
|
|
|
|
await dispatch(machPath, args, ENGINE_DIR, true)
|
|
|
|
log.info('Copying results up')
|
|
|
|
log.debug("Creating the dist directory if it doesn't exist")
|
|
if (!existsSync(DIST_DIR)) await mkdir(DIST_DIR, { recursive: true })
|
|
|
|
log.debug('Indexing files to copy')
|
|
const files = (await readdir(join(OBJ_DIR, 'dist'), { withFileTypes: true }))
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => entry.name)
|
|
|
|
for (const file of files) {
|
|
const destFile = join(DIST_DIR, file)
|
|
log.debug(`Copying ${file}`)
|
|
if (existsSync(destFile)) await unlink(destFile)
|
|
await copyFile(join(OBJ_DIR, 'dist', file), destFile)
|
|
}
|
|
|
|
// Windows has some special dist files that are available within the dist
|
|
// directory.
|
|
if (process.platform == 'win32') {
|
|
const installerDistDirectory = join(OBJ_DIR, 'dist', 'install', 'sea')
|
|
|
|
if (!existsSync(installerDistDirectory)) {
|
|
log.error(
|
|
`Could not find windows installer files located at '${installerDistDirectory}'`
|
|
)
|
|
}
|
|
|
|
const windowsInstallerFiles = (
|
|
await readdir(installerDistDirectory, { withFileTypes: true })
|
|
)
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => entry.name)
|
|
|
|
for (const file of windowsInstallerFiles) {
|
|
let newFileName = file
|
|
|
|
// There are some special cases that I want to reformat the name for
|
|
if (file.includes('.installer.exe')) {
|
|
newFileName = `${config.binaryName}.installer.exe`
|
|
}
|
|
if (file.includes('.installer-stub.exe')) {
|
|
newFileName = `${config.binaryName}.installer.pretty.exe`
|
|
log.warning(
|
|
`The installer ${newFileName} requires that your binaries are available from the internet and everything is correctly configured. I recommend you ship '${config.binaryName}.installer.exe' if you have not set this up correctly yet`
|
|
)
|
|
}
|
|
|
|
// Actually copy
|
|
const destFile = join(DIST_DIR, newFileName)
|
|
log.debug(`Copying ${file}`)
|
|
if (existsSync(destFile)) await unlink(destFile)
|
|
await copyFile(join(installerDistDirectory, file), destFile)
|
|
}
|
|
}
|
|
|
|
const marPath = await createMarFile(version, channel)
|
|
dynamicConfig.set('marPath', marPath)
|
|
|
|
await generateBrowserUpdateFiles()
|
|
|
|
log.info()
|
|
log.info(`Output written to ${DIST_DIR}`)
|
|
|
|
log.success('Packaging complected!')
|
|
}
|
|
|
|
function getCurrentBrandName(): string {
|
|
const brand = dynamicConfig.get('brand') as string
|
|
|
|
if (brand == 'unofficial') {
|
|
return 'Nightly'
|
|
}
|
|
|
|
return config.brands[brand].brandFullName
|
|
}
|
|
|
|
async function createMarFile(version: string, channel: string) {
|
|
log.info(`Creating mar file...`)
|
|
let marBinary: string = windowsPathToUnix(
|
|
join(OBJ_DIR, 'dist/host/bin', 'mar')
|
|
)
|
|
|
|
if (process.platform == 'win32') {
|
|
marBinary += '.exe'
|
|
}
|
|
|
|
// On macos this should be
|
|
// <obj dir>/dist/${binaryName}/${brandFullName}.app and on everything else,
|
|
// the contents of the folder <obj dir>/dist/${binaryName}
|
|
let binary: string
|
|
|
|
if (process.platform == 'darwin') {
|
|
binary = join(
|
|
OBJ_DIR,
|
|
'dist',
|
|
config.binaryName,
|
|
`${getCurrentBrandName()}.app`
|
|
)
|
|
} else {
|
|
binary = join(OBJ_DIR, 'dist', config.binaryName)
|
|
}
|
|
|
|
const marPath = windowsPathToUnix(join(DIST_DIR, 'output.mar'))
|
|
await configDispatch('./tools/update-packaging/make_full_update.sh', {
|
|
args: [
|
|
// The mar output location
|
|
windowsPathToUnix(join(DIST_DIR)),
|
|
binary,
|
|
],
|
|
cwd: ENGINE_DIR,
|
|
env: {
|
|
MOZ_PRODUCT_VERSION: version,
|
|
MAR_CHANNEL_ID: channel,
|
|
MAR: marBinary,
|
|
},
|
|
})
|
|
return marPath
|
|
}
|