-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7082ca6
Showing
27 changed files
with
467 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "standard" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules/ | ||
.DS_Store | ||
npm-debug.log | ||
*~ | ||
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
.npmignore | ||
*.coffee | ||
.DS_Store | ||
npm-debug.log | ||
spec/ | ||
tasks/ | ||
bin/node | ||
.travis.yml | ||
.pairs | ||
.vscode/ | ||
.eslintrc.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
// 使用 IntelliSense 了解相关属性。 | ||
// 悬停以查看现有属性的描述。 | ||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 | ||
"version": "0.2.0", | ||
"configurations": [ | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "启动程序", | ||
"program": "${workspaceFolder}\\spec\\index.js" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# asar-node | ||
|
||
Enable require('./path/to/any-node-project.asar') & require('./path/to/any-node-project.asar/any/file') in your nodejs app. | ||
|
||
`asar-node` can not be used in Electron. | ||
|
||
Or just run `asar-node ./path/to/any-node-project.asar` | ||
|
||
## Usage | ||
|
||
Exists `./path/to/any-node-project.asar` | ||
|
||
``` bash | ||
$ asar-node ./path/to/any-node-project # OK! | ||
$ asar-node ./path/to/any-node-project.asar # OK! | ||
|
||
$ asar-node ./path/to/any-node-project.asar/any/file # OK! | ||
$ asar-node ./path/to/any-node-project.asar/any/file.js # OK! | ||
$ asar-node ./path/to/any-node-project.asar/any/file.json # OK! | ||
$ asar-node ./path/to/any-node-project.asar/any/file.node # OK! | ||
``` | ||
|
||
Or | ||
|
||
```js | ||
require('asar-node') | ||
|
||
require('./path/to/any-node-project') // like require a nodejs directory | ||
// or require('./path/to/any-node-project.asar') | ||
require('./path/to/any-node-project.asar/any/file') | ||
``` | ||
|
||
If require a asar file, make sure there is `package.json` and `main` field or `index.js` in the asar root. | ||
|
||
**Note: Only these fs api functions are available and you should use absolute path. Also `child_process` api is not supported in asar file.** | ||
|
||
* fs.readFileSync() | ||
* fs.createReadStream() | ||
* fs.statSync() | ||
* fs.existsSync() | ||
* fs.realpathSync() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env node | ||
|
||
require('child_process').spawnSync('node', process.argv.slice(1).unshift('--require=asar-node'), { stdio: 'inherit' }) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
if (process.versions.electron) { | ||
throw new Error('asar-node can not be used in Electron.') | ||
} | ||
|
||
require('./lib/module.js') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
const fs = process.versions.electron ? require('original-fs') : require('fs') | ||
const asar = require('asar') | ||
const path = require('path') | ||
const pickle = require('chromium-pickle-js') | ||
const { splitPath } = require('./util.js') | ||
|
||
let nextInode = 0 | ||
const uid = process.getuid != null ? process.getuid() : 0 | ||
const gid = process.getgid != null ? process.getgid() : 0 | ||
const fakeTime = new Date() | ||
const asarStatsToFsStats = (stats) => { | ||
const isFile = !stats.files | ||
return { | ||
dev: 1, | ||
ino: ++nextInode, | ||
mode: 33188, | ||
nlink: 1, | ||
uid: uid, | ||
gid: gid, | ||
rdev: 0, | ||
atime: stats.atime || fakeTime, | ||
birthtime: stats.birthtime || fakeTime, | ||
mtime: stats.mtime || fakeTime, | ||
ctime: stats.ctime || fakeTime, | ||
size: stats.size, | ||
isFile: () => isFile, | ||
isDirectory: () => !isFile, | ||
isSymbolicLink: () => false, | ||
isBlockDevice: () => false, | ||
isCharacterDevice: () => false, | ||
isFIFO: () => false, | ||
isSocket: () => false | ||
} | ||
} | ||
|
||
// Start overriding fs methods. | ||
const readFileSync = fs.readFileSync | ||
fs.readFileSync = function (p, options) { | ||
const [isAsar, asarPath, filePath] = splitPath(p) | ||
if (!isAsar) return readFileSync.apply(this, arguments) | ||
|
||
if (!options) { | ||
options = { encoding: null, flag: 'r' } | ||
} else if (typeof options === 'string') { | ||
options = { encoding: options, flag: 'r' } | ||
} else if (typeof options !== 'object') { | ||
throw new TypeError('Bad arguments') | ||
} | ||
|
||
let content | ||
try { | ||
content = asar.extractFile(asarPath, filePath.replace(/\\/g, '/')) | ||
} catch (_error) { | ||
throw new Error('ENOENT: no such file or directory, open \'' + p + '\'') | ||
} | ||
if (options.encoding) { | ||
return content.toString(options.encoding) | ||
} else { | ||
return content | ||
} | ||
} | ||
|
||
const createReadStream = fs.createReadStream | ||
fs.createReadStream = function (p, options) { | ||
if (!p || (options && options.fd)) return createReadStream.apply(this, arguments) | ||
const [isAsar, asarPath, filePath] = splitPath(p) | ||
if (!isAsar) return createReadStream.apply(this, arguments) | ||
|
||
const fd = fs.openSync(asarPath, 'r') | ||
|
||
const sizeBuf = Buffer.alloc(8) | ||
if (fs.readSync(fd, sizeBuf, 0, 8, null) !== 8) { | ||
throw new Error('Unable to read header size') | ||
} | ||
|
||
const sizePickle = pickle.createFromBuffer(sizeBuf) | ||
let headerSize = sizePickle.createIterator().readUInt32() | ||
|
||
let stats | ||
try { | ||
stats = asar.statFile(asarPath, filePath) | ||
} catch (_error) { | ||
throw new Error('Not found \'' + p + '\'') | ||
} | ||
|
||
let defaultOption = { | ||
fd, | ||
autoClose: true, | ||
start: 8 + headerSize + parseInt(stats.offset, 10), | ||
end: 8 + headerSize + parseInt(stats.offset, 10) + stats.size - 1 | ||
} | ||
|
||
if (Object.prototype.toString.call(options) === '[object Object]') { | ||
if (typeof options.end === 'number') { | ||
defaultOption.end = defaultOption.start + options.end | ||
delete options.end | ||
} | ||
if (typeof options.start === 'number') { | ||
defaultOption.start += options.start | ||
delete options.start | ||
} | ||
options = Object.assign({}, defaultOption, options) | ||
} else { | ||
options = defaultOption | ||
} | ||
|
||
return createReadStream('', options) | ||
} | ||
|
||
const statSync = fs.statSync | ||
fs.statSync = function (p) { | ||
const [isAsar, asarPath, filePath] = splitPath(p) | ||
if (!isAsar) return statSync.apply(this, arguments) | ||
return asarStatsToFsStats(asar.statFile(asarPath, filePath)) | ||
} | ||
|
||
const existsSync = fs.existsSync | ||
fs.existsSync = function (p) { | ||
const [isAsar, asarPath, filePath] = splitPath(p) | ||
if (!isAsar) return existsSync.apply(this, arguments) | ||
try { | ||
asar.statFile(asarPath, filePath) | ||
return true | ||
} catch (_error) { | ||
return false | ||
} | ||
} | ||
|
||
const realpathSync = fs.realpathSync | ||
fs.realpathSync = function (p) { | ||
let [isAsar, asarPath, filePath] = splitPath(p) | ||
if (!isAsar) return realpathSync.apply(this, arguments) | ||
const stat = asar.statFile(asarPath, filePath) | ||
if (stat.link) filePath = stat.link | ||
return path.join(realpathSync(asarPath), filePath) | ||
} | ||
|
||
module.exports = fs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
let Module | ||
try { | ||
Module = require('module') | ||
} catch (_error) { | ||
Module = null | ||
} | ||
|
||
const path = require('path') | ||
const fs = require('./fs.js') | ||
const { toAbsolute, splitPath } = require('./util.js') | ||
|
||
function checkFilename (request, absolutePath) { | ||
if (!path.isAbsolute(absolutePath)) throw new Error('Not absolute path.') | ||
if (path.extname(absolutePath) !== '') { | ||
if (fs.existsSync(absolutePath)) return absolutePath | ||
throw new Error('Cannot find module \'' + request + '\'') | ||
} | ||
if (fs.existsSync(absolutePath + '.js')) return absolutePath + '.js' | ||
if (fs.existsSync(absolutePath + '.json')) return absolutePath + '.json' | ||
if (fs.existsSync(absolutePath + '.node')) return absolutePath + '.node' | ||
throw new Error('Cannot find module \'' + request + '\'') | ||
} | ||
|
||
// if (Module && Module._resolveLookupPaths) { | ||
// const oldResolveLookupPaths = Module._resolveLookupPaths | ||
// Module._resolveLookupPaths = function (request, parent, newReturn) { | ||
// const result = oldResolveLookupPaths(request, parent, newReturn) | ||
|
||
// const paths = newReturn ? result : result[1] | ||
// let length = paths.length | ||
// for (let i = 0; i < length; i++) { | ||
// if (path.basename(paths[i]) === 'node_modules') { | ||
// paths.splice(i + 1, 0, paths[i] + '.asar') | ||
// length = paths.length | ||
// } | ||
// } | ||
|
||
// return result | ||
// } | ||
// } | ||
|
||
if (Module && Module._findPath) { | ||
const oldFindPath = Module._findPath | ||
Module._findPath = function (request, paths, isMain) { | ||
const [isAsar, asarPath, filePath] = splitPath(request) | ||
if (!isAsar) return oldFindPath.apply(this, arguments) | ||
if (filePath === '') { | ||
const pkgPath = toAbsolute(path.join(asarPath, 'package.json')) | ||
const indexjs = toAbsolute(path.join(asarPath, 'index.js')) | ||
if (fs.existsSync(pkgPath)) { | ||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) | ||
pkg.main = pkg.main || 'index.js' | ||
const main = toAbsolute(path.join(asarPath, pkg.main)) | ||
return checkFilename(request, main) | ||
} else if (fs.existsSync(indexjs)) { | ||
return indexjs | ||
} else { | ||
throw new Error('Cannot find module \'' + request + '\'') | ||
} | ||
} | ||
|
||
const absoluteRequest = toAbsolute(request) | ||
return checkFilename(request, absoluteRequest) | ||
} | ||
} | ||
|
||
if (Module && Module._resolveFilename) { | ||
const oldResolveFilename = Module._resolveFilename | ||
Module._resolveFilename = function (request, parent, isMain, options) { | ||
if (path.isAbsolute(request) || request.charAt(0) === '.') { | ||
if (parent) { | ||
let paths | ||
if (typeof options === 'object' && options !== null && | ||
Array.isArray(options.paths)) { | ||
const fakeParent = new Module('', null) | ||
|
||
paths = [] | ||
|
||
for (let i = 0; i < options.paths.length; i++) { | ||
const path = options.paths[i] | ||
fakeParent.paths = Module._nodeModulePaths(path) | ||
const lookupPaths = Module._resolveLookupPaths(request, fakeParent, true) | ||
|
||
if (!paths.includes(path)) paths.push(path) | ||
|
||
for (let j = 0; j < lookupPaths.length; j++) { | ||
if (!paths.includes(lookupPaths[j])) paths.push(lookupPaths[j]) | ||
} | ||
} | ||
} else { | ||
paths = Module._resolveLookupPaths(request, parent, true) | ||
} | ||
const index = parent.filename.lastIndexOf('.asar') | ||
if (index !== -1) { | ||
const absoluteRequest = toAbsolute(path.join(path.extname(parent.filename) === '.asar' ? parent.filename : path.dirname(parent.filename), request)) | ||
return checkFilename(request, absoluteRequest) | ||
} | ||
} | ||
} | ||
|
||
return oldResolveFilename.apply(this, arguments) | ||
} | ||
} | ||
|
||
if (Module && Module._extensions) { | ||
Module._extensions['.asar'] = Module._extensions['.asar'] || function (module, filename) { | ||
const pkgPath = toAbsolute(path.join(filename, 'package.json')) | ||
const indexjs = toAbsolute(path.join(filename, 'index.js')) | ||
if (fs.existsSync(pkgPath)) { | ||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) | ||
pkg.main = pkg.main || 'index.js' | ||
const main = toAbsolute(path.join(filename, pkg.main)) | ||
if (path.extname(main) !== '') { | ||
if (fs.existsSync(main)) return Module._extensions[path.extname(main)](module, main) | ||
throw new Error('Cannot find module \'' + filename + '\'') | ||
} | ||
if (fs.existsSync(main + '.js')) return Module._extensions['.js'](module, main + '.js') | ||
if (fs.existsSync(main + '.json')) return Module._extensions['.json'](module, main + '.json') | ||
if (fs.existsSync(main + '.node')) return Module._extensions['.node'](module, main + '.node') | ||
throw new Error('Cannot find module \'' + filename + '\'') | ||
} else if (fs.existsSync(indexjs)) { | ||
return Module._extensions['.js'](module, indexjs) | ||
} else { | ||
throw new Error('Cannot find module \'' + filename + '\'') | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
const path = require('path') | ||
|
||
const mainDir = require.main ? path.dirname(require.main.filename) : process.cwd() | ||
|
||
exports.toAbsolute = function (p) { | ||
return path.isAbsolute(p) ? p : path.join(mainDir, p) | ||
} | ||
|
||
exports.splitPath = function (p) { | ||
if (typeof p !== 'string') return [false] | ||
if (p.substr(-5) === '.asar') return [true, p, ''] | ||
const indexWindows = p.lastIndexOf('.asar\\') | ||
const indexPosix = p.lastIndexOf('.asar/') | ||
if (indexWindows === -1 && indexPosix === -1) return [false] | ||
const index = indexPosix === -1 ? indexWindows : indexPosix | ||
return [true, p.substr(0, index + 5), p.substr(index + 6).replace(/\\/g, '/')] | ||
} |
Oops, something went wrong.