embark
1 #!/usr/bin/env node 2 3 /* global __dirname __filename process require */ 4 5 // This script doesn't use JS syntax, packages, or APIs *un*supported by any 6 // node version >=4.0.0, so unsupported versions from v4.0.0+ will get the 7 // intended error messages. A future version of this script could instead rely 8 // on babel to achieve the same goal. 9 // See: https://node.green/ 10 11 // KEY ASSUMPTION: for a DApp to be valid, from embark's perspective, it must 12 // have a parsable embark.json file in its top-level directory; if that 13 // requirement changes in the future then this script must be revised. 14 // Hypothetical example of such a change: embark config info may be included in 15 // package.json under `{"embark": {...}}` -or- stored in an embark.json file. 16 17 function main() { 18 whenNoShim(); 19 var invoked = thisEmbark(); 20 var embarkJson = findEmbarkJson(); 21 var dappPath = embarkJson.dirname; 22 process.chdir(dappPath); 23 process.env.DAPP_PATH = dappPath; 24 process.env.PWD = dappPath; 25 26 /* attempt to find a "local" embark in or above but not below dappPath 27 28 let `dappPath/(([../])*)bin/embark` be a "containing" embark 29 30 let `dappPath/(([../])*)node_modules/embark/bin/embark` be an "installed" 31 embark 32 33 if containing and installed embarks are both found, and if containing 34 embark is higher in the dir structure than installed embark, then 35 containing embark will be selected 36 37 according to the rule above: if an installed embark is found within a 38 containing embark's own node_modules (that would be odd), installed embark 39 will be selected 40 41 invoked embark may find itself as local embark, but that is detected by 42 comparing `binrealpath` props to avoid double-checking and infinite loops 43 44 if no local embark is found then cmd execution will use invoked embark */ 45 46 var containing = findBinContaining(dappPath, invoked); 47 var installed = findBinInstalled(dappPath, invoked); 48 var local = selectLocal(containing, installed); 49 var pkgJson = findPkgJson(dappPath, embarkJson, local); 50 process.env.PKG_PATH = pkgJson.dirname; 51 var embark = select(invoked, local); 52 process.env.EMBARK_PATH = embark.pkgDir; 53 embark.exec(); 54 } 55 56 // ----------------------------------------------------------------------------- 57 58 var checkDeps = require('check-dependencies'); 59 var npmlog = require('npmlog'); 60 var findUp = require('find-up'); 61 var fs = require('fs'); 62 var path = require('path'); 63 var parseJsonWithErrors = require('json-parse-better-errors'); 64 var pkgUp = require('pkg-up'); 65 var semver = require('semver'); 66 var subdir = require('subdir'); 67 68 // -- embark bins -------------------------------------------------------------- 69 70 function EmbarkBin(binpath, kind) { 71 this.binpath = binpath; 72 this.binrealpath = undefined; 73 this.kind = kind || 'invoked'; 74 this.pkgDir = undefined; 75 this.pkgJson = undefined; 76 } 77 78 EmbarkBin.prototype.exec = function () { 79 var Cmd = require('../cmd/cmd'); 80 var cli = new Cmd(); 81 if(_logged) { console[this.loglevel](); } 82 cli.process(process.argv); 83 }; 84 85 EmbarkBin.prototype.handle = function () { 86 this.setup(); 87 this.log(); 88 return this; 89 }; 90 91 EmbarkBin.prototype.log = function () { 92 this.logMissingBin(); 93 this.pkgJson.log(); 94 }; 95 96 EmbarkBin.prototype.loglevel = 'info'; 97 98 EmbarkBin.prototype.logMissingBin = function () { 99 var oldlevel = this.loglevel; 100 this.loglevel = 'error'; 101 if (!this.binrealpath) { 102 reportMissingFile_EmbarkBin(this.binpath, this.kind, this.loglevel); 103 exitWithError(); 104 } 105 this.loglevel = oldlevel; 106 }; 107 108 EmbarkBin.prototype.setBinrealpath = function () { 109 if (this.binpath) { 110 this.binrealpath = realpath(this.binpath); 111 } 112 }; 113 114 EmbarkBin.prototype.setPkgDir = function () { 115 if (this.binpath) { 116 this.pkgDir = path.join(path.dirname(this.binpath), '..'); 117 } 118 }; 119 120 EmbarkBin.prototype.setPkgJson = function () { 121 if (this.binrealpath) { 122 this.pkgJson = ( 123 new PkgJsonEmbark( 124 path.join(this.pkgDir, 'package.json'), 125 this.kind 126 ) 127 ); 128 var upNodeModules = findUp.sync( 129 'node_modules', 130 {cwd: path.join(path.dirname(this.binrealpath), '../..')} 131 ); 132 this.pkgJson.noCheck = ( 133 upNodeModules ? subdir(upNodeModules, this.binrealpath) : false 134 ); 135 this.pkgJson.setup(); 136 } 137 }; 138 139 EmbarkBin.prototype.setup = function () { 140 this.setBinrealpath(); 141 this.setPkgDir(); 142 this.setPkgJson(); 143 return this; 144 }; 145 146 // -- bin/embark :: local ------------------------------------------------------ 147 148 function EmbarkBinLocal(binpath, invokedEmbark) { 149 EmbarkBin.call(this, binpath, 'local'); 150 this.invokedEmbark = invokedEmbark; 151 } 152 setupProto(EmbarkBinLocal, EmbarkBin); 153 154 EmbarkBinLocal.prototype.exec = function () { 155 process.argv[1] = this.binpath; 156 process.env.EMBARK_NO_SHIM = true; 157 console[this.loglevel](); 158 require(this.binpath); 159 }; 160 161 EmbarkBinLocal.prototype.log = function () { 162 if (this.binrealpath !== this.invokedEmbark.binrealpath) { 163 this.logSwitching(); 164 EmbarkBin.prototype.log.call(this); 165 } 166 }; 167 168 EmbarkBinLocal.prototype.logSwitching = function () { 169 reportSwitching( 170 this.invokedEmbark.binpath, 171 this.binpath, 172 this.loglevel, 173 this.invokedEmbark.pkgJson.pkg, 174 this.pkgJson.pkg 175 ); 176 }; 177 178 EmbarkBinLocal.prototype.setup = function () { 179 this.setBinrealpath(); 180 this.setPkgDir(); 181 if (this.binrealpath !== this.invokedEmbark.binrealpath) { 182 this.setPkgJson(); 183 } 184 return this; 185 }; 186 187 // -- bin/embark :: local containing ------------------------------------------- 188 189 function EmbarkBinLocalContaining(binpath, invokedEmbark) { 190 EmbarkBinLocal.call(this, binpath, invokedEmbark); 191 } 192 setupProto(EmbarkBinLocalContaining, EmbarkBinLocal); 193 194 EmbarkBinLocalContaining.prototype.setPkgJson = function () { 195 if (this.binrealpath) { 196 this.pkgJson = ( 197 new PkgJsonEmbark( 198 path.join(this.pkgDir, 'package.json'), 199 this.kind 200 ) 201 ); 202 this.pkgJson.noCheck = false; 203 this.pkgJson.setup(); 204 } 205 }; 206 207 // -- bin/embark :: local installed -------------------------------------------- 208 209 function EmbarkBinLocalInstalled(binpath, invokedEmbark) { 210 EmbarkBinLocal.call(this, binpath, invokedEmbark); 211 } 212 setupProto(EmbarkBinLocalInstalled, EmbarkBinLocal); 213 214 EmbarkBinLocalInstalled.prototype.log = function () { 215 EmbarkBinLocal.prototype.log.call(this); 216 this.pkgJsonLocalExpected.log(); 217 }; 218 219 EmbarkBinLocalInstalled.prototype.setPkgJson = function () { 220 if (this.binrealpath) { 221 this.pkgJson = ( 222 new PkgJsonEmbark( 223 path.join(this.pkgDir, 'package.json'), 224 this.kind 225 ) 226 ).setup(); 227 } 228 }; 229 230 EmbarkBinLocalInstalled.prototype.setPkgJsonLocalExpected = function () { 231 if (this.binrealpath) { 232 this.pkgJsonLocalExpected = ( 233 new PkgJsonLocalExpected(path.join(this.pkgDir, '../../package.json')) 234 ).setup(); 235 } 236 }; 237 238 EmbarkBinLocalInstalled.prototype.setup = function () { 239 EmbarkBinLocal.prototype.setup.call(this); 240 this.setPkgJsonLocalExpected(); 241 return this; 242 }; 243 244 // -- finders ------------------------------------------------------------------ 245 246 function findBin(dappPath, find, invoked, Kind) { 247 return ( 248 new Kind( 249 findUp.sync(find, {cwd: dappPath}), 250 invoked 251 ) 252 ).setup(); 253 } 254 255 function findBinContaining(dappPath, invoked) { 256 return findBin( 257 dappPath, 258 'bin/embark', 259 invoked, 260 EmbarkBinLocalContaining 261 ); 262 } 263 264 function findBinInstalled(dappPath, invoked) { 265 return findBin( 266 dappPath, 267 'node_modules/embark/bin/embark', 268 invoked, 269 EmbarkBinLocalInstalled 270 ); 271 } 272 273 function findEmbarkJson() { 274 // findUp search begins in process.cwd() by default, but embark.json could 275 // be in a subdir if embark was invoked via `npm run` (which changes cwd to 276 // package.json's dir) and the package.json is in a dir above the top-level 277 // DApp dir; so start at INIT_CWD if that has been set (by npm, presumably) 278 // See: https://docs.npmjs.com/cli/run-script 279 var startDir = initCwd(); 280 return (new EmbarkJson( 281 findUp.sync('embark.json', {cwd: startDir}) || 282 path.join(startDir, 'embark.json'), 283 process.argv[2] 284 )).handle(); 285 } 286 287 function findPkgJson(dappPath, embarkJson, local) { 288 var skipDirs = []; 289 if (local) { 290 if (local instanceof EmbarkBinLocalContaining) { 291 skipDirs.push(local.pkgDir); 292 } 293 if (local instanceof EmbarkBinLocalInstalled) { 294 skipDirs.push(local.pkgJsonLocalExpected.dirname); 295 } 296 } 297 var closest, dir, found; 298 var startDir = dappPath; 299 300 /* let `dappPath/(([../])*)package.json` be a "local" package.json */ 301 302 // look for local package.json files starting from dappPath 303 function stop() { 304 found = pkgUp.sync(startDir); 305 if (found && !closest) { 306 closest = found; 307 } 308 dir = found ? path.dirname(found) : found; 309 var stop = !dir || !isDappCmd(embarkJson.cmd); 310 if (!stop) { 311 startDir = path.join(dir, '..'); 312 } 313 return stop; 314 } 315 while (!stop()) { 316 if (skipDirs.indexOf(dir) === -1) { 317 (new PkgJsonLocal(found)).handle(); 318 } 319 } 320 if (isDappCmd(embarkJson.cmd) && !closest) { 321 var loglevel = 'error'; 322 reportMissingFile(path.join(dappPath, 'package.json'), loglevel); 323 reportMissingFile_DappJson(embarkJson.cmd, loglevel, 'package', 'in or above'); 324 exitWithError(); 325 } 326 return ( 327 closest || (new PkgJsonLocal(path.join(startDir, 'package.json'))).setup() 328 ); 329 } 330 331 // -- json files --------------------------------------------------------------- 332 333 function Json(filepath) { 334 this.filepath = filepath; 335 this.dirname = undefined; 336 this.json = undefined; 337 this.realpath = undefined; 338 } 339 340 Json.prototype.handle = function () { 341 this.setup(); 342 this.log(); 343 return this; 344 }; 345 346 Json.prototype.log = function () { 347 this.logMissingFile(); 348 this.logUnparsable(); 349 }; 350 351 Json.prototype.loglevel = 'warn'; 352 353 Json.prototype.logMissingFile = function () { 354 var missing; 355 if (!this.realpath) { 356 missing = true; 357 reportMissingFile(this.filepath, this.loglevel); 358 } 359 return missing; 360 }; 361 362 Json.prototype.logUnparsable = function () { 363 var unparsable; 364 if (this.realpath && !this.json) { 365 unparsable = true; 366 reportUnparsable(this.filepath, this.loglevel); 367 } 368 return unparsable; 369 }; 370 371 Json.prototype.setDirname = function () { 372 if (this.filepath) { 373 this.dirname = path.dirname(this.filepath); 374 } 375 }; 376 377 Json.prototype.setJson = function () { 378 if (this.realpath) { 379 this.json = parseJson(this.filepath); 380 } 381 }; 382 383 Json.prototype.setRealpath = function () { 384 if (this.filepath) { 385 this.realpath = realpath(this.filepath); 386 } 387 }; 388 389 Json.prototype.setup = function () { 390 this.setDirname(); 391 this.setRealpath(); 392 this.setJson(); 393 return this; 394 }; 395 396 // -- embark.json -------------------------------------------------------------- 397 398 function EmbarkJson(filepath, cmd) { 399 Json.call(this, filepath); 400 this.cmd = cmd; 401 } 402 setupProto(EmbarkJson, Json); 403 404 EmbarkJson.prototype.loglevel = 'error'; 405 406 EmbarkJson.prototype.log = function () { 407 this.logMissingFile(); 408 this.logUnparsable(); 409 }; 410 411 EmbarkJson.prototype.logMissingFile = function () { 412 if (isDappCmd(this.cmd) && Json.prototype.logMissingFile.call(this)) { 413 reportMissingFile_DappJson(this.cmd, this.loglevel, 'embark', 'in'); 414 exitWithError(); 415 } 416 }; 417 418 EmbarkJson.prototype.logUnparsable = function () { 419 if (isDappCmd(this.cmd) && Json.prototype.logUnparsable.call(this)) { 420 reportUnparsable_EmbarkJson(this.loglevel); 421 exitWithError(); 422 } 423 }; 424 425 // -- package.json ------------------------------------------------------------- 426 427 function PkgJson(filepath) { 428 Json.call(this, filepath); 429 } 430 setupProto(PkgJson, Json); 431 432 PkgJson.prototype.log = function () { 433 Json.prototype.log.call(this); 434 this.logPkgErrors(); 435 }; 436 437 PkgJson.prototype.logPkgErrors = function () { 438 var pkgErrors; 439 if (this.json && !this.noCheck) { 440 pkgErrors = checkPkg(this.dirname); 441 } 442 if (pkgErrors) { 443 reportPkgErrors(pkgErrors, this.filepath, this.loglevel); 444 } 445 return !!pkgErrors; 446 }; 447 448 PkgJson.prototype.noCheck = false; 449 450 // -- package.json :: of an embark pkg ----------------------------------------- 451 452 function PkgJsonEmbark(filepath, kind) { 453 PkgJson.call(this, filepath); 454 this.kind = kind || 'invoked'; 455 this.nodeRange = undefined; 456 this.pkg = undefined; 457 this.version = undefined; 458 } 459 setupProto(PkgJsonEmbark, PkgJson); 460 461 PkgJsonEmbark.prototype.log = function () { 462 PkgJson.prototype.log.call(this); 463 this.logMissingVersion(); 464 this.logUnsupportedNode(); 465 }; 466 467 PkgJsonEmbark.prototype.loglevel = 'error'; 468 469 PkgJsonEmbark.prototype.logMissingFile = function () { 470 if (PkgJson.prototype.logMissingFile.call(this)) { 471 reportMissingFile_PkgJsonEmbark(this.kind, this.loglevel); 472 exitWithError(); 473 } 474 }; 475 476 PkgJsonEmbark.prototype.logMissingVersion = function () { 477 var missing; 478 var oldlevel = this.loglevel; 479 this.loglevel = 'warn'; 480 if (this.json && this.version === '???') { 481 missing = true; 482 reportMissingVersion(this.filepath, this.kind, this.loglevel); 483 } 484 this.loglevel = oldlevel; 485 return missing; 486 }; 487 488 PkgJsonEmbark.prototype.logPkgErrors = function () { 489 if (PkgJson.prototype.logPkgErrors.call(this)) { 490 reportPkgErrors_PkgJsonEmbark(this.dirname, this.kind, this.loglevel); 491 exitWithError(); 492 } 493 }; 494 495 PkgJsonEmbark.prototype.logUnparsable = function () { 496 if (PkgJson.prototype.logUnparsable.call(this)) { 497 reportUnparsable_PkgJsonEmbark(this.kind, this.loglevel); 498 exitWithError(); 499 } 500 }; 501 502 PkgJsonEmbark.prototype.logUnsupportedNode = function () { 503 var missing; 504 var range = this.nodeRange; 505 if (typeof range === 'undefined') { 506 missing = true; 507 range = this.nodeRangeDefault; 508 } 509 var bad; 510 range = parseRange(range); 511 if (!range) { 512 bad = true; 513 range = this.nodeRangeDefault; 514 } 515 var procVer = semver.clean(process.version); 516 this.loglevel = 'error'; 517 if (!semver.satisfies(procVer, range)) { 518 reportUnsupportedNode( 519 bad, 520 this.filepath, 521 this.kind, 522 this.loglevel, 523 missing, 524 this.nodeRangeDefault, 525 this.nodeRange, 526 this.pkg, 527 procVer, 528 range 529 ); 530 exitWithError(); 531 } 532 }; 533 534 PkgJsonEmbark.prototype.noCheck = true; 535 536 // if changing to the `nodeRangeDefault` value, make sure to manually check 537 // that it's a valid semver range, otherwise fallback logic in the prototype 538 // methods won't be reliable 539 PkgJsonEmbark.prototype.nodeRangeDefault = semver.Range('>=8.11.3').range; 540 541 PkgJsonEmbark.prototype.setNodeRange = function () { 542 if (isObject(this.json) && 543 this.json.hasOwnProperty('engines') && 544 this.json.engines.hasOwnProperty('node')) { 545 this.nodeRange = this.json.engines.node; 546 } 547 }; 548 549 PkgJsonEmbark.prototype.setPkg = function () { 550 this.pkg = `embark@${this.version}`; 551 }; 552 553 PkgJsonEmbark.prototype.setVersion = function () { 554 if (isObject(this.json) && this.json.version) { 555 this.version = this.json.version; 556 } else { 557 this.version = '???'; 558 } 559 }; 560 561 PkgJsonEmbark.prototype.setup = function () { 562 PkgJson.prototype.setup.call(this); 563 this.setVersion(); 564 this.setPkg(); 565 this.setNodeRange(); 566 return this; 567 }; 568 569 // -- package.json :: local to DApp -------------------------------------------- 570 571 function PkgJsonLocal(filepath) { 572 PkgJson.call(this, filepath); 573 } 574 setupProto(PkgJsonLocal, PkgJson); 575 576 PkgJsonLocal.prototype.loglevel = 'error'; 577 578 PkgJsonLocal.prototype.logMissingFile = function () { 579 if (PkgJson.prototype.logMissingFile.call(this)) { 580 reportMissingFile_PkgJsonLocal(this.loglevel); 581 exitWithError(); 582 } 583 }; 584 585 PkgJsonLocal.prototype.logPkgErrors = function () { 586 if (PkgJson.prototype.logPkgErrors.call(this)) { 587 reportPkgErrors_PkgJsonLocal(this.dirname, this.loglevel); 588 exitWithError(); 589 } 590 }; 591 592 PkgJsonLocal.prototype.logUnparsable = function () { 593 if (PkgJson.prototype.logUnparsable.call(this)) { 594 reportUnparsable_PkgJsonLocal(this.loglevel); 595 exitWithError(); 596 } 597 }; 598 599 // -- package.json :: local to DApp, expected by local installed embark -------- 600 601 function PkgJsonLocalExpected(filepath) { 602 PkgJsonLocal.call(this, filepath); 603 this.embarkDep = undefined; 604 } 605 setupProto(PkgJsonLocalExpected, PkgJsonLocal); 606 607 PkgJsonLocalExpected.prototype.log = function () { 608 PkgJsonLocal.prototype.log.call(this); 609 this.logMissingEmbarkDep(); 610 }; 611 612 PkgJsonLocalExpected.prototype.logMissingEmbarkDep = function () { 613 if (this.json && !this.embarkDep) { 614 reportMissingEmbarkDep(this.filepath, this.dirname, this.loglevel); 615 exitWithError(); 616 } 617 }; 618 619 PkgJsonLocalExpected.prototype.logMissingFile = function () { 620 // PkgJson.prototype NOT PkgJsonLocal.prototype 621 if (PkgJson.prototype.logMissingFile.call(this)) { 622 reportMissingFile_PkgJsonLocalExpected(this.dirname, this.loglevel); 623 exitWithError(); 624 } 625 }; 626 627 PkgJsonLocalExpected.prototype.setEmbarkDep = function () { 628 if (isObject(this.json)) { 629 if (this.json.dependencies) { 630 this.embarkDep = this.json.dependencies.embark; 631 } else if (this.json.devDependencies) { 632 this.embarkDep = this.json.devDependencies.embark; 633 } 634 } 635 }; 636 637 PkgJsonLocalExpected.prototype.setup = function () { 638 PkgJsonLocal.prototype.setup.call(this); 639 this.setEmbarkDep(); 640 return this; 641 }; 642 643 // -- loggers ------------------------------------------------------------------ 644 645 var embarklog = npmlog; 646 embarklog.heading = 'embark'; 647 648 var _logged = false; 649 function logged(which) { 650 var embarklog_which = embarklog[which]; 651 return function () { 652 _logged = true; 653 embarklog_which.apply(embarklog, arguments); 654 }; 655 } 656 657 embarklog.error = logged('error'); 658 embarklog.info = logged('info'); 659 embarklog.warn = logged('warn'); 660 661 function blankLineMaybe(which) { 662 if (_logged) { 663 console[which](); 664 } 665 } 666 667 var isNpmRun = process.env.hasOwnProperty('npm_lifecycle_script'); 668 function blankLineTrailingMaybe(which) { 669 if (isNpmRun) { 670 console[which](); 671 } 672 } 673 674 // -- processors --------------------------------------------------------------- 675 676 function checkPkg(pkgDir, scopes) { 677 var errors; 678 try { 679 var config = {packageDir: pkgDir}; 680 if (scopes) { 681 config.scopeList = scopes; 682 } 683 var checked = checkDeps.sync(config); 684 if (checked.error.length) { 685 errors = checked.error; 686 } 687 } finally { 688 // eslint-disable-next-line no-unsafe-finally 689 return errors; 690 } 691 } 692 693 function parseJson(filepath) { 694 var parsed; 695 try { 696 parsed = require(filepath); 697 } finally { 698 // eslint-disable-next-line no-unsafe-finally 699 return parsed; 700 } 701 } 702 703 function parseRange(range) { 704 var parsed; 705 try { 706 parsed = semver.Range(range).range; 707 } finally { 708 // eslint-disable-next-line no-unsafe-finally 709 return parsed; 710 } 711 } 712 713 function realpath(filepath) { 714 var resolved; 715 try { 716 resolved = fs.realpathSync(filepath); 717 } finally { 718 // eslint-disable-next-line no-unsafe-finally 719 return resolved; 720 } 721 } 722 723 function thisEmbark() { 724 return (new EmbarkBin(__filename)).handle(); 725 } 726 727 function whenNoShim() { 728 var noShim = false; 729 if (process.env.EMBARK_NO_SHIM) { 730 noShim = true; 731 } 732 if (noShim) { 733 EmbarkBin.prototype.exec(); 734 } 735 } 736 737 // -- reporters ---------------------------------------------------------------- 738 739 function reportMissingEmbarkDep(filepath, dirname, loglevel) { 740 blankLineMaybe(loglevel); 741 embarklog[loglevel]('file', filepath); 742 embarklog[loglevel]( 743 '', 744 [ 745 `Could not find embark specified in "dependencies" or "devDependencies" of local package.json file`, 746 `But embark was found in node_modules relative to that file:`, 747 `${dirname}/node_modules/embark/` 748 ].join('\n') 749 ); 750 } 751 752 function reportMissingFile(filepath, loglevel) { 753 try { 754 // force the exception 755 fs.realpathSync(filepath); 756 } catch (e) { 757 blankLineMaybe(loglevel); 758 embarklog[loglevel]('path', e.path); 759 embarklog[loglevel]('code', e.code); 760 embarklog[loglevel]('errno', e.errno); 761 embarklog[loglevel]('syscall', e.syscall); 762 embarklog[loglevel](e.code.toLowerCase(), e.message); 763 } 764 } 765 766 function reportMissingFile_DappJson(cmd, loglevel, kind, where) { 767 blankLineMaybe(loglevel); 768 embarklog[loglevel]( 769 '', 770 `Could not locate your DApp's ${kind}.json file` 771 ); 772 embarklog[loglevel]( 773 '', 774 `Make sure a valid ${kind}.json file exists ${where} your DApp's top-level directory` 775 ); 776 embarklog[loglevel]( 777 '', 778 `Embark command '${cmd}' can only be used inside a valid DApp directory structure` 779 ); 780 } 781 782 function reportMissingFile_EmbarkBin(binpath, kind, loglevel) { 783 reportMissingFile(binpath, loglevel); 784 console[loglevel](); 785 embarklog[loglevel]( 786 '', 787 [ 788 `Could not resolve ${kind} embark command path with require('fs').realpathSync`, 789 `Maybe a broken symbolic link?` 790 ].join('\n') 791 ); 792 } 793 794 function reportMissingFile_PkgJsonEmbark(kind, loglevel) { 795 console[loglevel](); 796 embarklog[loglevel]( 797 '', 798 `Could not locate ${kind} embark's package.json file` 799 ); 800 } 801 802 function reportMissingFile_PkgJsonLocal(loglevel) { 803 console[loglevel](); 804 embarklog[loglevel]( 805 '', 806 [ 807 `Could not resolve local package.json path with require('fs').realpathSync`, 808 `Maybe a broken symbolic link?` 809 ].join('\n') 810 ); 811 } 812 813 function reportMissingFile_PkgJsonLocalExpected(dirname, loglevel) { 814 console[loglevel](); 815 embarklog[loglevel]( 816 '', 817 [ 818 `Could not find expected local package.json relative to embark found in:`, 819 `${dirname}/node_modules/embark/` 820 ].join('\n') 821 ); 822 } 823 824 function reportMissingVersion(filepath, kind, loglevel) { 825 blankLineMaybe(loglevel); 826 embarklog[loglevel]('file', filepath); 827 embarklog[loglevel]( 828 '', 829 `No version is specified in ${kind} embark's package.json file` 830 ); 831 } 832 833 function reportPkgErrors(errors, filepath, loglevel) { 834 blankLineMaybe(loglevel); 835 embarklog[loglevel]('file', filepath); 836 embarklog[loglevel]('code', `EPKGCHK`); 837 embarklog[loglevel]('package', errors.join('\n')); 838 } 839 840 function reportPkgErrors_PkgJsonEmbark(dirname, kind, loglevel) { 841 console[loglevel](); 842 embarklog[loglevel]( 843 '', 844 [ 845 `Dependencies are missing relative to ${kind} embark's package.json in:`, 846 `${dirname}/` 847 ].join('\n') 848 ); 849 } 850 851 function reportPkgErrors_PkgJsonLocal(dirname, loglevel) { 852 console[loglevel](); 853 embarklog[loglevel]( 854 '', 855 [ 856 `Dependencies are missing relative to local package.json in:`, 857 `${dirname}/` 858 ].join('\n') 859 ); 860 } 861 862 function reportSwitching(binpathFrom, binpathTo, loglevel, pkgFrom, pkgTo) { 863 blankLineMaybe(loglevel); 864 embarklog[loglevel]('invoked', binpathFrom); 865 embarklog[loglevel]('located', binpathTo); 866 embarklog[loglevel]( 867 '', 868 `Switching from ${pkgFrom} to ${pkgTo}` 869 ); 870 } 871 872 function reportUnparsable(filepath, loglevel) { 873 try { 874 // force the exception 875 parseJsonWithErrors(stripBOM(fs.readFileSync(filepath))); 876 } catch (e) { 877 var basename = path.basename(filepath); 878 blankLineMaybe(loglevel); 879 embarklog[loglevel]('file', filepath); 880 embarklog[loglevel]('code', `EJSONPARSE`); 881 embarklog[loglevel]('JSON parse', `Failed to parse json`); 882 embarklog[loglevel]('JSON parse', e.message); 883 embarklog[loglevel]('JSON parse', `Failed to parse ${basename} data.`); 884 embarklog[loglevel]('JSON parse', `${basename} must be actual JSON, not just JavaScript.`); 885 } 886 } 887 888 function reportUnparsable_EmbarkJson(loglevel) { 889 console[loglevel](); 890 embarklog[loglevel]('', `Could not parse your DApp's embark.json file`); 891 } 892 893 function reportUnparsable_PkgJsonEmbark(kind, loglevel) { 894 console[loglevel](); 895 embarklog[loglevel]( 896 `Could not parse ${kind} embark's package.json file` 897 ); 898 } 899 900 function reportUnparsable_PkgJsonLocal(loglevel) { 901 embarklog[loglevel]('', `Could not parse a local package.json file`); 902 } 903 904 function reportUnsupportedNode( 905 bad, filepath, kind, loglevel, missing, rangeDefault, rangeSupplied, pkg, 906 procVer, range) { 907 blankLineMaybe(loglevel); 908 function report(qual, invalid) { 909 embarklog[loglevel]('file', filepath); 910 embarklog[loglevel]( 911 'engine', 912 `package.json of ${kind} ${pkg} does not specify ${qual ? qual : ''}%j`, 913 {engines: {node: '[semver]'}} 914 ); 915 if (invalid) { 916 embarklog[loglevel]( 917 'engine', 918 `Specified: %j`, {engines: {node: rangeSupplied}} 919 ); 920 } 921 embarklog[loglevel]( 922 'engine', 923 `Defaulting to: %j`, {engines: {node: rangeDefault}} 924 ); 925 console[loglevel](); 926 } 927 if (missing) { report(); } 928 if (bad) { report('a valid ', true); } 929 embarklog[loglevel]('notsup', `Unsupported runtime`); 930 embarklog[loglevel]( 931 'notsup', 932 `${kind} ${pkg} is not compatible with your version of node` 933 ); 934 embarklog[loglevel]('notsup', `Required:`, range); 935 embarklog[loglevel]('notsup', `Actual:`, procVer); 936 } 937 938 // -- selectors ---------------------------------------------------------------- 939 940 function select(invoked, local) { 941 var embark; 942 if (local && local.binrealpath !== invoked.binrealpath) { 943 embark = local; 944 } else { 945 embark = invoked; 946 } 947 return embark; 948 } 949 950 function selectLocal(containing, installed) { 951 var local; 952 if (containing.binrealpath && 953 (!installed.binrealpath || 954 subdir( 955 installed.pkgJsonLocalExpected.dirname, 956 containing.pkgDir 957 ))) { 958 local = containing; 959 } 960 if (installed.binrealpath && 961 (!containing.binrealpath || 962 subdir(containing.pkgDir, installed.pkgDir))) { 963 local = installed; 964 } 965 if (local) { local.log(); } 966 return local; 967 } 968 969 // -- utils -------------------------------------------------------------------- 970 971 function exitWithError(code) { 972 blankLineTrailingMaybe('error'); 973 process.exit(code || 1); 974 } 975 976 function initCwd() { 977 var initCwd = process.env.INIT_CWD || process.cwd(); 978 // allow for env override 979 initCwd = process.env.DAPP_PATH || initCwd; 980 return initCwd; 981 } 982 983 function isDappCmd(cmd) { 984 return [ 985 undefined, 986 '-V', 987 '--version', 988 '-h', 989 '--help', 990 'new', 991 'demo', 992 'version', 993 'help' 994 ].indexOf(cmd) === -1; 995 } 996 997 function isObject(val) { 998 // eslint-disable-next-line no-eq-null 999 return val != null && typeof val === 'object' && Array.isArray(val) === false; 1000 } 1001 1002 function setupProto(Sub, Par) { 1003 Sub.prototype = Object.create(Par.prototype); 1004 Sub.prototype.constructor = Sub; 1005 } 1006 1007 // See: https://github.com/npm/cli/blob/v6.4.1/lib/utils/parse-json.js#L16 1008 function stripBOM (content) { 1009 content = content.toString(); 1010 if (content.charCodeAt(0) === 0xFEFF) { 1011 content = content.slice(1); 1012 } 1013 return content; 1014 } 1015 1016 // ----------------------------------------------------------------------------- 1017 1018 main();