🎨 Run prettier

This commit is contained in:
trickypr 2021-09-20 11:10:52 +10:00
parent 7a81587f9f
commit 4714fb4bc8
42 changed files with 1786 additions and 2445 deletions

View file

@ -1,7 +1,7 @@
{ {
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"semi": false, "semi": false,
"singleQuote": true, "singleQuote": true,
"trailingComma": "es5" "trailingComma": "es5"
} }

View file

@ -1,2 +1,3 @@
# melon # melon
🍉 Build Firefox-based browsers with ease 🍉 Build Firefox-based browsers with ease

View file

@ -5,7 +5,8 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc" "build": "tsc",
"format": "prettier . -w"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -1,161 +1,148 @@
import { import {
bootstrap, bootstrap,
build, build,
discard, discard,
download, download,
downloadArtifacts, downloadArtifacts,
execute, execute,
exportFile, exportFile,
exportPatches, exportPatches,
fixLineEndings, fixLineEndings,
importPatches, importPatches,
init, init,
licenseCheck, licenseCheck,
melonPackage, melonPackage,
reset, reset,
run, run,
setBranch, setBranch,
status, status,
test test,
} from "./commands"; } from './commands'
import { Cmd } from "./types"; import { Cmd } from './types'
export const commands: Cmd[] = [ export const commands: Cmd[] = [
{ {
cmd: "bootstrap", cmd: 'bootstrap',
description: "Bootstrap Dot Browser.", description: 'Bootstrap Dot Browser.',
controller: bootstrap controller: bootstrap,
},
{
cmd: 'build [os]',
aliases: ['b'],
description:
'Build Dot Browser. Specify the OS param for cross-platform builds.',
options: [
{
arg: '--a, --arch <architecture>',
description: 'Specify architecture for build',
},
],
controller: build,
},
{
cmd: 'discard <file>',
description: 'Discard a files changes.',
options: [
{
arg: '--keep, --keep-patch',
description: 'Keep the patch file instead of removing it',
},
],
controller: discard,
},
{
cmd: 'download [ffVersion]',
description: 'Download Firefox.',
controller: download,
},
{
cmd: 'download-artifacts',
description: 'Download Windows artifacts from GitHub.',
flags: {
platforms: ['win32'],
}, },
{ controller: downloadArtifacts,
cmd: "build [os]", },
aliases: ["b"], {
description: cmd: 'execute',
"Build Dot Browser. Specify the OS param for cross-platform builds.", description: 'Execute a command inside the engine directory.',
options: [ controller: execute,
{ },
arg: "--a, --arch <architecture>", {
description: cmd: 'export-file <file>',
"Specify architecture for build" description: 'Export a changed file as a patch.',
} controller: exportFile,
], },
controller: build {
}, cmd: 'export',
{ aliases: ['export-patches'],
cmd: "discard <file>", description: 'Export the changed files as patches.',
description: "Discard a files changes.", controller: exportPatches,
options: [ },
{ {
arg: "--keep, --keep-patch", cmd: 'lfify',
description: aliases: ['fix-le'],
"Keep the patch file instead of removing it" description: 'Convert CRLF line endings to Unix LF line endings.',
} controller: fixLineEndings,
], },
controller: discard {
}, cmd: 'import [type]',
{ aliases: ['import-patches', 'i'],
cmd: "download [ffVersion]", description: 'Import patches into the browser.',
description: "Download Firefox.", options: [
controller: download {
}, arg: '-m, --minimal',
{ description: 'Import patches in minimal mode',
cmd: "download-artifacts", },
description: {
"Download Windows artifacts from GitHub.", arg: '--noignore',
flags: { description: "Bypass .gitignore. You shouldn't really use this.",
platforms: ["win32"] },
}, ],
controller: downloadArtifacts controller: importPatches,
}, },
{ {
cmd: "execute", cmd: 'init <source>',
description: aliases: ['initialise', 'initialize'],
"Execute a command inside the engine directory.", description: 'Initialise the Firefox directory.',
controller: execute controller: init,
}, },
{ {
cmd: "export-file <file>", cmd: 'license-check',
description: "Export a changed file as a patch.", aliases: ['lc'],
controller: exportFile description: 'Check the src directory for the absence of MPL-2.0 header.',
}, controller: licenseCheck,
{ },
cmd: "export", {
aliases: ["export-patches"], cmd: 'package',
description: aliases: ['pack'],
"Export the changed files as patches.", description: 'Package the browser for distribution.',
controller: exportPatches controller: melonPackage,
}, },
{ {
cmd: "lfify", cmd: 'reset',
aliases: ["fix-le"], description: 'Reset the source directory to stock Firefox.',
description: controller: reset,
"Convert CRLF line endings to Unix LF line endings.", },
controller: fixLineEndings {
}, cmd: 'run [chrome]',
{ aliases: ['r', 'open'],
cmd: "import [type]", description: 'Run the browser.',
aliases: ["import-patches", "i"], controller: run,
description: "Import patches into the browser.", },
options: [ {
{ cmd: 'set-branch <branch>',
arg: "-m, --minimal", description: 'Change the default branch.',
description: controller: setBranch,
"Import patches in minimal mode" },
}, {
{ cmd: 'status',
arg: "--noignore", description: 'Status and files changed for src directory.',
description: controller: status,
"Bypass .gitignore. You shouldn't really use this." },
} {
], cmd: 'test',
controller: importPatches description: 'Run the test suite for Dot Browser.',
}, controller: test,
{ },
cmd: "init <source>", ]
aliases: ["initialise", "initialize"],
description: "Initialise the Firefox directory.",
controller: init
},
{
cmd: "license-check",
aliases: ["lc"],
description:
"Check the src directory for the absence of MPL-2.0 header.",
controller: licenseCheck
},
{
cmd: "package",
aliases: ["pack"],
description:
"Package the browser for distribution.",
controller: melonPackage
},
{
cmd: "reset",
description:
"Reset the source directory to stock Firefox.",
controller: reset
},
{
cmd: "run [chrome]",
aliases: ["r", "open"],
description: "Run the browser.",
controller: run
},
{
cmd: "set-branch <branch>",
description: "Change the default branch.",
controller: setBranch
},
{
cmd: "status",
description:
"Status and files changed for src directory.",
controller: status
},
{
cmd: "test",
description:
"Run the test suite for Dot Browser.",
controller: test
}
];

View file

@ -1,89 +1,81 @@
/// <reference path="./linus.d.ts"/> /// <reference path="./linus.d.ts"/>
import distro from "linus"; import distro from 'linus'
import { bin_name } from ".."; import { bin_name } from '..'
import { log } from "../"; import { log } from '../'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
import { pacmanInstall } from "./bootstrap/arch"; import { pacmanInstall } from './bootstrap/arch'
export const bootstrap = async () => { export const bootstrap = async () => {
if (process.platform == "win32") if (process.platform == 'win32')
log.error( log.error(
`You do not need to bootstrap on Windows. As long as you ran |${bin_name} download-artifacts| everything should work fine.` `You do not need to bootstrap on Windows. As long as you ran |${bin_name} download-artifacts| everything should work fine.`
); )
log.info(`Bootstrapping Dot Browser for Desktop...`); log.info(`Bootstrapping Dot Browser for Desktop...`)
const args = ["--application-choice", "browser"]; const args = ['--application-choice', 'browser']
if (process.platform === "linux") { if (process.platform === 'linux') {
linuxBootstrap(); linuxBootstrap()
} else { } else {
console.info( console.info(
`Custom bootstrapping doesn't work on ${process.platform}. Consider contributing to improve support` `Custom bootstrapping doesn't work on ${process.platform}. Consider contributing to improve support`
); )
console.info( console.info(`Passing through to |mach bootstrap|`)
`Passing through to |mach bootstrap|`
);
await dispatch( await dispatch(`./mach`, ['bootstrap', ...args], ENGINE_DIR)
`./mach`, }
["bootstrap", ...args], }
ENGINE_DIR
);
}
};
function getDistro(): Promise<string> { function getDistro(): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
distro.name((err: Error, name: string) => { distro.name((err: Error, name: string) => {
if (name) resolve(name); if (name) resolve(name)
else { else {
reject( reject(err || 'Failed to get linux distro')
err || "Failed to get linux distro" }
); })
} })
});
});
} }
async function linuxBootstrap() { async function linuxBootstrap() {
const distro = await getDistro(); const distro = await getDistro()
switch (distro) { switch (distro) {
// Both arch and manjaro use the same package repo and the same package manager // Both arch and manjaro use the same package repo and the same package manager
case "ManjaroLinux": case 'ManjaroLinux':
case "ArchLinux": case 'ArchLinux':
console.log( console.log(
await pacmanInstall( await pacmanInstall(
// Shared packages // Shared packages
"base-devel", 'base-devel',
"nodejs", 'nodejs',
"unzip", 'unzip',
"zip", 'zip',
// Needed for desktop apps // Needed for desktop apps
"alsa-lib", 'alsa-lib',
"dbus-glib", 'dbus-glib',
"gtk3", 'gtk3',
"libevent", 'libevent',
"libvpx", 'libvpx',
"libxt", 'libxt',
"mime-types", 'mime-types',
"nasm", 'nasm',
"startup-notification", 'startup-notification',
"gst-plugins-base-libs", 'gst-plugins-base-libs',
"libpulse", 'libpulse',
"xorg-server-xvfb", 'xorg-server-xvfb',
"gst-libav", 'gst-libav',
"gst-plugins-good" 'gst-plugins-good'
) )
); )
break; break
default: default:
log.error(`Unimplemented distro '${distro}'`); log.error(`Unimplemented distro '${distro}'`)
} }
} }

View file

@ -1,14 +1,6 @@
import execa from "execa"; import execa from 'execa'
export async function pacmanInstall( export async function pacmanInstall(...packages: string[]): Promise<string> {
...packages: string[] return (await execa('sudo', ['pacman', '--noconfirm', '-S', ...packages]))
): Promise<string> { .stdout
return (
await execa("sudo", [
"pacman",
"--noconfirm",
"-S",
...packages
])
).stdout;
} }

View file

@ -1,187 +1,129 @@
import execa from "execa"; import execa from 'execa'
import { existsSync, readFileSync, writeFileSync } from 'fs'
import { join, resolve } from 'path'
import { bin_name, log } from '..'
import { import {
existsSync, ARCHITECTURE,
readFileSync, BUILD_TARGETS,
writeFileSync CONFIGS_DIR,
} from "fs"; ENGINE_DIR,
import { join, resolve } from "path"; } from '../constants'
import { bin_name, log } from ".."; import { dispatch } from '../utils'
import {
ARCHITECTURE,
BUILD_TARGETS,
CONFIGS_DIR,
ENGINE_DIR
} from "../constants";
import { dispatch } from "../utils";
const platform: any = { const platform: any = {
win32: "windows", win32: 'windows',
darwin: "macos", darwin: 'macos',
linux: "linux" linux: 'linux',
};
const applyConfig = async (os: string, arch: string) => {
log.info("Applying mozconfig...");
let commonConfig = readFileSync(
resolve(CONFIGS_DIR, "common", "mozconfig"),
"utf-8"
);
const changesetPrefix = commonConfig
.split("\n")
.find((ln) =>
ln.startsWith("export MOZ_SOURCE_CHANGESET=")
);
const changeset = changesetPrefix?.replace(
/export MOZ_SOURCE_CHANGESET=/,
""
);
const { stdout: gitSha } = await execa("git", [
"rev-parse",
"HEAD"
]);
console.log(changeset, gitSha);
if (changeset)
commonConfig = commonConfig.replace(
changeset,
gitSha
);
writeFileSync(
resolve(CONFIGS_DIR, "common", "mozconfig"),
commonConfig
);
const osConfig = readFileSync(
resolve(
CONFIGS_DIR,
os,
arch === "i686"
? "mozconfig-i686"
: "mozconfig"
),
"utf-8"
);
// Allow a custom config to be placed in /mozconfig. This will not be committed
// to origin
const customConfig = existsSync(
join(process.cwd(), "mozconfig")
)
? readFileSync(
join(process.cwd(), "mozconfig")
).toString()
: "";
const mergedConfig = `# This file is automatically generated. You should only modify this if you know what you are doing!\n\n${commonConfig}\n\n${osConfig}\n\n${customConfig}`;
writeFileSync(
resolve(ENGINE_DIR, "mozconfig"),
mergedConfig
);
log.info(`Config for this \`${os}\` build:`);
mergedConfig.split("\n").map((ln) => {
if (
ln.startsWith("mk") ||
ln.startsWith("ac") ||
ln.startsWith("export")
)
log.info(
`\t${ln
.replace(/mk_add_options /, "")
.replace(/ac_add_options /, "")
.replace(/export /, "")}`
);
});
};
const genericBuild = async (os: string, tier: string) => {
log.info(`Building for "${os}"...`);
log.warning(
`If you get any dependency errors, try running |${bin_name} bootstrap|.`
);
await dispatch(
`./mach`,
["build"].concat(tier ? [tier] : []),
ENGINE_DIR
);
};
const parseDate = (d: number) => {
d = d / 1000;
var h = Math.floor(d / 3600);
var m = Math.floor((d % 3600) / 60);
var s = Math.floor((d % 3600) % 60);
var hDisplay =
h > 0
? h + (h == 1 ? " hour, " : " hours, ")
: "";
var mDisplay =
m > 0
? m + (m == 1 ? " minute, " : " minutes, ")
: "";
var sDisplay =
s > 0
? s + (s == 1 ? " second" : " seconds")
: "";
return hDisplay + mDisplay + sDisplay;
};
const success = (date: number) => {
// mach handles the success messages
console.log();
log.info(
`Total build time: ${parseDate(
Date.now() - date
)}.`
);
};
interface Options {
arch: string;
} }
export const build = async ( const applyConfig = async (os: string, arch: string) => {
tier: string, log.info('Applying mozconfig...')
options: Options
) => {
let d = Date.now();
// Host build let commonConfig = readFileSync(
resolve(CONFIGS_DIR, 'common', 'mozconfig'),
'utf-8'
)
const prettyHost = platform[process.platform as any]; const changesetPrefix = commonConfig
.split('\n')
.find((ln) => ln.startsWith('export MOZ_SOURCE_CHANGESET='))
if (BUILD_TARGETS.includes(prettyHost)) { const changeset = changesetPrefix?.replace(/export MOZ_SOURCE_CHANGESET=/, '')
let arch = "64bit";
if (options.arch) { const { stdout: gitSha } = await execa('git', ['rev-parse', 'HEAD'])
if (!ARCHITECTURE.includes(options.arch))
return log.error(
`We do not support "${
options.arch
}" build right now.\nWe only currently support ${JSON.stringify(
ARCHITECTURE
)}.`
);
else arch = options.arch;
}
applyConfig(prettyHost, options.arch); console.log(changeset, gitSha)
setTimeout(async () => { if (changeset) commonConfig = commonConfig.replace(changeset, gitSha)
await genericBuild(prettyHost, tier).then(
(_) => success(d) writeFileSync(resolve(CONFIGS_DIR, 'common', 'mozconfig'), commonConfig)
);
}, 2500); const osConfig = readFileSync(
resolve(CONFIGS_DIR, os, arch === 'i686' ? 'mozconfig-i686' : 'mozconfig'),
'utf-8'
)
// Allow a custom config to be placed in /mozconfig. This will not be committed
// to origin
const customConfig = existsSync(join(process.cwd(), 'mozconfig'))
? readFileSync(join(process.cwd(), 'mozconfig')).toString()
: ''
const mergedConfig = `# This file is automatically generated. You should only modify this if you know what you are doing!\n\n${commonConfig}\n\n${osConfig}\n\n${customConfig}`
writeFileSync(resolve(ENGINE_DIR, 'mozconfig'), mergedConfig)
log.info(`Config for this \`${os}\` build:`)
mergedConfig.split('\n').map((ln) => {
if (ln.startsWith('mk') || ln.startsWith('ac') || ln.startsWith('export'))
log.info(
`\t${ln
.replace(/mk_add_options /, '')
.replace(/ac_add_options /, '')
.replace(/export /, '')}`
)
})
}
const genericBuild = async (os: string, tier: string) => {
log.info(`Building for "${os}"...`)
log.warning(
`If you get any dependency errors, try running |${bin_name} bootstrap|.`
)
await dispatch(`./mach`, ['build'].concat(tier ? [tier] : []), ENGINE_DIR)
}
const parseDate = (d: number) => {
d = d / 1000
var h = Math.floor(d / 3600)
var m = Math.floor((d % 3600) / 60)
var s = Math.floor((d % 3600) % 60)
var hDisplay = h > 0 ? h + (h == 1 ? ' hour, ' : ' hours, ') : ''
var mDisplay = m > 0 ? m + (m == 1 ? ' minute, ' : ' minutes, ') : ''
var sDisplay = s > 0 ? s + (s == 1 ? ' second' : ' seconds') : ''
return hDisplay + mDisplay + sDisplay
}
const success = (date: number) => {
// mach handles the success messages
console.log()
log.info(`Total build time: ${parseDate(Date.now() - date)}.`)
}
interface Options {
arch: string
}
export const build = async (tier: string, options: Options) => {
let d = Date.now()
// Host build
const prettyHost = platform[process.platform as any]
if (BUILD_TARGETS.includes(prettyHost)) {
let arch = '64bit'
if (options.arch) {
if (!ARCHITECTURE.includes(options.arch))
return log.error(
`We do not support "${
options.arch
}" build right now.\nWe only currently support ${JSON.stringify(
ARCHITECTURE
)}.`
)
else arch = options.arch
} }
};
applyConfig(prettyHost, options.arch)
setTimeout(async () => {
await genericBuild(prettyHost, tier).then((_) => success(d))
}, 2500)
}
}

View file

@ -1,71 +1,61 @@
import execa from "execa"; import execa from 'execa'
import { existsSync, statSync } from "fs"; import { existsSync, statSync } from 'fs'
import { resolve } from "path"; import { resolve } from 'path'
import rimraf from "rimraf"; import rimraf from 'rimraf'
import { log } from ".."; import { log } from '..'
import { ENGINE_DIR, PATCHES_DIR } from "../constants"; import { ENGINE_DIR, PATCHES_DIR } from '../constants'
interface Options { interface Options {
keep?: boolean; keep?: boolean
fromRemote?: string; fromRemote?: string
} }
const remotes = { const remotes = {
ff: (file: string, version: string) => ff: (file: string, version: string) =>
`https://hg.mozilla.org/experimental/firefox-unified-stage/raw-file/FIREFOX_${version `https://hg.mozilla.org/experimental/firefox-unified-stage/raw-file/FIREFOX_${version
.replace(" ", "_") .replace(' ', '_')
.replace(".", "_")}_RELEASE/${file}`, .replace('.', '_')}_RELEASE/${file}`,
dot: (file: string, ref: string) => dot: (file: string, ref: string) =>
`https://raw.githubusercontent.com/dothq/browser-desktop/${ref}/${file}` `https://raw.githubusercontent.com/dothq/browser-desktop/${ref}/${file}`,
}; }
export const discard = async ( export const discard = async (file: string, options: Options) => {
file: string, log.info(`Discarding ${file}...`)
options: Options
) => {
log.info(`Discarding ${file}...`);
if (!statSync(file).isFile()) if (!statSync(file).isFile()) throw new Error('Target must be a file.')
throw new Error("Target must be a file.");
// @todo add remote discard // @todo add remote discard
if (options.fromRemote) { if (options.fromRemote) {
if ( if (options.fromRemote == 'ff' || options.fromRemote == 'firefox') {
options.fromRemote == "ff" || } else if (options.fromRemote == 'dot') {
options.fromRemote == "firefox"
) {
} else if (options.fromRemote == "dot") {
} else {
throw new Error(
"Unrecognised remote type. Expected `ff` or `dot`."
);
}
} else { } else {
if (!existsSync(resolve(ENGINE_DIR, file))) throw new Error('Unrecognised remote type. Expected `ff` or `dot`.')
throw new Error(
`File ${file} could not be found in src directory. Check the path for any mistakes and try again.`
);
const patchFile = resolve(
PATCHES_DIR,
file.replace(/\//g, "-").replace(/\./g, "-") +
".patch"
);
if (!existsSync(patchFile))
throw new Error(
`File ${file} does have an associated patch in the patches directory.`
);
const { stdout, exitCode } = await execa(
"git",
["apply", "-R", "-p", "1", patchFile],
{ cwd: ENGINE_DIR }
);
if (exitCode == 0) {
log.success(`Discarded changes to ${file}.`);
if (!options.keep) rimraf.sync(patchFile);
} else throw new Error(stdout);
} }
}; } else {
if (!existsSync(resolve(ENGINE_DIR, file)))
throw new Error(
`File ${file} could not be found in src directory. Check the path for any mistakes and try again.`
)
const patchFile = resolve(
PATCHES_DIR,
file.replace(/\//g, '-').replace(/\./g, '-') + '.patch'
)
if (!existsSync(patchFile))
throw new Error(
`File ${file} does have an associated patch in the patches directory.`
)
const { stdout, exitCode } = await execa(
'git',
['apply', '-R', '-p', '1', patchFile],
{ cwd: ENGINE_DIR }
)
if (exitCode == 0) {
log.success(`Discarded changes to ${file}.`)
if (!options.keep) rimraf.sync(patchFile)
} else throw new Error(stdout)
}
}

View file

@ -1,81 +1,61 @@
import axios from "axios"; import axios from 'axios'
import execa from "execa"; import execa from 'execa'
import fs from "fs"; import fs from 'fs'
import { homedir } from "os"; import { homedir } from 'os'
import { posix, resolve, sep } from "path"; import { posix, resolve, sep } from 'path'
import { log } from ".."; import { log } from '..'
export const downloadArtifacts = async () => { export const downloadArtifacts = async () => {
if (process.platform !== "win32") if (process.platform !== 'win32')
return log.error( return log.error(
"This is not a Windows machine, will not download artifacts." 'This is not a Windows machine, will not download artifacts.'
); )
if (process.env.MOZILLABUILD) if (process.env.MOZILLABUILD)
return log.error( return log.error(
"Run this command in Git Bash, it does not work in Mozilla Build." 'Run this command in Git Bash, it does not work in Mozilla Build.'
); )
const filename = "mozbuild.tar.bz2"; const filename = 'mozbuild.tar.bz2'
const url = `https://github.com/dothq/windows-artifacts/releases/latest/download/mozbuild.tar.bz2`; const url = `https://github.com/dothq/windows-artifacts/releases/latest/download/mozbuild.tar.bz2`
let home = homedir().split(sep).join(posix.sep); let home = homedir().split(sep).join(posix.sep)
if (process.platform == "win32") { if (process.platform == 'win32') {
home = home = '/' + home.replace(/\:/, '').replace(/\\/g, '/').toLowerCase()
"/" + }
home
.replace(/\:/, "") log.info(`Downloading Windows artifacts...`)
.replace(/\\/g, "/")
.toLowerCase(); const { data, headers } = await axios.get(url, {
responseType: 'stream',
})
const length = headers['content-length']
const writer = fs.createWriteStream(resolve(process.cwd(), filename))
let receivedBytes = 0
data.on('data', (chunk: any) => {
receivedBytes += chunk.length
let rand = Math.floor(Math.random() * 1000 + 1)
if (rand > 999.5) {
let percentCompleted = parseInt(
Math.round((receivedBytes * 100) / length).toFixed(0)
)
if (percentCompleted % 2 == 0 || percentCompleted >= 100) return
log.info(`\t${filename}\t${percentCompleted}%...`)
} }
})
log.info(`Downloading Windows artifacts...`); data.pipe(writer)
const { data, headers } = await axios.get(url, { data.on('end', async () => {
responseType: "stream" log.info('Unpacking mozbuild...')
});
const length = headers["content-length"]; await execa('tar', ['-xvf', filename, '-C', home])
const writer = fs.createWriteStream( log.info('Done extracting mozbuild artifacts.')
resolve(process.cwd(), filename) })
); }
let receivedBytes = 0;
data.on("data", (chunk: any) => {
receivedBytes += chunk.length;
let rand = Math.floor(Math.random() * 1000 + 1);
if (rand > 999.5) {
let percentCompleted = parseInt(
Math.round(
(receivedBytes * 100) / length
).toFixed(0)
);
if (
percentCompleted % 2 == 0 ||
percentCompleted >= 100
)
return;
log.info(
`\t${filename}\t${percentCompleted}%...`
);
}
});
data.pipe(writer);
data.on("end", async () => {
log.info("Unpacking mozbuild...");
await execa("tar", [
"-xvf",
filename,
"-C",
home
]);
log.info("Done extracting mozbuild artifacts.");
});
};

View file

@ -1,269 +1,223 @@
import axios from "axios"; import axios from 'axios'
import chalk from "chalk"; import chalk from 'chalk'
import execa from "execa"; import execa from 'execa'
import fs, { import fs, { existsSync, rmdirSync, writeFileSync } from 'fs'
existsSync, import { ensureDirSync, removeSync } from 'fs-extra'
rmdirSync, import ora from 'ora'
writeFileSync import { homedir } from 'os'
} from "fs"; import { posix, resolve, sep } from 'path'
import { ensureDirSync, removeSync } from "fs-extra"; import { bin_name, log } from '..'
import ora from "ora"; import { ENGINE_DIR } from '../constants'
import { homedir } from "os"; import { getLatestFF, writeMetadata } from '../utils'
import { posix, resolve, sep } from "path"; import { downloadArtifacts } from './download-artifacts'
import { bin_name, log } from "..";
import { ENGINE_DIR } from "../constants";
import { getLatestFF, writeMetadata } from "../utils";
import { downloadArtifacts } from "./download-artifacts";
const pjson = require("../../package.json"); const pjson = require('../../package.json')
let initProgressText = "Initialising..."; let initProgressText = 'Initialising...'
let initProgress: any = ora({ let initProgress: any = ora({
text: `Initialising...`, text: `Initialising...`,
prefixText: chalk.blueBright.bold("00:00:00"), prefixText: chalk.blueBright.bold('00:00:00'),
spinner: { spinner: {
frames: [""] frames: [''],
}, },
indent: 0 indent: 0,
}); })
const onData = (data: any) => { const onData = (data: any) => {
const d = data.toString(); const d = data.toString()
d.split("\n").forEach((line: any) => { d.split('\n').forEach((line: any) => {
if (line.trim().length !== 0) { if (line.trim().length !== 0) {
let t = line.split(" "); let t = line.split(' ')
t.shift(); t.shift()
initProgressText = t.join(" "); initProgressText = t.join(' ')
} }
}); })
}; }
const unpack = async (name: string, version: string) => { const unpack = async (name: string, version: string) => {
let cwd = process.cwd().split(sep).join(posix.sep); let cwd = process.cwd().split(sep).join(posix.sep)
if (process.platform == "win32") { if (process.platform == 'win32') {
cwd = "./"; cwd = './'
}
initProgress.start()
setInterval(() => {
if (initProgress) {
initProgress.text = initProgressText
initProgress.prefixText = chalk.blueBright.bold(log.getDiff())
} }
}, 100)
initProgress.start(); initProgressText = `Unpacking Firefox...`
setInterval(() => { try {
if (initProgress) { rmdirSync(ENGINE_DIR)
initProgress.text = initProgressText; } catch (e) {}
initProgress.prefixText = ensureDirSync(ENGINE_DIR)
chalk.blueBright.bold(log.getDiff());
}
}, 100);
initProgressText = `Unpacking Firefox...`; let tarProc = execa('tar', [
'--transform',
's,firefox-89.0,engine,',
`--show-transformed`,
'-xf',
resolve(cwd, '.dotbuild', 'engines', name),
])
try { ;(tarProc.stdout as any).on('data', onData)
rmdirSync(ENGINE_DIR); ;(tarProc.stdout as any).on('error', onData)
} catch (e) {}
ensureDirSync(ENGINE_DIR);
let tarProc = execa("tar", [ tarProc.on('exit', () => {
"--transform", if (process.env.CI_SKIP_INIT) return log.info('Skipping initialisation.')
"s,firefox-89.0,engine,",
`--show-transformed`,
"-xf",
resolve(cwd, ".dotbuild", "engines", name)
]);
(tarProc.stdout as any).on("data", onData); const initProc = execa(`./${bin_name}`, ['init', 'engine'])
(tarProc.stdout as any).on("error", onData);
tarProc.on("exit", () => { ;(initProc.stdout as any).on('data', onData)
if (process.env.CI_SKIP_INIT) ;(initProc.stdout as any).on('error', onData)
return log.info("Skipping initialisation.");
const initProc = execa(`./${bin_name}`, [ initProc.on('exit', async () => {
"init", initProgressText = ''
"engine" initProgress.stop()
]); initProgress = null
(initProc.stdout as any).on("data", onData); await new Promise((resolve) => setTimeout(resolve, 5000))
(initProc.stdout as any).on("error", onData);
initProc.on("exit", async () => { log.success(
initProgressText = ""; `You should be ready to make changes to Dot Browser.\n\n\t You should import the patches next, run |${bin_name} import|.\n\t To begin building Dot, run |${bin_name} build|.`
initProgress.stop(); )
initProgress = null; console.log()
await new Promise((resolve) => pjson.versions['firefox-display'] = version
setTimeout(resolve, 5000) pjson.versions['firefox'] = version.split('b')[0]
);
log.success( writeFileSync(
`You should be ready to make changes to Dot Browser.\n\n\t You should import the patches next, run |${bin_name} import|.\n\t To begin building Dot, run |${bin_name} build|.` resolve(process.cwd(), 'package.json'),
); JSON.stringify(pjson, null, 4)
console.log(); )
pjson.versions["firefox-display"] = version; await writeMetadata()
pjson.versions["firefox"] =
version.split("b")[0];
writeFileSync( removeSync(resolve(cwd, '.dotbuild', 'engines', name))
resolve(process.cwd(), "package.json"),
JSON.stringify(pjson, null, 4)
);
await writeMetadata(); process.exit(0)
})
})
}
removeSync( export const download = async (firefoxVersion?: string) => {
resolve(cwd, ".dotbuild", "engines", name) if (firefoxVersion)
); log.warning(
`A custom Firefox version is being used. Some features of Dot may not work as expected.`
process.exit(0);
});
});
};
export const download = async (
firefoxVersion?: string
) => {
if (firefoxVersion)
log.warning(
`A custom Firefox version is being used. Some features of Dot may not work as expected.`
);
if (!firefoxVersion) {
firefoxVersion =
pjson.versions["firefox-display"];
}
let version = await getLatestFF();
if (firefoxVersion) {
version = firefoxVersion;
}
const base = `https://archive.mozilla.org/pub/firefox/releases/${version}/source/`;
const filename = `firefox-${version}.source.tar.xz`;
const url = `${base}${filename}`;
log.info(`Locating Firefox release ${version}...`);
ensureDirSync(
resolve(process.cwd(), `.dotbuild`, `engines`)
);
if (
existsSync(
resolve(
process.cwd(),
`.dotbuild`,
`engines`,
`firefox-${version.split("b")[0]}`
)
)
) {
log.error(
`Cannot download version ${
version.split("b")[0]
} as it already exists at "${resolve(
process.cwd(),
`firefox-${version.split("b")[0]}`
)}"`
);
}
if (version == firefoxVersion)
log.info(
`Version is frozen at ${firefoxVersion}!`
);
if (version.includes("b"))
log.warning(
"Version includes non-numeric characters. This is probably a beta."
);
if (
fs.existsSync(
resolve(
process.cwd(),
`.dotbuild`,
`engines`,
"firefox",
version.split("b")[0]
)
) ||
fs.existsSync(
resolve(
process.cwd(),
"firefox",
"firefox-" + version.split("b")[0]
)
)
) )
log.error(
`Workspace with version "${
version.split("b")[0]
}" already exists.\nRemove that workspace and run |${bin_name} download ${version}| again.`
);
log.info(`Downloading Firefox release ${version}...`); if (!firefoxVersion) {
firefoxVersion = pjson.versions['firefox-display']
}
const { data, headers } = await axios.get(url, { let version = await getLatestFF()
responseType: "stream"
});
const length = headers["content-length"]; if (firefoxVersion) {
version = firefoxVersion
}
const writer = fs.createWriteStream( const base = `https://archive.mozilla.org/pub/firefox/releases/${version}/source/`
resolve( const filename = `firefox-${version}.source.tar.xz`
process.cwd(),
`.dotbuild`,
`engines`,
filename
)
);
let receivedBytes = 0; const url = `${base}${filename}`
data.on("data", (chunk: any) => { log.info(`Locating Firefox release ${version}...`)
receivedBytes += chunk.length;
let rand = Math.floor(Math.random() * 1000 + 1); ensureDirSync(resolve(process.cwd(), `.dotbuild`, `engines`))
if (rand > 999.5) { if (
let percentCompleted = parseInt( existsSync(
Math.round( resolve(
(receivedBytes * 100) / length process.cwd(),
).toFixed(0) `.dotbuild`,
); `engines`,
if ( `firefox-${version.split('b')[0]}`
percentCompleted % 2 == 0 || )
percentCompleted >= 100 )
) ) {
return; log.error(
log.info( `Cannot download version ${
`\t${filename}\t${percentCompleted}%...` version.split('b')[0]
); } as it already exists at "${resolve(
} process.cwd(),
}); `firefox-${version.split('b')[0]}`
)}"`
)
}
data.pipe(writer); if (version == firefoxVersion)
log.info(`Version is frozen at ${firefoxVersion}!`)
if (version.includes('b'))
log.warning(
'Version includes non-numeric characters. This is probably a beta.'
)
data.on("end", async () => { if (
await unpack(filename, version); fs.existsSync(
resolve(
process.cwd(),
`.dotbuild`,
`engines`,
'firefox',
version.split('b')[0]
)
) ||
fs.existsSync(
resolve(process.cwd(), 'firefox', 'firefox-' + version.split('b')[0])
)
)
log.error(
`Workspace with version "${
version.split('b')[0]
}" already exists.\nRemove that workspace and run |${bin_name} download ${version}| again.`
)
if (process.platform === "win32") { log.info(`Downloading Firefox release ${version}...`)
if (
existsSync( const { data, headers } = await axios.get(url, {
resolve(homedir(), ".mozbuild") responseType: 'stream',
) })
) {
log.info( const length = headers['content-length']
"Mozbuild directory already exists, not redownloading"
); const writer = fs.createWriteStream(
} else { resolve(process.cwd(), `.dotbuild`, `engines`, filename)
log.info( )
"Mozbuild not found, downloading artifacts."
); let receivedBytes = 0
await downloadArtifacts();
} data.on('data', (chunk: any) => {
} receivedBytes += chunk.length
});
}; let rand = Math.floor(Math.random() * 1000 + 1)
if (rand > 999.5) {
let percentCompleted = parseInt(
Math.round((receivedBytes * 100) / length).toFixed(0)
)
if (percentCompleted % 2 == 0 || percentCompleted >= 100) return
log.info(`\t${filename}\t${percentCompleted}%...`)
}
})
data.pipe(writer)
data.on('end', async () => {
await unpack(filename, version)
if (process.platform === 'win32') {
if (existsSync(resolve(homedir(), '.mozbuild'))) {
log.info('Mozbuild directory already exists, not redownloading')
} else {
log.info('Mozbuild not found, downloading artifacts.')
await downloadArtifacts()
}
}
})
}

View file

@ -1,26 +1,24 @@
import { existsSync } from "fs"; import { existsSync } from 'fs'
import { log } from ".."; import { log } from '..'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
export const execute = async (_: any, cmd: any[]) => { export const execute = async (_: any, cmd: any[]) => {
if (existsSync(ENGINE_DIR)) { if (existsSync(ENGINE_DIR)) {
if (!cmd || cmd.length == 0) if (!cmd || cmd.length == 0)
log.error( log.error('You need to specify a command to run.')
"You need to specify a command to run."
);
const bin = cmd[0]; const bin = cmd[0]
const args = cmd; const args = cmd
args.shift(); args.shift()
log.info( log.info(
`Executing \`${bin}${ `Executing \`${bin}${args.length !== 0 ? ` ` : ``}${args.join(
args.length !== 0 ? ` ` : `` ' '
}${args.join(" ")}\` in \`src\`...` )}\` in \`src\`...`
); )
dispatch(bin, args, ENGINE_DIR, true); dispatch(bin, args, ENGINE_DIR, true)
} else { } else {
log.error(`Unable to locate src directory.`); log.error(`Unable to locate src directory.`)
} }
}; }

View file

@ -1,64 +1,56 @@
import execa from "execa"; import execa from 'execa'
import { existsSync, writeFileSync } from "fs"; import { existsSync, writeFileSync } from 'fs'
import { ensureDirSync } from "fs-extra"; import { ensureDirSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { log } from ".."; import { log } from '..'
import { ENGINE_DIR, SRC_DIR } from "../constants"; import { ENGINE_DIR, SRC_DIR } from '../constants'
import { delay } from "../utils"; import { delay } from '../utils'
export const exportFile = async (file: string) => { export const exportFile = async (file: string) => {
log.info(`Exporting ${file}...`); log.info(`Exporting ${file}...`)
if (!existsSync(resolve(ENGINE_DIR, file))) if (!existsSync(resolve(ENGINE_DIR, file)))
throw new Error( throw new Error(
`File ${file} could not be found in engine directory. Check the path for any mistakes and try again.` `File ${file} could not be found in engine directory. Check the path for any mistakes and try again.`
); )
const proc = await execa( const proc = await execa(
"git", 'git',
[ [
"diff", 'diff',
"--src-prefix=a/", '--src-prefix=a/',
"--dst-prefix=b/", '--dst-prefix=b/',
"--full-index", '--full-index',
resolve(ENGINE_DIR, file) resolve(ENGINE_DIR, file),
], ],
{ {
cwd: ENGINE_DIR, cwd: ENGINE_DIR,
stripFinalNewline: false stripFinalNewline: false,
}
);
const name =
file
.split("/")
[
file.replace(/\./g, "-").split("/")
.length - 1
].replace(/\./g, "-") + ".patch";
const patchPath = file
.replace(/\./g, "-")
.split("/")
.slice(0, -1);
ensureDirSync(resolve(SRC_DIR, ...patchPath));
if (proc.stdout.length >= 8000) {
log.warning("");
log.warning(
`Exported patch is over 8000 characters. This patch may become hard to manage in the future.`
);
log.warning(
`We recommend trying to decrease your patch size by making minimal edits to the source.`
);
log.warning("");
await delay(2000);
} }
)
const name =
file
.split('/')
[file.replace(/\./g, '-').split('/').length - 1].replace(/\./g, '-') +
'.patch'
writeFileSync( const patchPath = file.replace(/\./g, '-').split('/').slice(0, -1)
resolve(SRC_DIR, ...patchPath, name),
proc.stdout ensureDirSync(resolve(SRC_DIR, ...patchPath))
);
log.info(`Wrote "${name}" to patches directory.`); if (proc.stdout.length >= 8000) {
console.log(); log.warning('')
}; log.warning(
`Exported patch is over 8000 characters. This patch may become hard to manage in the future.`
)
log.warning(
`We recommend trying to decrease your patch size by making minimal edits to the source.`
)
log.warning('')
await delay(2000)
}
writeFileSync(resolve(SRC_DIR, ...patchPath, name), proc.stdout)
log.info(`Wrote "${name}" to patches directory.`)
console.log()
}

View file

@ -1,218 +1,163 @@
import execa from "execa"; import execa from 'execa'
import { import {
appendFileSync, appendFileSync,
createWriteStream, createWriteStream,
existsSync, existsSync,
mkdirSync, mkdirSync,
rmdirSync, rmdirSync,
writeFileSync writeFileSync,
} from "fs"; } from 'fs'
import { copySync, ensureDirSync } from "fs-extra"; import { copySync, ensureDirSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { log } from ".."; import { log } from '..'
import { import { COMMON_DIR, ENGINE_DIR, PATCHES_DIR } from '../constants'
COMMON_DIR, import manualPatches from '../manual-patches'
ENGINE_DIR,
PATCHES_DIR
} from "../constants";
import manualPatches from "../manual-patches";
const flags: { const flags: {
[key: string]: string; [key: string]: string
} = { } = {
D: "delete", D: 'delete',
M: "modify", M: 'modify',
A: "add" A: 'add',
}; }
const getFiles = async (flags: string, cwd: string) => { const getFiles = async (flags: string, cwd: string) => {
let { stdout: ignored } = await execa( let { stdout: ignored } = await execa(
"git", 'git',
[ ['ls-files', `-${flags.toLowerCase()}`, '-i', '-o', '--exclude-standard'],
"ls-files", { cwd }
`-${flags.toLowerCase()}`, )
"-i",
"-o",
"--exclude-standard"
],
{ cwd }
);
let { stdout: fls } = await execa( let { stdout: fls } = await execa(
"git", 'git',
[ ['diff', `--diff-filter=${flags}`, '--name-only', '--ignore-space-at-eol'],
"diff", { cwd }
`--diff-filter=${flags}`, )
"--name-only",
"--ignore-space-at-eol"
],
{ cwd }
);
const files = fls.split("\n").filter((i: any) => { const files = fls.split('\n').filter((i: any) => {
return !( return !(ignored.split('\n').includes(i) || i == '.gitignore')
ignored.split("\n").includes(i) || }) // this filters out the manual patches
i == ".gitignore"
);
}); // this filters out the manual patches
log.info( log.info(`Ignoring ${ignored.split('\n').length} files...`)
`Ignoring ${ignored.split("\n").length} files...`
);
const fileNames: any = files.map((f: any) => { const fileNames: any = files.map((f: any) => {
if (f.length !== 0) { if (f.length !== 0) {
return ( return f.replace(/\//g, '-').replace(/\./g, '-') + '.patch'
f }
.replace(/\//g, "-") })
.replace(/\./g, "-") + ".patch"
);
}
});
return { files, fileNames }; return { files, fileNames }
}; }
const exportModified = async ( const exportModified = async (patchesDir: string, cwd: string) => {
patchesDir: string, const { files, fileNames } = await getFiles('M', cwd)
cwd: string
) => {
const { files, fileNames } = await getFiles("M", cwd);
var filesWritten = 0; var filesWritten = 0
await Promise.all( await Promise.all(
files.map(async (file: any, i: any) => { files.map(async (file: any, i: any) => {
if (file) { if (file) {
try { try {
const proc = execa( const proc = execa(
"git", 'git',
[ [
"diff", 'diff',
"--src-prefix=a/", '--src-prefix=a/',
"--dst-prefix=b/", '--dst-prefix=b/',
"--full-index", '--full-index',
file file,
], ],
{ {
cwd, cwd,
stripFinalNewline: false stripFinalNewline: false,
}
);
const name = fileNames[i];
proc.stdout?.pipe(
createWriteStream(
resolve(patchesDir, name)
)
);
appendFileSync(
resolve(PATCHES_DIR, ".index"),
`${name} - ${file}\n`
);
++filesWritten;
} catch (e) {
log.error(e);
return;
}
} }
}) )
); const name = fileNames[i]
log.info( proc.stdout?.pipe(createWriteStream(resolve(patchesDir, name)))
`Wrote ${filesWritten} to patches directory.`
);
};
const exportFlag = async ( appendFileSync(resolve(PATCHES_DIR, '.index'), `${name} - ${file}\n`)
flag: string,
cwd: string,
actions: any[]
) => {
const { files } = await getFiles(flag, cwd);
actions.push({ ++filesWritten
action: flags[flag], } catch (e) {
target: files log.error(e)
}); return
}
}
})
)
return actions; log.info(`Wrote ${filesWritten} to patches directory.`)
}; }
const exportFlag = async (flag: string, cwd: string, actions: any[]) => {
const { files } = await getFiles(flag, cwd)
actions.push({
action: flags[flag],
target: files,
})
return actions
}
const exportManual = async (cwd: string) => { const exportManual = async (cwd: string) => {
return new Promise(async (resol) => { return new Promise(async (resol) => {
manualPatches.forEach((patch) => { manualPatches.forEach((patch) => {
if (patch.action == "copy") { if (patch.action == 'copy') {
if (typeof patch.src == "string") { if (typeof patch.src == 'string') {
const inSrc = resolve(cwd, patch.src); const inSrc = resolve(cwd, patch.src)
const outsideSrc = resolve( const outsideSrc = resolve(COMMON_DIR, patch.src)
COMMON_DIR,
patch.src
);
if (!existsSync(inSrc)) if (!existsSync(inSrc))
return log.error( return log.error(`Cannot find "${patch.src}" from manual patches.`)
`Cannot find "${patch.src}" from manual patches.` if (!existsSync(outsideSrc)) ensureDirSync(outsideSrc) // make sure target dir exists before copying
);
if (!existsSync(outsideSrc))
ensureDirSync(outsideSrc); // make sure target dir exists before copying
copySync(inSrc, outsideSrc); copySync(inSrc, outsideSrc)
} else if (Array.isArray(patch.src)) { } else if (Array.isArray(patch.src)) {
patch.src.forEach((p) => { patch.src.forEach((p) => {
const inSrc = resolve(cwd, p); const inSrc = resolve(cwd, p)
const outsideSrc = resolve( const outsideSrc = resolve(COMMON_DIR, p)
COMMON_DIR,
p
);
if (!existsSync(inSrc)) if (!existsSync(inSrc))
return log.error( return log.error(`Cannot find "${p}" from manual patches.`)
`Cannot find "${p}" from manual patches.` if (!existsSync(outsideSrc)) ensureDirSync(outsideSrc) // make sure target dir exists before copying
);
if (!existsSync(outsideSrc))
ensureDirSync(outsideSrc); // make sure target dir exists before copying
copySync(inSrc, outsideSrc); copySync(inSrc, outsideSrc)
}); })
} }
} }
}); })
}); })
}; }
export const exportPatches = async () => { export const exportPatches = async () => {
throw new Error( throw new Error(
"export-patches has been deprecated in favour of export-file. This change has been made to limit the amount of active patches we have in the tree." 'export-patches has been deprecated in favour of export-file. This change has been made to limit the amount of active patches we have in the tree.'
); )
let actions: any[] = []; let actions: any[] = []
log.info(`Wiping patches directory...`); log.info(`Wiping patches directory...`)
console.log(); console.log()
// TODO: Replace this with fs.rmSync(path, { recursive: true }) when node 12 is deprecated // TODO: Replace this with fs.rmSync(path, { recursive: true }) when node 12 is deprecated
// This function has been depriciated, however its replacement was only available // This function has been depriciated, however its replacement was only available
// from v14.14.0 onwards (https://nodejs.org/dist/latest-v16.x/docs/api/fs.html#fs_fs_rmsync_path_options) // from v14.14.0 onwards (https://nodejs.org/dist/latest-v16.x/docs/api/fs.html#fs_fs_rmsync_path_options)
rmdirSync(PATCHES_DIR, { recursive: true }); rmdirSync(PATCHES_DIR, { recursive: true })
mkdirSync(PATCHES_DIR); mkdirSync(PATCHES_DIR)
writeFileSync(resolve(PATCHES_DIR, ".index"), ""); writeFileSync(resolve(PATCHES_DIR, '.index'), '')
log.info("Exporting modified files..."); log.info('Exporting modified files...')
await exportModified(PATCHES_DIR, ENGINE_DIR); await exportModified(PATCHES_DIR, ENGINE_DIR)
console.log(); console.log()
log.info("Exporting deleted files..."); log.info('Exporting deleted files...')
await exportFlag("D", ENGINE_DIR, actions); await exportFlag('D', ENGINE_DIR, actions)
console.log(); console.log()
log.info("Exporting manual patches..."); log.info('Exporting manual patches...')
await exportManual(ENGINE_DIR); await exportManual(ENGINE_DIR)
console.log(); console.log()
copySync( copySync(resolve(ENGINE_DIR, 'dot'), resolve(process.cwd(), 'browser'))
resolve(ENGINE_DIR, "dot"), }
resolve(process.cwd(), "browser")
);
};

View file

@ -1,49 +1,28 @@
import { import { existsSync, readdirSync, readFileSync } from 'fs-extra'
existsSync, import { resolve } from 'path'
readdirSync, import { log } from '..'
readFileSync import { ENGINE_DIR, PATCHES_DIR } from '../constants'
} from "fs-extra"; import { dispatch } from '../utils'
import { resolve } from "path";
import { log } from "..";
import { ENGINE_DIR, PATCHES_DIR } from "../constants";
import { dispatch } from "../utils";
export const fixLineEndings = async () => { export const fixLineEndings = async () => {
let patches = readdirSync(PATCHES_DIR); let patches = readdirSync(PATCHES_DIR)
patches = patches.filter((p) => p !== ".index"); patches = patches.filter((p) => p !== '.index')
await Promise.all( await Promise.all(
patches.map(async (patch) => { patches.map(async (patch) => {
const patchContents = readFileSync( const patchContents = readFileSync(resolve(PATCHES_DIR, patch), 'utf-8')
resolve(PATCHES_DIR, patch), const originalPath = patchContents
"utf-8" .split('diff --git a/')[1]
); .split(' b/')[0]
const originalPath = patchContents
.split("diff --git a/")[1]
.split(" b/")[0];
if ( if (existsSync(resolve(ENGINE_DIR, originalPath))) {
existsSync( dispatch('dos2unix', [originalPath], ENGINE_DIR).then(async (_) => {
resolve(ENGINE_DIR, originalPath) await dispatch('dos2unix', [patch], PATCHES_DIR)
)
) {
dispatch(
"dos2unix",
[originalPath],
ENGINE_DIR
).then(async (_) => {
await dispatch(
"dos2unix",
[patch],
PATCHES_DIR
);
});
} else {
log.warning(
`Skipping ${patch} as it no longer exists in tree...`
);
}
}) })
); } else {
}; log.warning(`Skipping ${patch} as it no longer exists in tree...`)
}
})
)
}

View file

@ -1,141 +1,115 @@
import { sync } from "glob"; import { sync } from 'glob'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
import { SRC_DIR } from "../constants"; import { SRC_DIR } from '../constants'
import Patch from "../controllers/patch"; import Patch from '../controllers/patch'
import manualPatches from "../manual-patches"; import manualPatches from '../manual-patches'
import { delay, dispatch } from "../utils"; import { delay, dispatch } from '../utils'
const { const {
versions: { dot } versions: { dot },
} = require("../../package.json"); } = require('../../package.json')
const importManual = async ( const importManual = async (minimal?: boolean, noIgnore?: boolean) => {
minimal?: boolean, log.info(`Applying ${manualPatches.length} manual patches...`)
noIgnore?: boolean
) => {
log.info(
`Applying ${manualPatches.length} manual patches...`
);
if (!minimal) console.log(); if (!minimal) console.log()
await delay(500); await delay(500)
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
var total = 0; var total = 0
var i = 0; var i = 0
for await (let { for await (let { name, action, src, markers, indent } of manualPatches) {
name, ++i
action,
src,
markers,
indent
} of manualPatches) {
++i;
const p = new Patch({ const p = new Patch({
name, name,
action, action,
src, src,
type: "manual", type: 'manual',
status: [i, manualPatches.length], status: [i, manualPatches.length],
markers, markers,
indent, indent,
options: { options: {
minimal, minimal,
noIgnore noIgnore,
} },
}); })
await delay(100); await delay(100)
await p.apply(); await p.apply()
}
log.success(
`Successfully imported ${manualPatches.length} manual patches!`
);
console.log();
await delay(1000);
res(total);
});
};
const importPatchFiles = async (
minimal?: boolean,
noIgnore?: boolean
) => {
let patches = sync("**/*.patch", {
nodir: true,
cwd: SRC_DIR
});
patches = patches
.filter((p) => p !== ".index")
.filter((p) => !p.includes("node_modules"));
log.info(`Applying ${patches.length} patch files...`);
if (!minimal) console.log();
await delay(500);
var i = 0;
for await (const patch of patches) {
++i;
const p = new Patch({
name: patch,
type: "file",
status: [i, patches.length],
options: {
minimal,
noIgnore
}
});
await delay(100);
await p.apply();
} }
console.log(); log.success(`Successfully imported ${manualPatches.length} manual patches!`)
await dispatch( console.log()
`./${bin_name}`,
["doctor", "patches"],
process.cwd(),
true,
true
);
log.success( await delay(1000)
`Successfully imported ${patches.length} patch files!`
);
};
interface Args { res(total)
minimal?: boolean; })
noignore?: boolean;
} }
export const importPatches = async ( const importPatchFiles = async (minimal?: boolean, noIgnore?: boolean) => {
type: string, let patches = sync('**/*.patch', {
args: Args nodir: true,
) => { cwd: SRC_DIR,
if (type) { })
if (type == "manual")
await importManual(args.minimal); patches = patches
else if (type == "file") .filter((p) => p !== '.index')
await importPatchFiles(args.minimal); .filter((p) => !p.includes('node_modules'))
} else {
await importManual(args.minimal, args.noignore); log.info(`Applying ${patches.length} patch files...`)
await importPatchFiles(
args.minimal, if (!minimal) console.log()
args.noignore
); await delay(500)
}
}; var i = 0
for await (const patch of patches) {
++i
const p = new Patch({
name: patch,
type: 'file',
status: [i, patches.length],
options: {
minimal,
noIgnore,
},
})
await delay(100)
await p.apply()
}
console.log()
await dispatch(
`./${bin_name}`,
['doctor', 'patches'],
process.cwd(),
true,
true
)
log.success(`Successfully imported ${patches.length} patch files!`)
}
interface Args {
minimal?: boolean
noignore?: boolean
}
export const importPatches = async (type: string, args: Args) => {
if (type) {
if (type == 'manual') await importManual(args.minimal)
else if (type == 'file') await importPatchFiles(args.minimal)
} else {
await importManual(args.minimal, args.noignore)
await importPatchFiles(args.minimal, args.noignore)
}
}

View file

@ -1,18 +1,18 @@
export * from "./bootstrap"; export * from './bootstrap'
export * from "./build"; export * from './build'
export * from "./discard"; export * from './discard'
export * from "./download"; export * from './download'
export * from "./download-artifacts"; export * from './download-artifacts'
export * from "./execute"; export * from './execute'
export * from "./export-file"; export * from './export-file'
export * from "./export-patches"; export * from './export-patches'
export * from "./fix-le"; export * from './fix-le'
export * from "./import-patches"; export * from './import-patches'
export * from "./init"; export * from './init'
export * from "./license-check"; export * from './license-check'
export * from "./package"; export * from './package'
export * from "./reset"; export * from './reset'
export * from "./run"; export * from './run'
export * from "./set-branch"; export * from './set-branch'
export * from "./status"; export * from './status'
export * from "./test"; export * from './test'

View file

@ -1,68 +1,53 @@
import { Command } from "commander"; import { Command } from 'commander'
import { existsSync, readFileSync } from "fs"; import { existsSync, readFileSync } from 'fs'
import { resolve } from "path"; import { resolve } from 'path'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
export const init = async (directory: Command) => { export const init = async (directory: Command) => {
if (process.platform == "win32") { if (process.platform == 'win32') {
// Because Windows cannot handle paths correctly, we're just calling a script as the workaround. // Because Windows cannot handle paths correctly, we're just calling a script as the workaround.
log.info( log.info(
"Successfully downloaded browser source. Please run |./windows-init.sh| to finish up." 'Successfully downloaded browser source. Please run |./windows-init.sh| to finish up.'
); )
process.exit(0); process.exit(0)
} }
const cwd = process.cwd(); const cwd = process.cwd()
const dir = resolve( const dir = resolve(cwd as string, directory.toString())
cwd as string,
directory.toString()
);
if (!existsSync(dir)) { if (!existsSync(dir)) {
log.error( log.error(
`Directory "${directory}" not found.\nCheck the directory exists and run |${bin_name} init| again.` `Directory "${directory}" not found.\nCheck the directory exists and run |${bin_name} init| again.`
); )
} }
let version = readFileSync( let version = readFileSync(
resolve( resolve(
cwd, cwd,
directory.toString(), directory.toString(),
"browser", 'browser',
"config", 'config',
"version_display.txt" 'version_display.txt'
), ),
"utf-8" 'utf-8'
); )
if (!version) if (!version)
log.error( log.error(
`Directory "${directory}" not found.\nCheck the directory exists and run |${bin_name} init| again.` `Directory "${directory}" not found.\nCheck the directory exists and run |${bin_name} init| again.`
); )
version = version.trim().replace(/\\n/g, ""); version = version.trim().replace(/\\n/g, '')
await dispatch("git", ["init"], dir as string); await dispatch('git', ['init'], dir as string)
await dispatch( await dispatch('git', ['checkout', '--orphan', version], dir as string)
"git", await dispatch('git', ['add', '-v', '-f', '.'], dir as string)
["checkout", "--orphan", version], await dispatch(
dir as string 'git',
); ['commit', '-am', `"Firefox ${version}"`],
await dispatch( dir as string
"git", )
["add", "-v", "-f", "."], await dispatch('git', ['checkout', '-b', 'dot'], dir as string)
dir as string }
);
await dispatch(
"git",
["commit", "-am", `"Firefox ${version}"`],
dir as string
);
await dispatch(
"git",
["checkout", "-b", "dot"],
dir as string
);
};

View file

@ -1,92 +1,69 @@
import chalk from "chalk"; import chalk from 'chalk'
import { readdirSync, readFileSync } from "fs-extra"; import { readdirSync, readFileSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { log } from ".."; import { log } from '..'
import { ENGINE_DIR, PATCHES_DIR } from "../constants"; import { ENGINE_DIR, PATCHES_DIR } from '../constants'
const ignoredExt = [".json", ".bundle.js"]; const ignoredExt = ['.json', '.bundle.js']
export const licenseCheck = async () => { export const licenseCheck = async () => {
log.info("Checking project..."); log.info('Checking project...')
let patches = readdirSync(PATCHES_DIR).map((p) => p); let patches = readdirSync(PATCHES_DIR).map((p) => p)
patches = patches.filter((p) => p !== ".index"); patches = patches.filter((p) => p !== '.index')
const originalPaths = patches.map((p) => { const originalPaths = patches.map((p) => {
const data = readFileSync( const data = readFileSync(resolve(PATCHES_DIR, p), 'utf-8')
resolve(PATCHES_DIR, p),
"utf-8"
);
return data return data.split('diff --git a/')[1].split(' b/')[0]
.split("diff --git a/")[1] })
.split(" b/")[0];
});
let passed: string[] = []; let passed: string[] = []
let failed: string[] = []; let failed: string[] = []
let ignored: string[] = []; let ignored: string[] = []
originalPaths.forEach((p) => { originalPaths.forEach((p) => {
const data = readFileSync( const data = readFileSync(resolve(ENGINE_DIR, p), 'utf-8')
resolve(ENGINE_DIR, p), const headerRegion = data.split('\n').slice(0, 32).join(' ')
"utf-8"
);
const headerRegion = data
.split("\n")
.slice(0, 32)
.join(" ");
const passes = const passes =
headerRegion.includes( headerRegion.includes('http://mozilla.org/MPL/2.0') &&
"http://mozilla.org/MPL/2.0" headerRegion.includes('This Source Code Form') &&
) && headerRegion.includes('copy of the MPL')
headerRegion.includes(
"This Source Code Form"
) &&
headerRegion.includes("copy of the MPL");
const isIgnored = ignoredExt.find((i) => const isIgnored = ignoredExt.find((i) => p.endsWith(i)) ? true : false
p.endsWith(i) isIgnored && ignored.push(p)
)
? true
: false;
isIgnored && ignored.push(p);
if (!isIgnored) { if (!isIgnored) {
if (passes) passed.push(p); if (passes) passed.push(p)
else if (!passes) failed.push(p); else if (!passes) failed.push(p)
} }
}); })
let maxPassed = 5; let maxPassed = 5
let i = 0; let i = 0
for (const p of passed) { for (const p of passed) {
log.info( log.info(`${p}... ${chalk.green('✔ Pass - MPL-2.0')}`)
`${p}... ${chalk.green("✔ Pass - MPL-2.0")}`
);
if (i >= maxPassed) { if (i >= maxPassed) {
log.info( log.info(
`${chalk.gray.italic( `${chalk.gray.italic(
`${ `${passed.length - maxPassed} other files...`
passed.length - maxPassed )} ${chalk.green('✔ Pass - MPL-2.0')}`
} other files...` )
)} ${chalk.green("✔ Pass - MPL-2.0")}` break
);
break;
}
++i;
} }
failed.forEach((p, i) => { ++i
log.info(`${p}... ${chalk.red("❗ Failed")}`); }
});
ignored.forEach((p, i) => { failed.forEach((p, i) => {
log.info(`${p}... ${chalk.gray(" Ignored")}`); log.info(`${p}... ${chalk.red('❗ Failed')}`)
}); })
};
ignored.forEach((p, i) => {
log.info(`${p}... ${chalk.gray(' Ignored')}`)
})
}

View file

@ -1,5 +1,3 @@
declare module "linus" { declare module 'linus' {
export function name( export function name(callback: (error: Error, name: string) => void): void
callback: (error: Error, name: string) => void
): void;
} }

View file

@ -1,35 +1,27 @@
import execa from "execa"; import execa from 'execa'
import { existsSync } from "fs"; import { existsSync } from 'fs'
import { resolve } from "path"; import { resolve } from 'path'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
export const melonPackage = async () => { export const melonPackage = async () => {
if (existsSync(ENGINE_DIR)) { if (existsSync(ENGINE_DIR)) {
const artifactPath = resolve(ENGINE_DIR, "mach"); const artifactPath = resolve(ENGINE_DIR, 'mach')
if (existsSync(artifactPath)) { if (existsSync(artifactPath)) {
const args = ["package"]; const args = ['package']
log.info( log.info(
`Packaging \`dot\` with args ${JSON.stringify( `Packaging \`dot\` with args ${JSON.stringify(args.slice(1, 0))}...`
args.slice(1, 0) )
)}...`
);
execa(artifactPath, args).stdout?.pipe( execa(artifactPath, args).stdout?.pipe(process.stdout)
process.stdout
);
} else {
log.error(
`Cannot binary with name \`mach\` in ${resolve(
ENGINE_DIR
)}`
);
}
} else { } else {
log.error( log.error(`Cannot binary with name \`mach\` in ${resolve(ENGINE_DIR)}`)
`Unable to locate any source directories.\nRun |${bin_name} download| to generate the source directory.`
);
} }
}; } else {
log.error(
`Unable to locate any source directories.\nRun |${bin_name} download| to generate the source directory.`
)
}
}

View file

@ -1,171 +1,93 @@
import execa from "execa"; import execa from 'execa'
import { existsSync } from "fs-extra"; import { existsSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { confirm } from "promptly"; import { confirm } from 'promptly'
import rimraf from "rimraf"; import rimraf from 'rimraf'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
import { IPatch } from "../interfaces/patch"; import { IPatch } from '../interfaces/patch'
import manualPatches from "../manual-patches"; import manualPatches from '../manual-patches'
export const reset = async () => { export const reset = async () => {
try { try {
log.warning( log.warning(
"This will clear all your unexported changes in the `src` directory!" 'This will clear all your unexported changes in the `src` directory!'
); )
log.warning( log.warning(`You can export your changes by running |${bin_name} export|.`)
`You can export your changes by running |${bin_name} export|.` confirm(`Are you sure you want to continue?`, {
); default: 'false',
confirm(`Are you sure you want to continue?`, { })
default: "false" .then(async (answer) => {
}) if (answer) {
.then(async (answer) => { await execa('git', ['checkout', '.'], { cwd: ENGINE_DIR })
if (answer) {
await execa(
"git",
["checkout", "."],
{ cwd: ENGINE_DIR }
);
manualPatches.forEach( manualPatches.forEach(async (patch: IPatch) => {
async (patch: IPatch) => { const { src, action } = patch
const { src, action } = patch;
if (action == "copy") { if (action == 'copy') {
if ( if (typeof src == 'string') {
typeof src == "string" const path = resolve(ENGINE_DIR, src)
) {
const path = resolve(
ENGINE_DIR,
src
);
if ( if (path !== ENGINE_DIR) {
path !== log.info(`Deleting ${src}...`)
ENGINE_DIR
) {
log.info(
`Deleting ${src}...`
);
if ( if (existsSync(path)) rimraf.sync(path)
existsSync(
path
)
)
rimraf.sync(
path
);
}
} else if (
Array.isArray(src)
) {
src.forEach((i) => {
const path =
resolve(
ENGINE_DIR,
i
);
if (
path !==
ENGINE_DIR
) {
log.info(
`Deleting ${i}...`
);
if (
existsSync(
path
)
)
rimraf.sync(
path
);
}
});
}
} else {
log.warning(
"Resetting does not work on manual patches that have a `delete` action, skipping..."
);
}
}
);
let leftovers = new Set();
const { stdout: origFiles } =
await execa(
"git",
[
"clean",
"-e",
"'!*.orig'",
"--dry-run"
],
{ cwd: ENGINE_DIR }
);
const { stdout: rejFiles } =
await execa(
"git",
[
"clean",
"-e",
"'!*.rej'",
"--dry-run"
],
{ cwd: ENGINE_DIR }
);
origFiles
.split("\n")
.map((f) =>
leftovers.add(
f.replace(
/Would remove /,
""
)
)
);
rejFiles
.split("\n")
.map((f) =>
leftovers.add(
f.replace(
/Would remove /,
""
)
)
);
Array.from(leftovers).forEach(
(f: any) => {
const path = resolve(
ENGINE_DIR,
f
);
if (path !== ENGINE_DIR) {
log.info(
`Deleting ${f}...`
);
rimraf.sync(
resolve(ENGINE_DIR, f)
);
}
}
);
log.success("Reset successfully.");
log.info(
"Next time you build, it may need to recompile parts of the program because the cache was invalidated."
);
} }
}) } else if (Array.isArray(src)) {
.catch((e) => e); src.forEach((i) => {
} catch (e) {} const path = resolve(ENGINE_DIR, i)
};
if (path !== ENGINE_DIR) {
log.info(`Deleting ${i}...`)
if (existsSync(path)) rimraf.sync(path)
}
})
}
} else {
log.warning(
'Resetting does not work on manual patches that have a `delete` action, skipping...'
)
}
})
let leftovers = new Set()
const { stdout: origFiles } = await execa(
'git',
['clean', '-e', "'!*.orig'", '--dry-run'],
{ cwd: ENGINE_DIR }
)
const { stdout: rejFiles } = await execa(
'git',
['clean', '-e', "'!*.rej'", '--dry-run'],
{ cwd: ENGINE_DIR }
)
origFiles
.split('\n')
.map((f) => leftovers.add(f.replace(/Would remove /, '')))
rejFiles
.split('\n')
.map((f) => leftovers.add(f.replace(/Would remove /, '')))
Array.from(leftovers).forEach((f: any) => {
const path = resolve(ENGINE_DIR, f)
if (path !== ENGINE_DIR) {
log.info(`Deleting ${f}...`)
rimraf.sync(resolve(ENGINE_DIR, f))
}
})
log.success('Reset successfully.')
log.info(
'Next time you build, it may need to recompile parts of the program because the cache was invalidated.'
)
}
})
.catch((e) => e)
} catch (e) {}
}

View file

@ -1,36 +1,32 @@
import { existsSync, readdirSync } from "fs"; import { existsSync, readdirSync } from 'fs'
import { resolve } from "path"; import { resolve } from 'path'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
export const run = async (chrome?: string) => { export const run = async (chrome?: string) => {
const dirs = readdirSync(ENGINE_DIR); const dirs = readdirSync(ENGINE_DIR)
const objDirname: any = dirs.find((dir) => { const objDirname: any = dirs.find((dir) => {
return dir.startsWith("obj-"); return dir.startsWith('obj-')
}); })
if (!objDirname) { if (!objDirname) {
throw new Error( throw new Error('Dot Browser needs to be built before you can do this.')
"Dot Browser needs to be built before you can do this." }
);
}
const objDir = resolve(ENGINE_DIR, objDirname); const objDir = resolve(ENGINE_DIR, objDirname)
if (existsSync(objDir)) { if (existsSync(objDir)) {
dispatch( dispatch(
"./mach", './mach',
["run"].concat( ['run'].concat(chrome ? ['-chrome', chrome] : []),
chrome ? ["-chrome", chrome] : [] ENGINE_DIR,
), true,
ENGINE_DIR, true
true, )
true } else {
); log.error(
} else { `Unable to locate any built binaries.\nRun |${bin_name} build| to initiate a build.`
log.error( )
`Unable to locate any built binaries.\nRun |${bin_name} build| to initiate a build.` }
); }
}
};

View file

@ -1,62 +1,29 @@
import execa from "execa"; import execa from 'execa'
import { import { existsSync, readFileSync, writeFileSync } from 'fs-extra'
existsSync, import { resolve } from 'path'
readFileSync, import { log } from '..'
writeFileSync
} from "fs-extra";
import { resolve } from "path";
import { log } from "..";
export const setBranch = async (branch: string) => { export const setBranch = async (branch: string) => {
if ( if (!existsSync(resolve(process.cwd(), '.dotbuild', 'metadata'))) {
!existsSync( return log.error('Cannot find metadata, aborting...')
resolve( }
process.cwd(),
".dotbuild",
"metadata"
)
)
) {
return log.error(
"Cannot find metadata, aborting..."
);
}
const metadata = JSON.parse( const metadata = JSON.parse(
readFileSync( readFileSync(resolve(process.cwd(), '.dotbuild', 'metadata'), 'utf-8')
resolve( )
process.cwd(),
".dotbuild",
"metadata"
),
"utf-8"
)
);
try { try {
await execa("git", [ await execa('git', ['rev-parse', '--verify', branch])
"rev-parse",
"--verify",
branch
]);
metadata.branch = branch; metadata.branch = branch
writeFileSync( writeFileSync(
resolve( resolve(process.cwd(), '.dotbuild', 'metadata'),
process.cwd(), JSON.stringify(metadata)
".dotbuild", )
"metadata"
),
JSON.stringify(metadata)
);
log.success( log.success(`Default branch is at \`${branch}\`.`)
`Default branch is at \`${branch}\`.` } catch (e) {
); return log.error(`Branch with name \`${branch}\` does not exist.`)
} catch (e) { }
return log.error( }
`Branch with name \`${branch}\` does not exist.`
);
}
};

View file

@ -1,12 +1,12 @@
import { existsSync } from "fs"; import { existsSync } from 'fs'
import { log } from ".."; import { log } from '..'
import { ENGINE_DIR } from "../constants"; import { ENGINE_DIR } from '../constants'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
export const status = async () => { export const status = async () => {
if (existsSync(ENGINE_DIR)) { if (existsSync(ENGINE_DIR)) {
dispatch("git", ["status"], ENGINE_DIR, true); dispatch('git', ['status'], ENGINE_DIR, true)
} else { } else {
log.error(`Unable to locate src directory.`); log.error(`Unable to locate src directory.`)
} }
}; }

View file

@ -1,10 +1,6 @@
import { resolve } from "path"; import { resolve } from 'path'
import { dispatch } from "../utils"; import { dispatch } from '../utils'
export const test = async () => { export const test = async () => {
dispatch( dispatch('yarn', ['test'], resolve(process.cwd(), 'src', 'dot'))
"yarn", }
["test"],
resolve(process.cwd(), "src", "dot")
);
};

View file

@ -1,51 +1,31 @@
import execa from "execa"; import execa from 'execa'
import { resolve } from "path"; import { resolve } from 'path'
export const BUILD_TARGETS = [ export const BUILD_TARGETS = ['linux', 'windows', 'macos']
"linux",
"windows",
"macos"
];
export const ARCHITECTURE = ["i686", "x86_64"]; export const ARCHITECTURE = ['i686', 'x86_64']
export const PATCH_ARGS = [ export const PATCH_ARGS = [
"--ignore-space-change", '--ignore-space-change',
"--ignore-whitespace", '--ignore-whitespace',
"--verbose" '--verbose',
]; ]
export const ENGINE_DIR = resolve( export const ENGINE_DIR = resolve(process.cwd(), 'engine')
process.cwd(), export const SRC_DIR = resolve(process.cwd(), 'src')
"engine" export const PATCHES_DIR = resolve(process.cwd(), 'patches')
); export const COMMON_DIR = resolve(process.cwd(), 'common')
export const SRC_DIR = resolve(process.cwd(), "src"); export const CONFIGS_DIR = resolve(process.cwd(), 'configs')
export const PATCHES_DIR = resolve(
process.cwd(),
"patches"
);
export const COMMON_DIR = resolve(
process.cwd(),
"common"
);
export const CONFIGS_DIR = resolve(
process.cwd(),
"configs"
);
export let CONFIG_GUESS: any = null; export let CONFIG_GUESS: any = null
try { try {
CONFIG_GUESS = execa.commandSync( CONFIG_GUESS = execa.commandSync('./build/autoconf/config.guess', {
"./build/autoconf/config.guess", cwd: ENGINE_DIR,
{ cwd: ENGINE_DIR } }).stdout
).stdout;
} catch (e) {} } catch (e) {}
export const OBJ_DIR = resolve( export const OBJ_DIR = resolve(ENGINE_DIR, `obj-${CONFIG_GUESS}`)
ENGINE_DIR,
`obj-${CONFIG_GUESS}`
);
export const FTL_STRING_LINE_REGEX = export const FTL_STRING_LINE_REGEX =
/(([a-zA-Z0-9\-]*|\.[a-z\-]*) =(.*|\.)|\[[a-zA-Z0-9]*\].*(\n\s?\s?})?|\*\[[a-zA-Z0-9]*\] .*(\n\s?\s?})?)/gm; /(([a-zA-Z0-9\-]*|\.[a-z\-]*) =(.*|\.)|\[[a-zA-Z0-9]*\].*(\n\s?\s?})?|\*\[[a-zA-Z0-9]*\] .*(\n\s?\s?})?)/gm

View file

@ -1,267 +1,188 @@
import chalk from "chalk"; import chalk from 'chalk'
import execa from "execa"; import execa from 'execa'
import { import { existsSync, rmdirSync, rmSync, statSync } from 'fs-extra'
existsSync, import { resolve } from 'path'
rmdirSync, import readline from 'readline'
rmSync, import { log } from '..'
statSync import { ENGINE_DIR, PATCH_ARGS, SRC_DIR } from '../constants'
} from "fs-extra"; import { copyManual } from '../utils'
import { resolve } from "path";
import readline from "readline";
import { log } from "..";
import {
ENGINE_DIR,
PATCH_ARGS,
SRC_DIR
} from "../constants";
import { copyManual } from "../utils";
class Patch { class Patch {
public name: string; public name: string
public action: string; public action: string
public src: string | string[]; public src: string | string[]
public type: "file" | "manual"; public type: 'file' | 'manual'
public status: number[]; public status: number[]
public markers?: { public markers?: {
[key: string]: [string, string]; [key: string]: [string, string]
}; }
public indent?: number; public indent?: number
public options: { public options: {
minimal?: boolean; minimal?: boolean
noIgnore?: boolean; noIgnore?: boolean
}; }
private _done: boolean = false; private _done: boolean = false
private error: Error | unknown; private error: Error | unknown
private async applyAsManual() { private async applyAsManual() {
return new Promise(async (res, rej) => { return new Promise(async (res, rej) => {
try { try {
switch (this.action) { switch (this.action) {
case "copy": case 'copy':
if (typeof this.src == "string") { if (typeof this.src == 'string') {
copyManual( copyManual(this.src, this.options.noIgnore)
this.src,
this.options.noIgnore
);
}
if (Array.isArray(this.src)) {
this.src.forEach((i) => {
copyManual(
i,
this.options.noIgnore
);
});
}
break;
case "delete":
if (typeof this.src == "string") {
if (
!existsSync(
resolve(
ENGINE_DIR,
this.src
)
)
)
return log.error(
`We were unable to delete the file or directory \`${this.src}\` as it doesn't exist in the src directory.`
);
if (
statSync(
resolve(
ENGINE_DIR,
this.src
)
).isDirectory()
) {
rmdirSync(
resolve(
ENGINE_DIR,
this.src
)
);
} else {
rmSync(
resolve(
ENGINE_DIR,
this.src
)
);
}
}
if (Array.isArray(this.src)) {
this.src.forEach((i) => {
if (
!existsSync(
resolve(
ENGINE_DIR,
i
)
)
)
return log.error(
`We were unable to delete the file or directory \`${i}\` as it doesn't exist in the src directory.`
);
if (
statSync(
resolve(
ENGINE_DIR,
i
)
).isDirectory()
) {
rmdirSync(
resolve(
ENGINE_DIR,
i
)
);
} else {
rmSync(
resolve(
ENGINE_DIR,
i
),
{ force: true }
);
}
});
}
break;
}
res(true);
} catch (e) {
rej(e);
} }
});
}
private async applyAsPatch() { if (Array.isArray(this.src)) {
return new Promise(async (res, rej) => { this.src.forEach((i) => {
try { copyManual(i, this.options.noIgnore)
try { })
await execa(
"git",
[
"apply",
"-R",
...PATCH_ARGS,
this.src as any
],
{ cwd: ENGINE_DIR }
);
} catch (e) {
null;
}
const { stdout, exitCode } = await execa(
"git",
[
"apply",
...PATCH_ARGS,
this.src as any
],
{ cwd: ENGINE_DIR }
);
if (exitCode == 0) res(true);
else throw stdout;
} catch (e) {
rej(e);
} }
});
}
public async apply() { break
if (!this.options.minimal) { case 'delete':
log.info( if (typeof this.src == 'string') {
`${chalk.gray( if (!existsSync(resolve(ENGINE_DIR, this.src)))
`(${this.status[0]}/${this.status[1]})` return log.error(
)} Applying ${this.name}...` `We were unable to delete the file or directory \`${this.src}\` as it doesn't exist in the src directory.`
); )
if (statSync(resolve(ENGINE_DIR, this.src)).isDirectory()) {
rmdirSync(resolve(ENGINE_DIR, this.src))
} else {
rmSync(resolve(ENGINE_DIR, this.src))
}
}
if (Array.isArray(this.src)) {
this.src.forEach((i) => {
if (!existsSync(resolve(ENGINE_DIR, i)))
return log.error(
`We were unable to delete the file or directory \`${i}\` as it doesn't exist in the src directory.`
)
if (statSync(resolve(ENGINE_DIR, i)).isDirectory()) {
rmdirSync(resolve(ENGINE_DIR, i))
} else {
rmSync(resolve(ENGINE_DIR, i), { force: true })
}
})
}
break
} }
res(true)
} catch (e) {
rej(e)
}
})
}
private async applyAsPatch() {
return new Promise(async (res, rej) => {
try {
try { try {
if (this.type == "manual") await execa('git', ['apply', '-R', ...PATCH_ARGS, this.src as any], {
await this.applyAsManual(); cwd: ENGINE_DIR,
if (this.type == "file") })
await this.applyAsPatch();
this.done = true;
} catch (e) { } catch (e) {
this.error = e; null
this.done = false;
}
}
public get done() {
return this._done;
}
public set done(_: any) {
this._done = _;
if (!this.options.minimal) {
readline.moveCursor(process.stdout, 0, -1);
readline.clearLine(process.stdout, 1);
log.info(
`${chalk.gray(
`(${this.status[0]}/${this.status[1]})`
)} Applying ${this.name}... ${chalk[
this._done ? "green" : "red"
].bold(
this._done ? "Done ✔" : "Error ❗"
)}`
);
} }
if (this.error) { const { stdout, exitCode } = await execa(
throw this.error; 'git',
} ['apply', ...PATCH_ARGS, this.src as any],
{ cwd: ENGINE_DIR }
)
if (exitCode == 0) res(true)
else throw stdout
} catch (e) {
rej(e)
}
})
}
public async apply() {
if (!this.options.minimal) {
log.info(
`${chalk.gray(`(${this.status[0]}/${this.status[1]})`)} Applying ${
this.name
}...`
)
} }
constructor({ try {
name, if (this.type == 'manual') await this.applyAsManual()
action, if (this.type == 'file') await this.applyAsPatch()
src,
type, this.done = true
status, } catch (e) {
markers, this.error = e
indent, this.done = false
options
}: {
name: string;
action?: string;
src?: string | string[];
type: "file" | "manual";
status: number[];
markers?: {
[key: string]: [string, string];
};
indent?: number;
options: {
minimal?: boolean;
noIgnore?: boolean;
};
}) {
this.name = name;
this.action = action || "";
this.src = src || resolve(SRC_DIR, name);
this.type = type;
this.status = status;
this.markers = markers;
this.indent = indent;
this.options = options;
} }
}
public get done() {
return this._done
}
public set done(_: any) {
this._done = _
if (!this.options.minimal) {
readline.moveCursor(process.stdout, 0, -1)
readline.clearLine(process.stdout, 1)
log.info(
`${chalk.gray(`(${this.status[0]}/${this.status[1]})`)} Applying ${
this.name
}... ${chalk[this._done ? 'green' : 'red'].bold(
this._done ? 'Done ✔' : 'Error ❗'
)}`
)
}
if (this.error) {
throw this.error
}
}
constructor({
name,
action,
src,
type,
status,
markers,
indent,
options,
}: {
name: string
action?: string
src?: string | string[]
type: 'file' | 'manual'
status: number[]
markers?: {
[key: string]: [string, string]
}
indent?: number
options: {
minimal?: boolean
noIgnore?: boolean
}
}) {
this.name = name
this.action = action || ''
this.src = src || resolve(SRC_DIR, name)
this.type = type
this.status = status
this.markers = markers
this.indent = indent
this.options = options
}
} }
export default Patch; export default Patch

View file

@ -1,108 +1,85 @@
import chalk from "chalk"; import chalk from 'chalk'
import commander, { Command } from "commander"; import commander, { Command } from 'commander'
import { existsSync, readFileSync } from "fs"; import { existsSync, readFileSync } from 'fs'
import { resolve } from "path"; import { resolve } from 'path'
import { commands } from "./cmds"; import { commands } from './cmds'
import { ENGINE_DIR } from "./constants"; import { ENGINE_DIR } from './constants'
import Log from "./log"; import Log from './log'
import { shaCheck } from "./middleware/sha-check"; import { shaCheck } from './middleware/sha-check'
import { updateCheck } from "./middleware/update-check"; import { updateCheck } from './middleware/update-check'
import { errorHandler } from "./utils"; import { errorHandler } from './utils'
const program = new Command(); const program = new Command()
export let log = new Log(); export let log = new Log()
program program.storeOptionsAsProperties(false).passCommandToAction(false)
.storeOptionsAsProperties(false)
.passCommandToAction(false);
const { dot, firefox, melon } = const { dot, firefox, melon } = require('../package.json').versions
require("../package.json").versions;
let reportedFFVersion; let reportedFFVersion
if ( if (existsSync(resolve(ENGINE_DIR, 'browser', 'config', 'version.txt'))) {
existsSync( const version = readFileSync(
resolve( resolve(ENGINE_DIR, 'browser', 'config', 'version.txt'),
ENGINE_DIR, 'utf-8'
"browser", ).replace(/\n/g, '')
"config",
"version.txt"
)
)
) {
const version = readFileSync(
resolve(
ENGINE_DIR,
"browser",
"config",
"version.txt"
),
"utf-8"
).replace(/\n/g, "");
if (version !== firefox) reportedFFVersion = version; if (version !== firefox) reportedFFVersion = version
} }
export const bin_name = "melon"; export const bin_name = 'melon'
program.version(` program.version(`
\t${chalk.bold("Dot Browser")} ${dot} \t${chalk.bold('Dot Browser')} ${dot}
\t${chalk.bold("Firefox")} ${firefox} ${ \t${chalk.bold('Firefox')} ${firefox} ${
reportedFFVersion reportedFFVersion ? `(being reported as ${reportedFFVersion})` : ``
? `(being reported as ${reportedFFVersion})`
: ``
} }
\t${chalk.bold("Melon")} ${melon} \t${chalk.bold('Melon')} ${melon}
${ ${
reportedFFVersion reportedFFVersion
? `Mismatch detected between expected Firefox version and the actual version. ? `Mismatch detected between expected Firefox version and the actual version.
You may have downloaded the source code using a different version and You may have downloaded the source code using a different version and
then switched to another branch.` then switched to another branch.`
: `` : ``
} }
`); `)
program.name(bin_name); program.name(bin_name)
commands.forEach((command) => { commands.forEach((command) => {
if (command.flags) { if (command.flags) {
if ( if (
command.flags.platforms && command.flags.platforms &&
!command.flags.platforms.includes( !command.flags.platforms.includes(process.platform)
process.platform ) {
) return
) {
return;
}
} }
}
const _cmd = commander.command(command.cmd); const _cmd = commander.command(command.cmd)
_cmd.description(command.description); _cmd.description(command.description)
command?.aliases?.forEach((alias) => { command?.aliases?.forEach((alias) => {
_cmd.alias(alias); _cmd.alias(alias)
}); })
command?.options?.forEach((opt) => { command?.options?.forEach((opt) => {
_cmd.option(opt.arg, opt.description); _cmd.option(opt.arg, opt.description)
}); })
_cmd.action(async (...args: any) => { _cmd.action(async (...args: any) => {
await shaCheck(command.cmd); await shaCheck(command.cmd)
await updateCheck(); await updateCheck()
command.controller(...args); command.controller(...args)
}); })
program.addCommand(_cmd); program.addCommand(_cmd)
}); })
process.on("uncaughtException", errorHandler); process.on('uncaughtException', errorHandler)
process.on("unhandledException", (err) => process.on('unhandledException', (err) => errorHandler(err, true))
errorHandler(err, true)
);
program.parse(process.argv); program.parse(process.argv)

View file

@ -1,9 +1,9 @@
export interface IPatch { export interface IPatch {
name: string; name: string
action: string; action: string
src: string | string[]; src: string | string[]
markers?: { markers?: {
[key: string]: [string, string]; [key: string]: [string, string]
}; }
indent?: number; indent?: number
} }

View file

@ -1,70 +1,51 @@
import chalk from "chalk"; import chalk from 'chalk'
class Log { class Log {
private startTime: number; private startTime: number
constructor() { constructor() {
const d = new Date(); const d = new Date()
this.startTime = d.getTime(); this.startTime = d.getTime()
}
getDiff() {
const d = new Date()
const currentTime = d.getTime()
const elapsedTime = currentTime - this.startTime
var secs = Math.floor((elapsedTime / 1000) % 60)
var mins = Math.floor((elapsedTime / (60 * 1000)) % 60)
var hours = Math.floor((elapsedTime / (60 * 60 * 1000)) % 24)
const format = (r: number) => {
return r.toString().length == 1 ? '0' + r : r
} }
getDiff() { return `${format(hours)}:${format(mins)}:${format(secs)}`
const d = new Date(); }
const currentTime = d.getTime(); info(...args: any[]) {
console.info(chalk.blueBright.bold(this.getDiff()), ...args)
}
const elapsedTime = currentTime - this.startTime; warning(...args: any[]) {
console.info(chalk.yellowBright.bold(' WARNING'), ...args)
}
var secs = Math.floor((elapsedTime / 1000) % 60); hardWarning(...args: any[]) {
var mins = Math.floor( console.info('', chalk.bgRed.bold('WARNING'), ...args)
(elapsedTime / (60 * 1000)) % 60 }
);
var hours = Math.floor(
(elapsedTime / (60 * 60 * 1000)) % 24
);
const format = (r: number) => { success(...args: any[]) {
return r.toString().length == 1 ? "0" + r : r; console.log(`\n${chalk.greenBright.bold('SUCCESS')}`, ...args)
}; }
return `${format(hours)}:${format(mins)}:${format( error(...args: any[]) {
secs throw new Error(...args)
)}`; }
}
info(...args: any[]) {
console.info(
chalk.blueBright.bold(this.getDiff()),
...args
);
}
warning(...args: any[]) {
console.info(
chalk.yellowBright.bold(" WARNING"),
...args
);
}
hardWarning(...args: any[]) {
console.info(
"",
chalk.bgRed.bold("WARNING"),
...args
);
}
success(...args: any[]) {
console.log(
`\n${chalk.greenBright.bold("SUCCESS")}`,
...args
);
}
error(...args: any[]) {
throw new Error(...args);
}
} }
export default Log; export default Log

View file

@ -1,32 +1,26 @@
import { sync } from "glob"; import { sync } from 'glob'
import { SRC_DIR } from "./constants"; import { SRC_DIR } from './constants'
import { IPatch } from "./interfaces/patch"; import { IPatch } from './interfaces/patch'
let files = sync("**/*", { let files = sync('**/*', {
nodir: true, nodir: true,
cwd: SRC_DIR cwd: SRC_DIR,
}).filter( }).filter(
(f) => (f) => !(f.endsWith('.patch') || f.split('/').includes('node_modules'))
!( )
f.endsWith(".patch") ||
f.split("/").includes("node_modules")
)
);
const manualPatches: IPatch[] = []; const manualPatches: IPatch[] = []
files.map((i) => { files.map((i) => {
const group = i.split("/")[0]; const group = i.split('/')[0]
if (!manualPatches.find((m) => m.name == group)) { if (!manualPatches.find((m) => m.name == group)) {
manualPatches.push({ manualPatches.push({
name: group, name: group,
action: "copy", action: 'copy',
src: files.filter( src: files.filter((f) => f.split('/')[0] == group),
(f) => f.split("/")[0] == group })
) }
}); })
}
});
export default manualPatches; export default manualPatches

View file

@ -1,53 +1,34 @@
import execa from "execa"; import execa from 'execa'
import { existsSync, readFileSync } from "fs-extra"; import { existsSync, readFileSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { bin_name, log } from ".."; import { bin_name, log } from '..'
const blacklistedCommands = [ const blacklistedCommands = ['reset', 'init', 'set-branch']
"reset",
"init",
"set-branch"
];
export const shaCheck = async (command: string) => { export const shaCheck = async (command: string) => {
if ( if (
blacklistedCommands.filter((c) => blacklistedCommands.filter((c) => command.startsWith(c)).length !== 0 ||
command.startsWith(c) !existsSync(resolve(process.cwd(), '.dotbuild', 'metadata'))
).length !== 0 || )
!existsSync( return
resolve(
process.cwd(),
".dotbuild",
"metadata"
)
)
)
return;
const metadata = JSON.parse( const metadata = JSON.parse(
readFileSync( readFileSync(resolve(process.cwd(), '.dotbuild', 'metadata'), 'utf-8')
resolve( )
process.cwd(),
".dotbuild",
"metadata"
),
"utf-8"
)
);
const { stdout: currentBranch } = await execa("git", [ const { stdout: currentBranch } = await execa('git', [
"branch", 'branch',
"--show-current" '--show-current',
]); ])
if (metadata && metadata.branch) { if (metadata && metadata.branch) {
if (metadata.branch !== currentBranch) { if (metadata.branch !== currentBranch) {
log.warning(`The current branch \`${currentBranch}\` differs from the original branch \`${metadata.branch}\`. log.warning(`The current branch \`${currentBranch}\` differs from the original branch \`${metadata.branch}\`.
\t If you are changing the Firefox version, you will need to reset the tree \t If you are changing the Firefox version, you will need to reset the tree
\t with |${bin_name} reset --hard| and then |${bin_name} download|. \t with |${bin_name} reset --hard| and then |${bin_name} download|.
\t Or you can change the default branch by typing |${bin_name} set-branch <branch>|.`); \t Or you can change the default branch by typing |${bin_name} set-branch <branch>|.`)
}
} }
}; }
}

View file

@ -1,31 +1,24 @@
import axios from "axios"; import axios from 'axios'
import { log } from "../"; import { log } from '../'
const pjson = require("../../package.json"); const pjson = require('../../package.json')
export const updateCheck = async () => { export const updateCheck = async () => {
const firefoxVersion = const firefoxVersion = pjson.versions['firefox-display']
pjson.versions["firefox-display"];
try { try {
const { data } = await axios.get( const { data } = await axios.get(
`https://product-details.mozilla.org/1.0/firefox_history_major_releases.json`, `https://product-details.mozilla.org/1.0/firefox_history_major_releases.json`,
{ timeout: 1000 } { timeout: 1000 }
); )
if (data) { if (data) {
let version = let version = Object.keys(data)[Object.keys(data).length - 1]
Object.keys(data)[
Object.keys(data).length - 1
];
if ( if (firefoxVersion && version !== firefoxVersion)
firefoxVersion && log.warning(
version !== firefoxVersion `Latest version of Firefox (${version}) does not match frozen version (${firefoxVersion}).`
) )
log.warning( }
`Latest version of Firefox (${version}) does not match frozen version (${firefoxVersion}).` } catch (e) {}
); }
}
} catch (e) {}
};

22
src/types.d.ts vendored
View file

@ -1,19 +1,19 @@
export interface Cmd { export interface Cmd {
cmd: string; cmd: string
description: string; description: string
controller: (...args: any) => void; controller: (...args: any) => void
options?: CmdOption[]; options?: CmdOption[]
aliases?: string[]; aliases?: string[]
flags?: { flags?: {
platforms?: CmdFlagPlatform[]; platforms?: CmdFlagPlatform[]
}; }
} }
export interface CmdOption { export interface CmdOption {
arg: string; arg: string
description: string; description: string
} }
export type CmdFlagPlatform = NodeJS.Platform; export type CmdFlagPlatform = NodeJS.Platform

View file

@ -1,5 +1,5 @@
export const delay = (delay: number) => { export const delay = (delay: number) => {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => resolve(true), delay); setTimeout(() => resolve(true), delay)
}); })
}; }

View file

@ -1,49 +1,42 @@
import execa from "execa"; import execa from 'execa'
import { log } from ".."; import { log } from '..'
const handle = (data: any, killOnError?: boolean) => { const handle = (data: any, killOnError?: boolean) => {
const d = data.toString(); const d = data.toString()
d.split("\n").forEach((line: any) => { d.split('\n').forEach((line: any) => {
if (line.length !== 0) if (line.length !== 0) log.info(line.replace(/\s\d{1,5}:\d\d\.\d\d /g, ''))
log.info( })
line.replace(/\s\d{1,5}:\d\d\.\d\d /g, "")
);
});
if (killOnError) { if (killOnError) {
log.error("Command failed. See error above."); log.error('Command failed. See error above.')
process.exit(1); process.exit(1)
} }
}; }
export const dispatch = ( export const dispatch = (
cmd: string, cmd: string,
args?: any[], args?: any[],
cwd?: string, cwd?: string,
noLog?: boolean, noLog?: boolean,
killOnError?: boolean killOnError?: boolean
) => { ) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
process.env.MACH_USE_SYSTEM_PYTHON = "true"; process.env.MACH_USE_SYSTEM_PYTHON = 'true'
const proc = execa(cmd, args, { const proc = execa(cmd, args, {
cwd: cwd ? cwd : process.cwd(), cwd: cwd ? cwd : process.cwd(),
env: process.env env: process.env,
}); })
proc.stdout?.on("data", (d) => handle(d)); proc.stdout?.on('data', (d) => handle(d))
proc.stderr?.on("data", (d) => handle(d)); proc.stderr?.on('data', (d) => handle(d))
proc.stdout?.on("error", (d) => proc.stdout?.on('error', (d) => handle(d, killOnError))
handle(d, killOnError) proc.stderr?.on('error', (d) => handle(d, killOnError))
);
proc.stderr?.on("error", (d) =>
handle(d, killOnError)
);
proc.on("exit", () => { proc.on('exit', () => {
resolve(true); resolve(true)
}); })
}); })
}; }

View file

@ -1,45 +1,39 @@
import chalk from "chalk"; import chalk from 'chalk'
import { readFileSync } from "fs-extra"; import { readFileSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import { log } from ".."; import { log } from '..'
export const errorHandler = ( export const errorHandler = (err: Error, isUnhandledRej: boolean) => {
err: Error, let cc = readFileSync(resolve(process.cwd(), '.dotbuild', 'command'), 'utf-8')
isUnhandledRej: boolean cc = cc.replace(/(\r\n|\n|\r)/gm, '')
) => {
let cc = readFileSync(
resolve(process.cwd(), ".dotbuild", "command"),
"utf-8"
);
cc = cc.replace(/(\r\n|\n|\r)/gm, "");
console.log(
`\n ${chalk.redBright.bold(
'ERROR'
)} An error occurred while running command ["${cc
.split(' ')
.join('", "')}"]:`
)
console.log(
`\n\t`,
isUnhandledRej
? err.toString().replace(/\n/g, '\n\t ')
: err.message.replace(/\n/g, '\n\t ')
)
if (err.stack || isUnhandledRej) {
const stack: any = err.stack?.split('\n')
stack.shift()
stack.shift()
console.log( console.log(
`\n ${chalk.redBright.bold( `\t`,
"ERROR" stack
)} An error occurred while running command ["${cc .join('\n')
.split(" ") .replace(/(\r\n|\n|\r)/gm, '')
.join('", "')}"]:` .replace(/ at /g, '\n\t • ')
); )
console.log( }
`\n\t`,
isUnhandledRej
? err.toString().replace(/\n/g, "\n\t ")
: err.message.replace(/\n/g, "\n\t ")
);
if (err.stack || isUnhandledRej) {
const stack: any = err.stack?.split("\n");
stack.shift();
stack.shift();
console.log(
`\t`,
stack
.join("\n")
.replace(/(\r\n|\n|\r)/gm, "")
.replace(/ at /g, "\n\t • ")
);
}
console.log(); console.log()
log.info("Exiting due to error."); log.info('Exiting due to error.')
process.exit(1); process.exit(1)
}; }

View file

@ -1,66 +1,46 @@
import { import {
appendFileSync, appendFileSync,
ensureSymlink, ensureSymlink,
lstatSync, lstatSync,
readFileSync readFileSync,
} from "fs-extra"; } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
import rimraf from "rimraf"; import rimraf from 'rimraf'
import { ENGINE_DIR, SRC_DIR } from "../constants"; import { ENGINE_DIR, SRC_DIR } from '../constants'
const getChunked = (location: string) => { const getChunked = (location: string) => {
return location.replace(/\\/g, "/").split("/"); return location.replace(/\\/g, '/').split('/')
}; }
export const copyManual = ( export const copyManual = (name: string, noIgnore?: boolean) => {
name: string, try {
noIgnore?: boolean
) => {
try { try {
try { if (
if ( !lstatSync(resolve(ENGINE_DIR, ...getChunked(name))).isSymbolicLink()
!lstatSync( ) {
resolve( rimraf.sync(resolve(ENGINE_DIR, ...getChunked(name)))
ENGINE_DIR, }
...getChunked(name) } catch (e) {}
)
).isSymbolicLink()
) {
rimraf.sync(
resolve(
ENGINE_DIR,
...getChunked(name)
)
);
}
} catch (e) {}
ensureSymlink( ensureSymlink(
resolve(SRC_DIR, ...getChunked(name)), resolve(SRC_DIR, ...getChunked(name)),
resolve(ENGINE_DIR, ...getChunked(name)) resolve(ENGINE_DIR, ...getChunked(name))
); )
if (!noIgnore) { if (!noIgnore) {
const gitignore = readFileSync( const gitignore = readFileSync(resolve(ENGINE_DIR, '.gitignore'), 'utf-8')
resolve(ENGINE_DIR, ".gitignore"),
"utf-8"
);
if ( if (!gitignore.includes(getChunked(name).join('/')))
!gitignore.includes( appendFileSync(
getChunked(name).join("/") resolve(ENGINE_DIR, '.gitignore'),
) `\n${getChunked(name).join('/')}`
) )
appendFileSync(
resolve(ENGINE_DIR, ".gitignore"),
`\n${getChunked(name).join("/")}`
);
}
return;
} catch (e) {
console.log(e);
process.exit(0);
// return e;
} }
};
return
} catch (e) {
console.log(e)
process.exit(0)
// return e;
}
}

View file

@ -1,6 +1,6 @@
export * from "./delay"; export * from './delay'
export * from "./dispatch"; export * from './dispatch'
export * from "./error-handler"; export * from './error-handler'
export * from "./import"; export * from './import'
export * from "./version"; export * from './version'
export * from "./write-metadata"; export * from './write-metadata'

View file

@ -1,11 +1,9 @@
import axios from "axios"; import axios from 'axios'
export const getLatestFF = async () => { export const getLatestFF = async () => {
const { data } = await axios.get( const { data } = await axios.get(
`https://product-details.mozilla.org/1.0/firefox_history_major_releases.json` `https://product-details.mozilla.org/1.0/firefox_history_major_releases.json`
); )
return Object.keys(data)[ return Object.keys(data)[Object.keys(data).length - 1]
Object.keys(data).length - 1 }
];
};

View file

@ -1,26 +1,20 @@
import execa from "execa"; import execa from 'execa'
import { writeFileSync } from "fs-extra"; import { writeFileSync } from 'fs-extra'
import { resolve } from "path"; import { resolve } from 'path'
const pjson = require("../../package.json"); const pjson = require('../../package.json')
export const writeMetadata = async () => { export const writeMetadata = async () => {
const { stdout: sha } = await execa("git", [ const { stdout: sha } = await execa('git', ['rev-parse', 'HEAD'])
"rev-parse", const { stdout: branch } = await execa('git', ['branch', '--show-current'])
"HEAD"
]);
const { stdout: branch } = await execa("git", [
"branch",
"--show-current"
]);
writeFileSync( writeFileSync(
resolve(process.cwd(), ".dotbuild", "metadata"), resolve(process.cwd(), '.dotbuild', 'metadata'),
JSON.stringify({ JSON.stringify({
sha, sha,
branch, branch,
birth: Date.now(), birth: Date.now(),
versions: pjson.versions versions: pjson.versions,
}) })
); )
}; }

View file

@ -1,69 +1,64 @@
{ {
"compilerOptions": { "compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */ /* Basic Options */
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, "target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */ // "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */ // "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist" /* Redirect output structure to the directory. */, "outDir": "./dist" /* Redirect output structure to the directory. */,
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */ // "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */ // "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */ // "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */ /* Strict Type-Checking Options */
"strict": true /* Enable all strict type-checking options. */, "strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */ // "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */ /* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
/* Module Resolution Options */ /* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */, // "types": [], /* Type declaration files to be included in compilation. */,
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */ /* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */ /* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */ /* Advanced Options */
"skipLibCheck": true /* Skip type checking of declaration files. */, "skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
}, },
"exclude": [ "exclude": ["node_modules/**/*", "firefox-*/**/*", "gecko", "engine/**/*"]
"node_modules/**/*",
"firefox-*/**/*",
"gecko",
"engine/**/*"
]
} }