refactor: addResource compiler method

This commit is contained in:
calebboyd
2017-09-19 00:54:20 -05:00
parent dbcff4c7d2
commit 4f2b1c51d5
13 changed files with 151 additions and 102 deletions
+54 -32
View File
@@ -5,7 +5,7 @@ import { createReadStream } from 'fs'
import { Readable } from 'stream'
import { spawn } from 'child_process'
import { Logger } from './logger'
import { readFileAsync, writeFileAsync, pathExistsAsync, dequote, isWindows } from './util'
import { readFileAsync, writeFileAsync, pathExistsAsync, dequote, isWindows, bound } from './util'
import { NexeOptions, nexeVersion } from './options'
import { NexeTarget } from './target'
import download = require('download')
@@ -34,19 +34,16 @@ export class NexeCompiler {
public log = new Logger(this.options.loglevel)
public src: string
public files: NexeFile[] = []
public shims: string[] = []
public input: string
public bundledInput?: string
public output: string | null
public targets: NexeTarget[]
public target: NexeTarget
public resources: { bundle: string; index: { [key: string]: number[] } } = {
public resources: { bundle: Buffer; index: { [key: string]: number[] } } = {
index: {},
bundle: ''
bundle: Buffer.from('')
}
public readFileAsync: (file: string) => Promise<NexeFile>
public writeFileAsync: (file: string, contents: Buffer | string) => Promise<void>
public replaceInFileAsync: (file: string, replacer: any, replaceValue: string) => Promise<void>
public setFileContentsAsync: (file: string, contents: string | Buffer) => Promise<void>
private nodeSrcBinPath: string
constructor(public options: NexeOptions) {
@@ -65,32 +62,50 @@ export class NexeCompiler {
this.env.PYTHON = python
}
}
}
this.readFileAsync = async (file: string) => {
let cachedFile = this.files.find(x => normalize(x.filename) === normalize(file))
if (!cachedFile) {
const absPath = join(this.src, file)
cachedFile = {
absPath,
filename: file,
contents: await readFileAsync(absPath, 'utf-8').catch(x => {
if (x.code === 'ENOENT') return ''
throw x
})
}
this.files.push(cachedFile)
@bound
addResource(file: string, contents: Buffer) {
const { resources } = this
resources.index[file] = [resources.bundle.byteLength, contents.byteLength]
resources.bundle = Buffer.concat([resources.bundle, contents])
}
@bound
async readFileAsync(file: string) {
this.assertBuild()
let cachedFile = this.files.find(x => normalize(x.filename) === normalize(file))
if (!cachedFile) {
const absPath = join(this.src, file)
cachedFile = {
absPath,
filename: file,
contents: await readFileAsync(absPath, 'utf-8').catch(x => {
if (x.code === 'ENOENT') return ''
throw x
})
}
return cachedFile
}
this.writeFileAsync = (file, contents) => writeFileAsync(join(this.src, file), contents)
this.replaceInFileAsync = async (file, replace: string | RegExp, value: string) => {
const entry = await this.readFileAsync(file)
entry.contents = entry.contents.replace(replace, value)
}
this.setFileContentsAsync = async (file: string, contents: string) => {
const entry = await this.readFileAsync(file)
entry.contents = contents
this.files.push(cachedFile)
}
return cachedFile
}
@bound
writeFileAsync(file: string, contents: string | Buffer) {
this.assertBuild()
return writeFileAsync(join(this.src, file), contents)
}
@bound
async replaceInFileAsync(file: string, replace: string | RegExp, value: string) {
const entry = await this.readFileAsync(file)
entry.contents = entry.contents.replace(replace, value)
}
@bound
async setFileContentsAsync(file: string, contents: string) {
const entry = await this.readFileAsync(file)
entry.contents = contents
}
quit() {
@@ -99,6 +114,12 @@ export class NexeCompiler {
return this.log.flush()
}
assertBuild() {
if (!this.options.build) {
throw new Error('This feature is only available with `--build`')
}
}
public getNodeExecutableLocation(target?: NexeTarget) {
if (target) {
return join(this.options.temp, target.toString())
@@ -217,12 +238,13 @@ export class NexeCompiler {
artifact.push(chunk)
})
binary.on('close', () => {
const content = this._serializeHeader(header) + this.input
const content = this._serializeHeader(header) + this.shims.join(';') + ';' + this.input
artifact.push(content)
artifact.push(this.resources.bundle)
const lengths = Buffer.from(Array(16))
lengths.writeDoubleLE(Buffer.byteLength(content), 0)
lengths.writeDoubleLE(Buffer.byteLength(this.resources.bundle), 8)
lengths.writeDoubleLE(this.resources.bundle.byteLength, 8)
artifact.push(Buffer.concat([Buffer.from('<nexe~~sentinel>'), lengths]))
artifact.push(null)
})
+13 -6
View File
@@ -148,10 +148,6 @@ function tryResolveMainFileName(cwd: string) {
filename = basename(file).replace(extname(file), '')
} catch (_) {}
if (filename === 'index' && basename(cwd)) {
return basename(cwd)
}
return filename ? filename : 'nexe_' + Date.now()
}
@@ -162,12 +158,23 @@ function extractLogLevel(options: NexeOptions) {
return 'info'
}
function isName(name: string) {
return name && name !== 'index'
}
function extractName(options: NexeOptions) {
let name = options.name
if (!name && typeof options.input === 'string') {
if (!isName(name) && typeof options.input === 'string') {
name = basename(options.input).replace(extname(options.input), '')
}
name = name === 'index' ? tryResolveMainFileName(options.cwd) : name
if (!isName(name)) {
name = tryResolveMainFileName(options.cwd)
}
if (!isName(name) && basename(options.cwd)) {
name = basename(options.cwd)
}
return name.replace(/\.exe$/, '')
}
+2 -9
View File
@@ -18,15 +18,8 @@ export default async function resource(compiler: NexeCompiler, next: () => Promi
count++
step.log(`Including file: ${file}`)
const contents = await readFileAsync(file)
const commentSafeContents = contents.toString('base64')
resources.index[file] = [
Buffer.byteLength(resources.bundle),
Buffer.byteLength(commentSafeContents)
]
resources.bundle += commentSafeContents
compiler.addResource(file, contents)
})
step.log(
`Included ${count} file(s). ${(Buffer.byteLength(resources.bundle) / 1e6).toFixed(3)} MB`
)
step.log(`Included ${count} file(s). ${(resources.bundle.byteLength / 1e6).toFixed(3)} MB`)
return next()
}
+17
View File
@@ -26,6 +26,22 @@ function padRight(str: string, l: number) {
return (str + ' '.repeat(l)).substr(0, l)
}
const bound: MethodDecorator = function bound<T>(
target: Object,
propertyKey: string,
descriptor: TypedPropertyDescriptor<T>
) {
const configurable = true
return {
configurable,
get(this: T) {
const value = (descriptor.value as any).bind(this)
Object.defineProperty(this, propertyKey, { configurable, value, writable: true })
return value
}
}
}
function dequote(input: string) {
input = input.trim()
const singleQuote = input.startsWith("'") && input.endsWith("'")
@@ -62,6 +78,7 @@ function isDirectoryAsync(path: string) {
export {
dequote,
padRight,
bound,
isWindows,
rimrafAsync,
statAsync,