Skip to content

Commit f63298c

Browse files
committed
Add npm and pip package managers working properly.
1 parent db807f1 commit f63298c

File tree

6 files changed

+386
-12
lines changed

6 files changed

+386
-12
lines changed

source/examples/metacallcli/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,12 @@ install(TARGETS ${target}
125125
# Define test
126126
#
127127

128+
set(TEST_COMMAND_LINE_ARGS "help") # TODO: Forward all commands, create an adaptor to existing system
128129
set(TEST_COMMAND_LINE_ARGS "load mock test.mock")
129130

131+
# TODO: NODE_PATH=`npm root --quiet -g`
132+
#set(TEST_COMMAND_LINE_ARGS "install node rambda")
133+
130134
if(WIN32)
131135
set(TEST_COMMAND cmd /c)
132136
else()

source/examples/metacallcli/application.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
#include <clocale>
3030

31+
/* Package Managers */
32+
#include "package_manager/pip.hpp"
33+
#include "package_manager/npm.hpp"
34+
3135
/* -- Namespace Declarations -- */
3236

3337
using namespace metacallcli;
@@ -338,18 +342,8 @@ void application::parameter_iterator::evaluate()
338342
/* List of scripts that run pip/npm/gem */
339343
static std::unordered_map<std::string, std::string> install_scripts =
340344
{
341-
{
342-
"py",
343-
"#!/usr/bin/env python3\n"
344-
"\n"
345-
"try:\n"
346-
" from pip import main as pipmain\n"
347-
"except ImportError:\n"
348-
" from pip._internal import main as pipmain\n"
349-
"\n"
350-
"def package_manager(args):\n"
351-
" return pipmain(args);\n"
352-
}
345+
{ "py", package_manager::pip },
346+
{ "node", package_manager::npm }
353347
};
354348

355349
/* List of available commands when installing */
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* MetaCall Command Line Interface by Parra Studios
3+
* Copyright (C) 2016 - 2020 Vicente Eduardo Ferrer Garcia <[email protected]>
4+
*
5+
* A command line interface example as metacall wrapper.
6+
*
7+
*/
8+
9+
#ifndef METACALL_CLI_PACKAGE_MANAGER_NPM_HPP
10+
#define METACALL_CLI_PACKAGE_MANAGER_NPM_HPP 1
11+
12+
/* -- Namespace -- */
13+
14+
namespace metacallcli {
15+
16+
namespace package_manager {
17+
18+
static const char npm[] =
19+
"#!/usr/bin/env node\n"
20+
"\n"
21+
"/* This has been ripped off from NPM and adapted to be callable instead of invoked by exec */\n"
22+
"\n"
23+
"function package_manager(args) {\n"
24+
" // windows: running npm blah in this folder will invoke WSH, not node.\n"
25+
" /* global WScript */\n"
26+
" if (typeof WScript !== 'undefined') {\n"
27+
" WScript.echo(\n"
28+
" 'npm does not work when run\\n' +\n"
29+
" 'with the Windows Scripting Host\\n\\n' +\n"
30+
" \"'cd' to a different directory,\\n\" +\n"
31+
" \"or type 'npm.cmd <args>',\\n\" +\n"
32+
" \"or type 'node npm <args>'.\"\n"
33+
" )\n"
34+
" WScript.quit(1)\n"
35+
" return\n"
36+
" }\n"
37+
"\n"
38+
" var unsupported = require('npm/lib/utils/unsupported.js')\n"
39+
" unsupported.checkForBrokenNode()\n"
40+
"\n"
41+
" var log = require('npm/node_modules/npmlog')\n"
42+
" log.pause() // will be unpaused when config is loaded.\n"
43+
" log.info('it worked if it ends with', 'ok')\n"
44+
"\n"
45+
" unsupported.checkForUnsupportedNode()\n"
46+
"\n"
47+
" var path = require('path')\n"
48+
" var npm = require('npm/lib/npm.js')\n"
49+
" var npmconf = require('npm/lib/config/core.js')\n"
50+
" var errorHandler = require('npm/lib/utils/error-handler.js')\n"
51+
"\n"
52+
" var configDefs = npmconf.defs\n"
53+
" var shorthands = configDefs.shorthands\n"
54+
" var types = configDefs.types\n"
55+
" var nopt = require('npm/node_modules/nopt')\n"
56+
"\n"
57+
" // Overwrite process args\n"
58+
" process.argv = [ 'node', 'npm', ...args ];\n"
59+
"\n"
60+
" log.verbose('cli', process.argv)\n"
61+
"\n"
62+
" var conf = nopt(types, shorthands)\n"
63+
" npm.argv = conf.argv.remain\n"
64+
" if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift()\n"
65+
" else conf.usage = true\n"
66+
"\n"
67+
" if (conf.version) {\n"
68+
" console.log(npm.version)\n"
69+
" return errorHandler.exit(0)\n"
70+
" }\n"
71+
"\n"
72+
" if (conf.versions) {\n"
73+
" npm.command = 'version'\n"
74+
" conf.usage = false\n"
75+
" npm.argv = []\n"
76+
" }\n"
77+
"\n"
78+
" log.info('using', 'npm@%s', npm.version)\n"
79+
" log.info('using', 'node@%s', process.version)\n"
80+
"\n"
81+
" process.on('uncaughtException', errorHandler)\n"
82+
"\n"
83+
" if (conf.usage && npm.command !== 'help') {\n"
84+
" npm.argv.unshift(npm.command)\n"
85+
" npm.command = 'help'\n"
86+
" }\n"
87+
"\n"
88+
" var isGlobalNpmUpdate = conf.global && ['install', 'update'].includes(npm.command) && npm.argv.includes('npm')\n"
89+
"\n"
90+
" // now actually fire up npm and run the command.\n"
91+
" // this is how to use npm programmatically:\n"
92+
" conf._exit = true\n"
93+
" npm.load(conf, function (er) {\n"
94+
" if (er) return errorHandler(er)\n"
95+
" if (\n"
96+
" !isGlobalNpmUpdate &&\n"
97+
" npm.config.get('update-notifier') &&\n"
98+
" !unsupported.checkVersion(process.version).unsupported\n"
99+
" ) {\n"
100+
" const pkg = require('npm/package.json')\n"
101+
" let notifier = require('npm/node_modules/update-notifier')({pkg})\n"
102+
" const isCI = require('npm/node_modules/ci-info').isCI\n"
103+
" if (\n"
104+
" notifier.update &&\n"
105+
" notifier.update.latest !== pkg.version &&\n"
106+
" !isCI\n"
107+
" ) {\n"
108+
" const color = require('ansicolors')\n"
109+
" const useColor = npm.config.get('color')\n"
110+
" const useUnicode = npm.config.get('unicode')\n"
111+
" const old = notifier.update.current\n"
112+
" const latest = notifier.update.latest\n"
113+
" let type = notifier.update.type\n"
114+
" if (useColor) {\n"
115+
" switch (type) {\n"
116+
" case 'major':\n"
117+
" type = color.red(type)\n"
118+
" break\n"
119+
" case 'minor':\n"
120+
" type = color.yellow(type)\n"
121+
" break\n"
122+
" case 'patch':\n"
123+
" type = color.green(type)\n"
124+
" break\n"
125+
" }\n"
126+
" }\n"
127+
" const changelog = `https://github.com/npm/cli/releases/tag/v${latest}`\n"
128+
" notifier.notify({\n"
129+
" message: `New ${type} version of ${pkg.name} available! ${\n"
130+
" useColor ? color.red(old) : old\n"
131+
" } ${useUnicode ? '→' : '->'} ${\n"
132+
" useColor ? color.green(latest) : latest\n"
133+
" }\\n` +\n"
134+
" `${\n"
135+
" useColor ? color.yellow('Changelog:') : 'Changelog:'\n"
136+
" } ${\n"
137+
" useColor ? color.cyan(changelog) : changelog\n"
138+
" }\\n` +\n"
139+
" `Run ${\n"
140+
" useColor\n"
141+
" ? color.green(`npm install -g ${pkg.name}`)\n"
142+
" : `npm i -g ${pkg.name}`\n"
143+
" } to update!`\n"
144+
" })\n"
145+
" }\n"
146+
" }\n"
147+
" npm.commands[npm.command](npm.argv, function (err) {\n"
148+
" // https://genius.com/Lin-manuel-miranda-your-obedient-servant-lyrics\n"
149+
" if (\n"
150+
" !err &&\n"
151+
" npm.config.get('ham-it-up') &&\n"
152+
" !npm.config.get('json') &&\n"
153+
" !npm.config.get('parseable') &&\n"
154+
" npm.command !== 'completion'\n"
155+
" ) {\n"
156+
" console.error(\n"
157+
" `\\n ${\n"
158+
" npm.config.get('unicode') ? '🎵 ' : ''\n"
159+
" } I Have the Honour to Be Your Obedient Servant,${\n"
160+
" npm.config.get('unicode') ? '🎵 ' : ''\n"
161+
" } ~ npm ${\n"
162+
" npm.config.get('unicode') ? '📜🖋 ' : ''\n"
163+
" }\\n`\n"
164+
" )\n"
165+
" }\n"
166+
" errorHandler.apply(this, arguments)\n"
167+
" })\n"
168+
" })\n"
169+
"}\n"
170+
"\n"
171+
"module.exports = {\n"
172+
" package_manager,\n"
173+
"};\n";
174+
175+
} /* namespace package_manager */
176+
177+
} /* namespace metacallcli */
178+
179+
#endif /* METACALL_CLI_PACKAGE_MANAGER_NPM_HPP */
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env node
2+
3+
/* This has been ripped off from NPM and adapted to be callable instead of invoked by exec */
4+
5+
function package_manager(args) {
6+
// windows: running "npm blah" in this folder will invoke WSH, not node.
7+
/* global WScript */
8+
if (typeof WScript !== 'undefined') {
9+
WScript.echo(
10+
'npm does not work when run\n' +
11+
'with the Windows Scripting Host\n\n' +
12+
"'cd' to a different directory,\n" +
13+
"or type 'npm.cmd <args>',\n" +
14+
"or type 'node npm <args>'."
15+
)
16+
WScript.quit(1)
17+
return
18+
}
19+
20+
var unsupported = require('npm/lib/utils/unsupported.js')
21+
unsupported.checkForBrokenNode()
22+
23+
var log = require('npm/node_modules/npmlog')
24+
log.pause() // will be unpaused when config is loaded.
25+
log.info('it worked if it ends with', 'ok')
26+
27+
unsupported.checkForUnsupportedNode()
28+
29+
var path = require('path')
30+
var npm = require('npm/lib/npm.js')
31+
var npmconf = require('npm/lib/config/core.js')
32+
var errorHandler = require('npm/lib/utils/error-handler.js')
33+
34+
var configDefs = npmconf.defs
35+
var shorthands = configDefs.shorthands
36+
var types = configDefs.types
37+
var nopt = require('npm/node_modules/nopt')
38+
39+
// Overwrite process args
40+
process.argv = [ 'node', 'npm', ...args ];
41+
42+
log.verbose('cli', process.argv)
43+
44+
var conf = nopt(types, shorthands)
45+
npm.argv = conf.argv.remain
46+
if (npm.deref(npm.argv[0])) npm.command = npm.argv.shift()
47+
else conf.usage = true
48+
49+
if (conf.version) {
50+
console.log(npm.version)
51+
return errorHandler.exit(0)
52+
}
53+
54+
if (conf.versions) {
55+
npm.command = 'version'
56+
conf.usage = false
57+
npm.argv = []
58+
}
59+
60+
log.info('using', 'npm@%s', npm.version)
61+
log.info('using', 'node@%s', process.version)
62+
63+
process.on('uncaughtException', errorHandler)
64+
65+
if (conf.usage && npm.command !== 'help') {
66+
npm.argv.unshift(npm.command)
67+
npm.command = 'help'
68+
}
69+
70+
var isGlobalNpmUpdate = conf.global && ['install', 'update'].includes(npm.command) && npm.argv.includes('npm')
71+
72+
// now actually fire up npm and run the command.
73+
// this is how to use npm programmatically:
74+
conf._exit = true
75+
npm.load(conf, function (er) {
76+
if (er) return errorHandler(er)
77+
if (
78+
!isGlobalNpmUpdate &&
79+
npm.config.get('update-notifier') &&
80+
!unsupported.checkVersion(process.version).unsupported
81+
) {
82+
const pkg = require('npm/package.json')
83+
let notifier = require('npm/node_modules/update-notifier')({pkg})
84+
const isCI = require('npm/node_modules/ci-info').isCI
85+
if (
86+
notifier.update &&
87+
notifier.update.latest !== pkg.version &&
88+
!isCI
89+
) {
90+
const color = require('ansicolors')
91+
const useColor = npm.config.get('color')
92+
const useUnicode = npm.config.get('unicode')
93+
const old = notifier.update.current
94+
const latest = notifier.update.latest
95+
let type = notifier.update.type
96+
if (useColor) {
97+
switch (type) {
98+
case 'major':
99+
type = color.red(type)
100+
break
101+
case 'minor':
102+
type = color.yellow(type)
103+
break
104+
case 'patch':
105+
type = color.green(type)
106+
break
107+
}
108+
}
109+
const changelog = `https://github.com/npm/cli/releases/tag/v${latest}`
110+
notifier.notify({
111+
message: `New ${type} version of ${pkg.name} available! ${
112+
useColor ? color.red(old) : old
113+
} ${useUnicode ? '→' : '->'} ${
114+
useColor ? color.green(latest) : latest
115+
}\n` +
116+
`${
117+
useColor ? color.yellow('Changelog:') : 'Changelog:'
118+
} ${
119+
useColor ? color.cyan(changelog) : changelog
120+
}\n` +
121+
`Run ${
122+
useColor
123+
? color.green(`npm install -g ${pkg.name}`)
124+
: `npm i -g ${pkg.name}`
125+
} to update!`
126+
})
127+
}
128+
}
129+
npm.commands[npm.command](npm.argv, function (err) {
130+
// https://genius.com/Lin-manuel-miranda-your-obedient-servant-lyrics
131+
if (
132+
!err &&
133+
npm.config.get('ham-it-up') &&
134+
!npm.config.get('json') &&
135+
!npm.config.get('parseable') &&
136+
npm.command !== 'completion'
137+
) {
138+
console.error(
139+
`\n ${
140+
npm.config.get('unicode') ? '🎵 ' : ''
141+
} I Have the Honour to Be Your Obedient Servant,${
142+
npm.config.get('unicode') ? '🎵 ' : ''
143+
} ~ npm ${
144+
npm.config.get('unicode') ? '📜🖋 ' : ''
145+
}\n`
146+
)
147+
}
148+
errorHandler.apply(this, arguments)
149+
})
150+
})
151+
}
152+
153+
module.exports = {
154+
package_manager,
155+
};

0 commit comments

Comments
 (0)