折腾:
【未解决】给gitbook install的npm添加代理无效
期间,去研究
git install
输出的log
xxx@xxx ~/dev/crifan/gitbook/gitbook_template/books/gitbook_demo master ● gitbook install info: installing 18 plugins using npm@3.9.2 info: info: installing plugin "google-adsense" info: install plugin "google-adsense" (*) from NPM with version 0.1.0
另外,从报错中:
at ReadStream.Readable.on (_stream_readable.js:849:29) at untarStream (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:304:8) at addShrinkwrap (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:200:3) at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/fetch-package-metadata.js:185:14 at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/iferr/index.js:13:50 at RES (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/inflight/inflight.js:23:14) at f (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/once/once.js:17:25) at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/lib/cache.js:362:16 at /Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/write-file-atomic/index.js:29:9 at LOOP (/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/node_modules/slide/lib/chain.js:7:26)
可以看出:
内部调用到了:
/Users/xxx/.gitbook/versions/3.2.3
下面的npm
node_modules/npm
想要搞清楚内部npm内部如何用上代理。
/Users/xxx/.gitbook/versions/3.2.3/package.json
{ "name": "gitbook", "version": "3.2.3", "homepage": "https://www.gitbook.com", "description": "Library and cmd utility to generate GitBooks",
其中的:
3.2.3是gitbook的版本
搜:
install
找到了:
/Users/xxx/.gitbook/versions/3.2.3/lib/cli/index.js
var buildEbook = require('./buildEbook'); module.exports = [ require('./build'), require('./serve'), require('./install'), require('./parse'), require('./init'), buildEbook('pdf'), buildEbook('epub'), buildEbook('mobi') ];
除了install
还要很多,比如pdf/epub/mobi等格式,和之前的build/serve/init等命令
引用的是
/Users/xxx/.gitbook/versions/3.2.3/lib/cli/install.js
var options = require('./options'); var getBook = require('./getBook'); var Parse = require('../parse'); var Plugins = require('../plugins'); module.exports = { name: 'install [book]', description: 'install all plugins dependencies', options: [ options.log ], exec: function(args, kwargs) { var book = getBook(args, kwargs); return Parse.parseConfig(book) .then(function(resultBook) { return Plugins.installPlugins(resultBook); }); } };
此处引用的是:
Plugins.installPlugins
通过加了:
console.info("book=%o", book)
调试打印出:
gitbook install book=Record { "logger": [object Object], "fs": Record { "root": "/Users/xxx/dev/crifan/gitbook/gitbook_template/books/gitbook_demo", "fsExists": function fileExists(filename) { var d = Promise.defer(); fs.exists(filename, function(exists) { d.resolve(exists); }); return d.promise; }, "fsReadFile": function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }, "fsStatFile": function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }, "fsReadDir": function fsReadDir(folder) { return fs.readdir(folder) .then(function(files) { files = Immutable.List(files); return files .map(function(file) { if (file == '.' || file == '..') return; var stat = fs.statSync(path.join(folder, file)); if (stat.isDirectory()) file = file + path.sep; return file; }) .filter(function(file) { return Boolean(file); }); }); }, "fsLoadObject": function fsLoadObject(filename) { return fresh(filename, require); }, "fsReadAsStream": function createReadStream (path, options) { return new ReadStream(path, options) } }, "ignore": Ignore { "ignore": [object Object] }, "config": Config { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "values": Map { "gitbook": "*", "theme": "default", "variables": Map {}, "plugins": List [], "pluginsConfig": Map {}, "structure": Map { "langs": "LANGS.md", "readme": "README.md", "glossary": "GLOSSARY.md", "summary": "SUMMARY.md" }, "pdf": Map { "pageNumbers": true, "fontSize": 12, "fontFamily": "Arial", "paperSize": "a4", "chapterMark": "pagebreak", "pageBreaksBefore": "/", "margin": Map { "right": 62, "left": 62, "top": 56, "bottom": 56 } } } }, "readme": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "title": "", "description": "" }, "summary": Summary { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "parts": List [] }, "glossary": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "entries": OrderedMap {} }, "languages": Record { "file": Record { "path": "", "mtime": "Wed Jan 20 2021 21:04:04 GMT+0800 (中国标准时间)" }, "list": OrderedMap {} }, "language": "", "books": OrderedMap {} } (node:1340) [DEP0079] DeprecationWarning: Custom inspection function on Objects via .inspect() is deprecated 。。。
另外:
console.info("resultBook=%o", resultBook)
输出类似。
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugins.js
var npmi = require('npmi'); var DEFAULT_PLUGINS = require('../constants/defaultPlugins'); var Promise = require('../utils/promise'); var installPlugin = require('./installPlugin'); /** Install plugin requirements for a book @param {Book} @return {Promise<Number>} */ function installPlugins(book) { var logger = book.getLogger(); var config = book.getConfig(); var plugins = config.getPluginDependencies(); // Remove default plugins // (only if version is same as installed) plugins = plugins.filterNot(function(plugin) { var dependency = DEFAULT_PLUGINS.find(function(dep) { return dep.getName() === plugin.getName(); }); return ( // Disabled plugin !plugin.isEnabled() || // Or default one installed in GitBook itself (dependency && plugin.getVersion() === dependency.getVersion()) ); }); if (plugins.size == 0) { logger.info.ln('nothing to install!'); return Promise(); } logger.info.ln('installing', plugins.size, 'plugins using npm@' + npmi.NPM_VERSION); return Promise.forEach(plugins, function(plugin) { return installPlugin(book, plugin); }) .thenResolve(plugins.size); } module.exports = installPlugins;
去打印:
console.info("config=%o", config)
出:
config=Config { "file": Record { "path": "book.json", "mtime": Wed Jan 20 2021 16:47:19 GMT+0800 (中国标准时间) }, "values": Map { "plugins": List [ "google-adsense", "theme-comscore", "anchors", "-lunr", "-search", "search-plus", "disqus", "-highlight", "prism", "prism-themes", "github-buttons", "splitter", "-sharing", "sharing-plus", "tbfed-pagefooter", "expandable-chapters-small", "ga", "donate", "sitemap-general", "copy-code-button", "callouts", "toolbar-button" ], "root": "./src", "pluginsConfig": Map { "tbfed-pagefooter": Map { "copyright": "crifan.org,使用<a href='https://creativecommons.org/licenses/by/4.0/deed.zh'>署名4.0国际(CC BY 4.0)协议</a>发布", "modify_label": "最后更新:", "modify_format": "YYYY-MM-DD HH:mm:ss" }, "prism": Map { "css": List [ "prism-themes/themes/prism-atom-dark.css" ] }, "disqus": Map { "shortName": "crifan" }, "callouts": Map { "showTypeInHeader": false }, "toolbar-button": Map { "url": "http://book.crifan.org/books/gitbook_demo/pdf/gitbook_demo.pdf", "icon": "fa-file-pdf-o", "label": "下载PDF" }, "autocover": Map { "title": "Gitbook演示", "author": "Crifan Li <xxx>", "font": Map { "size": null, "family": "Impact", "color": "#FFF" }, "size": Map { "w": 1800, "h": 2360 }, "background": Map { "color": "#09F" } }, "donate": Map { "wechat": "https://www.crifan.org/files/res/crifan_com/crifan_wechat_pay.jpg", "alipay": "https://www.crifan.org/files/res/crifan_com/crifan_alipay_pay.jpg", "title": "", "button": "打赏", "alipayText": "支付宝打赏给Crifan", "wechatText": "微信打赏给Crifan" }, "sitemap-general": Map { "prefix": "https://book.crifan.org/gitbook/gitbook_demo/website/" }, "google-adsense": Map { "ads": List [ Map { "client": "ca-pub-6626240105039250" } ] }, "github-buttons": Map { "buttons": List [ Map { "repo": "gitbook_demo", "user": "crifan", "type": "star", "count": true, "size": "small" }, Map { "user": "crifan", "type": "follow", "width": "120", "count": false, "size": "small" } ] }, "ga": Map { "token": "UA-28297199-1" }, "sharing": Map { "qq": true, "all": List [ "douban", "facebook", "google", "instapaper", "line", "linkedin", "messenger", "pocket", "qq", "qzone", "stumbleupon", "twitter", "viber", "vk", "weibo", "whatsapp" ], "douban": false, "facebook": true, "weibo": true, "instapaper": false, "whatsapp": false, "hatenaBookmark": false, "twitter": true, "messenger": false, "line": false, "vk": false, "pocket": false, "google": false, "viber": false, "stumbleupon": false, "qzone": false, "linkedin": false }, "theme-default": Map { "showLevel": true } }, "theme": "default", "author": "Crifan Li <xxx>", "pdf": Map { "pageNumbers": true, "fontSize": 12, "fontFamily": "Arial", "paperSize": "a4", "chapterMark": "pagebreak", "pageBreaksBefore": "/", "margin": Map { "right": 62, "left": 62, "top": 56, "bottom": 56 } }, "structure": Map { "langs": "LANGS.md", "readme": "README.md", "glossary": "GLOSSARY.md", "summary": "SUMMARY.md" }, "variables": Map {}, "title": "Gitbook演示", "language": "zh-hans", "links": Map { "sidebar": Map { "主页": "https://www.crifan.org" } }, "gitbook": "3.2.3", "description": "crifan的Gitbook模版,用于演示如何用Gitbook创建一个自己的book电子书" } }
就是我们的gitbook_demo的配置
console.info("plugins=%o", plugins)
输出:
plugins=List [ PluginDependency { "name": "google-adsense", "version": "*", "enabled": true }, PluginDependency { "name": "theme-comscore", "version": "*", "enabled": true }, PluginDependency { "name": "anchors", "version": "*", "enabled": true }, PluginDependency { "name": "search-plus", "version": "*", "enabled": true }, PluginDependency { "name": "disqus", "version": "*", "enabled": true }, PluginDependency { "name": "prism", "version": "*", "enabled": true }, PluginDependency { "name": "prism-themes", "version": "*", "enabled": true }, PluginDependency { "name": "github-buttons", "version": "*", "enabled": true }, PluginDependency { "name": "splitter", "version": "*", "enabled": true }, PluginDependency { "name": "sharing-plus", "version": "*", "enabled": true }, PluginDependency { "name": "tbfed-pagefooter", "version": "*", "enabled": true }, PluginDependency { "name": "expandable-chapters-small", "version": "*", "enabled": true }, PluginDependency { "name": "ga", "version": "*", "enabled": true }, PluginDependency { "name": "donate", "version": "*", "enabled": true }, PluginDependency { "name": "sitemap-general", "version": "*", "enabled": true }, PluginDependency { "name": "copy-code-button", "version": "*", "enabled": true }, PluginDependency { "name": "callouts", "version": "*", "enabled": true }, PluginDependency { "name": "toolbar-button", "version": "*", "enabled": true } ]
是此处的插件列表
继续:
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugin.js
var npmi = require('npmi'); var Promise = require('../utils/promise'); var resolveVersion = require('./resolveVersion'); /** Install a plugin for a book @param {Book} @param {PluginDependency} @return {Promise} */ function installPlugin(book, plugin) { var logger = book.getLogger(); var installFolder = book.getRoot(); var name = plugin.getName(); var requirement = plugin.getVersion(); logger.info.ln(''); logger.info.ln('installing plugin "' + name + '"'); // Find a version to install return resolveVersion(plugin) .then(function(version) { if (!version) { throw new Error('Found no satisfactory version for plugin "' + name + '" with requirement "' + requirement + '"'); } logger.info.ln('install plugin "' + name +'" (' + requirement + ') from NPM with version', version); return Promise.nfcall(npmi, { 'name': plugin.getNpmID(), 'version': version, 'path': installFolder, 'npmLoad': { 'loglevel': 'silent', 'loaded': true, 'prefix': installFolder } }); }) .then(function() { logger.info.ok('plugin "' + name + '" installed with success'); }); } module.exports = installPlugin;
貌似核心的是:
return Promise.nfcall(npmi, {
看到函数原型是:
/Users/xxx/Library/Caches/typescript/4.1/node_modules/@types/q/index.d.ts
/** * Calls a Node.js-style function with the given variadic arguments, returning a promise that is fulfilled if the * Node.js function calls back with a result, or rejected if it calls back with an error * (or throws one synchronously). An example: * * @example * Q.nfcall(FS.readFile, "foo.txt", "utf-8").done(function (text) { * }); * * The same warning about functions vs. methods applies for nfcall as it does for nfapply. In this case, the better * strategy would be to use Q.ninvoke. */ export function nfcall<T>(nodeFunction: (...args: any[]) => any, ...args: any[]): Promise<T>;
此处:
- nodeFunction=npmi
- args = 此处json=dict
{ 'name': plugin.getNpmID(), 'version': version, 'path': installFolder, 'npmLoad': { 'loglevel': 'silent', 'loaded': true, 'prefix': installFolder }
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npmi/npmi.js
var npm = require('npm'); var fs = require('fs'); var path = require('path'); var semver = require('semver'); var LOAD_ERR = 'NPM_LOAD_ERR', INSTALL_ERR = 'NPM_INSTALL_ERR', VIEW_ERR = 'NPM_VIEW_ERR'; /** * Created with IntelliJ IDEA. * User: leiko * Date: 30/01/14 * Time: 10:28 */ var npmi = function (options, callback) { callback = callback || function () {}; var name = options.name, pkgName = options.pkgName || name, version = options.version || 'latest', installPath = options.path || '.', forceInstall = options.forceInstall || false, localInstall = options.localInstall || false, npmLoad = options.npmLoad || {loglevel: 'silent'}, savedPrefix = null; function viewCallback(installedVersion) { 。。。 function checkInstalled(isTarball) { 。。。 function installCallback(err, result) { // reset npm.prefix to saved value npm.prefix = savedPrefix; if (err) { err.code = INSTALL_ERR; } callback(err, result); } 。。。 function loadCallback(err) { 。。。 npmi.LOAD_ERR = LOAD_ERR; npmi.INSTALL_ERR = INSTALL_ERR; npmi.VIEW_ERR = VIEW_ERR; npmi.NPM_VERSION = npm.version; module.exports = npmi;
感觉是:
此处报错就是调用了installCallback,发生了error
试试:
// callback(err, result); console.info("err=%o", err) console.info("result=%o", result)
输出:
好像没有多余输出。
另外去看:
loadCallback
console.info("loadCallback:err=%o", err)
没有
console.info("checkInstalled: isTarball=%o", isTarball)
结果:
没有
function viewCallback(installedVersion) { console.info("viewCallback: installedVersion=%o", installedVersion)
也没有。
var npmi = function (options, callback) { console.info("npmi: options=%o", options)
结果:也没有。
看来不是这个文件。
console.info("in npmi")
有输出,确定是加载了:
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npmi/npmi.js
搜npmi
找到
/Users/xxx/.gitbook/versions/3.2.3/package.json
"npm": "3.9.2", "npmi": "2.0.1",
console.info("npmLoad=%o", npmLoad) console.info("loadCallback=%o", loadCallback) npm.load(npmLoad, loadCallback);
结果:没有
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/package.json
"bin": { "npm": "./bin/npm-cli.js" },
去看看
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm-cli.js
#!/usr/bin/env node ;(function () { // wrapper in case we're in module_context mode // windows: running "npm blah" in this folder will invoke WSH, not node. /*global WScript*/ if (typeof WScript !== 'undefined') { WScript.echo( 'npm does not work when run\n' + 'with the Windows Scripting Host\n\n' + "'cd' to a different directory,\n" + "or type 'npm.cmd <args>',\n" + "or type 'node npm <args>'." ) WScript.quit(1) return } process.title = 'npm' var log = require('npmlog') log.pause() // will be unpaused when config is loaded. log.info('it worked if it ends with', 'ok') var path = require('path') var npm = require('../lib/npm.js') var npmconf = require('../lib/config/core.js') var errorHandler = require('../lib/utils/error-handler.js') var configDefs = npmconf.defs var shorthands = configDefs.shorthands var types = configDefs.types var nopt = require('nopt') // if npm is called as "npmg" or "npm_g", then // run in global mode. if (path.basename(process.argv[1]).slice(-1) === 'g') { process.argv.splice(1, 1, 'npm', '-g') } log.verbose('cli', process.argv) var conf = nopt(types, shorthands) npm.argv = conf.argv.remain if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift() else conf.usage = true if (conf.version) { console.log(npm.version) return } if (conf.versions) { npm.command = 'version' conf.usage = false npm.argv = [] } log.info('using', 'npm@%s', npm.version) log.info('using', 'node@%s', process.version) process.on('uncaughtException', errorHandler) if (conf.usage && npm.command !== 'help') { npm.argv.unshift(npm.command) npm.command = 'help' } // now actually fire up npm and run the command. // this is how to use npm programmatically: conf._exit = true npm.load(conf, function (er) { if (er) return errorHandler(er) npm.commands[npm.command](npm.argv, errorHandler) }) })() #!/usr/bin/env node ;(function () { // wrapper in case we're in module_context mode // windows: running "npm blah" in this folder will invoke WSH, not node. /*global WScript*/ if (typeof WScript !== 'undefined') { WScript.echo( 'npm does not work when run\n' + 'with the Windows Scripting Host\n\n' + "'cd' to a different directory,\n" + "or type 'npm.cmd <args>',\n" + "or type 'node npm <args>'." ) WScript.quit(1) return } process.title = 'npm' var log = require('npmlog') log.pause() // will be unpaused when config is loaded. log.info('it worked if it ends with', 'ok') var path = require('path') var npm = require('../lib/npm.js') var npmconf = require('../lib/config/core.js') var errorHandler = require('../lib/utils/error-handler.js') var configDefs = npmconf.defs var shorthands = configDefs.shorthands var types = configDefs.types var nopt = require('nopt') // if npm is called as "npmg" or "npm_g", then // run in global mode. if (path.basename(process.argv[1]).slice(-1) === 'g') { process.argv.splice(1, 1, 'npm', '-g') } log.verbose('cli', process.argv) var conf = nopt(types, shorthands) npm.argv = conf.argv.remain if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift() else conf.usage = true if (conf.version) { console.log(npm.version) return } if (conf.versions) { npm.command = 'version' conf.usage = false npm.argv = [] } log.info('using', 'npm@%s', npm.version) log.info('using', 'node@%s', process.version) process.on('uncaughtException', errorHandler) if (conf.usage && npm.command !== 'help') { npm.argv.unshift(npm.command) npm.command = 'help' } // now actually fire up npm and run the command. // this is how to use npm programmatically: conf._exit = true npm.load(conf, function (er) { if (er) return errorHandler(er) npm.commands[npm.command](npm.argv, errorHandler) }) })()
另外还有
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm.cmd
/Users/xxx/.gitbook/versions/3.2.3/node_modules/npm/bin/npm
console.info("in versions/3.2.3/node_modules/npm/bin/npm-cli.js")
结果:没输出。
回去注意到
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/installPlugin.js
// Find a version to install return resolveVersion(plugin) .then(function(version) {
去看看
/Users/xxx/.gitbook/versions/3.2.3/lib/plugins/resolveVersion.js
/** Resolve a plugin dependency to a version @param {PluginDependency} plugin @return {Promise<String>} */ function resolveVersion(plugin) { var npmId = Plugin.nameToNpmID(plugin.getName()); var requiredVersion = plugin.getVersion(); if (plugin.isGitDependency()) { return Promise.resolve(requiredVersion); } ...
用:
function resolveVersion(plugin) { console.info("plugin=%o", plugin)
输出:
plugin=PluginDependency { "name": "google-adsense", "version": "*", "enabled": true }
function resolveVersion(plugin) { console.info("plugin=%o", plugin) var npmId = Plugin.nameToNpmID(plugin.getName()); console.info("npmId=%o", npmId) var requiredVersion = plugin.getVersion(); console.info("requiredVersion=%o", requiredVersion) if (plugin.isGitDependency()) { console.info("plugin.isGitDependency is True") return Promise.resolve(requiredVersion); } return initNPM() .then(function() { console.info("complete initNPM") console.info("npm.commands=%o", npm.commands) console.info("npm.commands.view=%o", npm.commands.view) return Promise.nfcall(npm.commands.view, [npmId + '@' + requiredVersion, 'engines'], true); })
输出:
plugin=PluginDependency { "name": "google-adsense", "version": "*", "enabled": true } npmId='gitbook-plugin-google-adsense' requiredVersion='*' (node:2659) [DEP0079] DeprecationWarning: Custom inspection function on Objects via .inspect() is deprecated complete initNPM npm.commands={ [ac]: [Getter], [acc]: [Getter], [acce]: [Getter], [acces]: [Getter], access: [Getter], [add-]: [Getter], [add-u]: [Getter], 。。。 [whoam]: [Getter], whoami: [Getter], [build]: [Getter], [unbuild]: [Getter], [xmas]: [Getter], [substack]: [Getter], [visnup]: [Getter] } npm.commands.view={ [Function] [length]: 0, [name]: '', [arguments]: null, [caller]: null, [prototype]: { [constructor]: [Circular] }, usage: 'npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...]\n\naliases: v, info, show', completion: { [Function] [length]: 2, [name]: '', [arguments]: null, [caller]: null, [prototype]: { [constructor]: [Circular] } } }
看到是:
npm view [<@scope>/]<pkg>[@<version>] [<field>[.subfield]...]\n\naliases: v, info, show
想到去:
xxx@xxx ~/.gitbook/versions/3.2.3/node_modules/npm bin/npm-cli.js --version in versions/3.2.3/node_modules/npm/bin/npm-cli.js 3.9.2
-》实现了我们希望的,至少找到了:npm对应的二进制是哪个