Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1851 from tagomaru/support-global-npm
Browse files Browse the repository at this point in the history
Improvement: Support globally installed npm
  • Loading branch information
CruzMolina committed Apr 23, 2019
2 parents 022773a + 9d820a9 commit 3ce1d5e
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 8 deletions.
9 changes: 5 additions & 4 deletions packages/truffle-compile/profiler.js
Expand Up @@ -391,10 +391,11 @@ module.exports = {
const imports = Parser.parseImports(body, solc);

// Convert explicitly relative dependencies of modules back into module paths.
return imports.map(dependencyPath =>
self.isExplicitlyRelative(dependencyPath)
? source.resolve_dependency_path(file, dependencyPath)
: dependencyPath
return imports.map(
dependencyPath =>
self.isExplicitlyRelative(dependencyPath)
? source.resolve_dependency_path(file, dependencyPath)
: dependencyPath
);
},

Expand Down
4 changes: 2 additions & 2 deletions packages/truffle-core/lib/templates/example.js
@@ -1,6 +1,6 @@
var Example = artifacts.require('Example');
var Example = artifacts.require("Example");

contract('Example', function(accounts) {
contract("Example", function(accounts) {
it("should assert true", function(done) {
var example = Example.deployed();
assert.isTrue(true);
Expand Down
71 changes: 71 additions & 0 deletions packages/truffle-resolver/globalnpm.js
@@ -0,0 +1,71 @@
const path = require("path");
const fs = require("fs");
const detectInstalled = require("detect-installed");
const get_installed_path = require("get-installed-path");
function GlobalNPM() {}

GlobalNPM.prototype.require = function(import_path) {
if (import_path.indexOf(".") === 0 || path.isAbsolute(import_path)) {
return null;
}
const contract_name = path.basename(import_path, ".sol");

let [package_name] = import_path.split("/", 1);
if (detectInstalled.sync(package_name)) {
const regex = new RegExp(`/${package_name}$`);
const global_package_path = get_installed_path
.getInstalledPathSync(package_name)
.replace(regex, "");
const expected_path = path.join(
global_package_path,
package_name,
"build",
"contracts",
contract_name + ".json"
);
try {
const result = fs.readFileSync(expected_path, "utf8");
return JSON.parse(result);
} catch (e) {
return null;
}
}
};

GlobalNPM.prototype.resolve = function(import_path, imported_from, callback) {
let [package_name] = import_path.split("/", 1);
let body;
if (detectInstalled.sync(package_name)) {
const regex = new RegExp(`/${package_name}$`);
const global_package_path = get_installed_path
.getInstalledPathSync(package_name)
.replace(regex, "");
const expected_path = path.join(global_package_path, import_path);
try {
body = fs.readFileSync(expected_path, { encoding: "utf8" });
} catch (err) {}
}

// If nothing's found, body returns `undefined`
return callback(null, body, import_path);
};

// We're resolving package paths to other package paths, not absolute paths.
// This will ensure the source fetcher conintues to use the correct sources for packages.
// i.e., if some_module/contracts/MyContract.sol imported "./AnotherContract.sol",
// we're going to resolve it to some_module/contracts/AnotherContract.sol, ensuring
// that when this path is evaluated this source is used again.
GlobalNPM.prototype.resolve_dependency_path = function(
import_path,
dependency_path
) {
var dirname = path.dirname(import_path);
return path.join(dirname, dependency_path);
};

GlobalNPM.prototype.provision_contracts = function(callback) {
// TODO: Fill this out!
callback(null, {});
};

module.exports = GlobalNPM;
2 changes: 2 additions & 0 deletions packages/truffle-resolver/index.js
@@ -1,5 +1,6 @@
var EPMSource = require("./epm");
var NPMSource = require("./npm");
var GlobalNPMSource = require("./globalnpm");
var FSSource = require("./fs");
var whilst = require("async/whilst");
var contract = require("truffle-contract");
Expand All @@ -14,6 +15,7 @@ function Resolver(options) {
this.sources = [
new EPMSource(options.working_directory, options.contracts_build_directory),
new NPMSource(options.working_directory),
new GlobalNPMSource(),
new FSSource(options.working_directory, options.contracts_build_directory)
];
}
Expand Down
9 changes: 7 additions & 2 deletions packages/truffle-resolver/package.json
Expand Up @@ -3,7 +3,9 @@
"version": "5.0.11",
"description": "Resolve contract dependencies given multiple configurable dependency sources",
"main": "index.js",
"scripts": {},
"scripts": {
"test": "mocha"
},
"repository": "https://github.com/trufflesuite/truffle/tree/master/packages/truffle-resolver",
"keywords": [
"ethereum",
Expand All @@ -19,12 +21,15 @@
"homepage": "https://github.com/trufflesuite/truffle-resolver#readme",
"dependencies": {
"async": "2.6.1",
"detect-installed": "^2.0.4",
"get-installed-path": "^4.0.8",
"truffle-contract": "^4.0.12",
"truffle-expect": "^0.0.7",
"truffle-provisioner": "^0.1.4"
},
"devDependencies": {
"mocha": "5.2.0"
"mocha": "5.2.0",
"sinon": "^7.3.1"
},
"publishConfig": {
"access": "public"
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

168 changes: 168 additions & 0 deletions packages/truffle-resolver/test/globalnpm.js
@@ -0,0 +1,168 @@
const assert = require("assert");
const GlobalNPM = require("../globalnpm");
const global_npm = new GlobalNPM();
const detectInstalled = require("detect-installed");
const get_installed_path = require("get-installed-path");
const sinon = require("sinon");
const path = require("path");
const fs = require("fs");

describe("globalnpm", () => {
describe("require function", () => {
let sync_stub;
let get_installed_path_sync_stub;

beforeEach(() => {
sync_stub = sinon.stub(detectInstalled, "sync");
get_installed_path_sync_stub = sinon.stub(
get_installed_path,
"getInstalledPathSync"
);
});

afterEach(() => {
sync_stub.restore();
get_installed_path_sync_stub.restore();
});

it("should return null if the import_path starts with '.'", () => {
const result = global_npm.require("./A.sol");
assert.deepEqual(result, null);
});

it("should return null if the import_path is absolute path", () => {
const result = global_npm.require("/A.sol");
assert.deepEqual(result, null);
});

it("should return the contents of json if the import_path exists", () => {
sync_stub.withArgs("package").returns(true);
get_installed_path_sync_stub
.withArgs("package")
.returns(
path.resolve(__dirname, "fixtures/globalnpm/node_modules/package")
);

const result = global_npm.require("package/contracts/Test.sol");

assert.deepEqual(result, {});
});

it("should return undefined if the import_path does not exist", () => {
const read_file_sync_stub = sinon.stub(fs, "readFileSync");

sync_stub.withArgs("package").returns(false);

const result = global_npm.require("package/contracts/Test.sol");

assert.ok(!get_installed_path_sync_stub.called);
assert.deepEqual(result, undefined);

read_file_sync_stub.restore();
});

it("should return null if readFileSync throws Error", () => {
const read_file_sync_stub = sinon.stub(fs, "readFileSync");

sync_stub.withArgs("package").returns(true);
get_installed_path_sync_stub
.withArgs("package")
.returns(
path.resolve(__dirname, "fixtures/globalnpm/node_modules/package")
);
read_file_sync_stub.throws("some error");

const result = global_npm.require("package/contracts/Test.sol");

assert.deepEqual(result, null);

read_file_sync_stub.restore();
});
});

describe("resolve function", () => {
let sync_stub;
let get_installed_path_sync_stub;

beforeEach(() => {
sync_stub = sinon.stub(detectInstalled, "sync");
get_installed_path_sync_stub = sinon.stub(
get_installed_path,
"getInstalledPathSync"
);
});

afterEach(() => {
sync_stub.restore();
get_installed_path_sync_stub.restore();
});

it("should return the contents of solidity file if the import_path exists", () => {
sync_stub.withArgs("package").returns(true);
get_installed_path_sync_stub
.withArgs("package")
.returns(
path.resolve(__dirname, "fixtures/globalnpm/node_modules/package")
);

const callback = (err, body, import_path) => {
assert.strictEqual(err, null);
assert.strictEqual(body, "contract Test {}\n");
assert.strictEqual(import_path, "package/contracts/Test.sol");
};

global_npm.resolve(
"package/contracts/Test.sol",
"imported_from",
callback
);
});

it("should return undefined body if the package does not exist", () => {
sync_stub.withArgs("package").returns(false);
get_installed_path_sync_stub
.withArgs("package")
.returns(
path.resolve(__dirname, "fixtures/globalnpm/node_modules/package")
);

const callback = (err, body, import_path) => {
assert.strictEqual(err, null);
assert.strictEqual(body, undefined);
assert.strictEqual(import_path, "package/contracts/Test.sol");
};

global_npm.resolve(
"package/contracts/Test.sol",
"imported_from",
callback
);
});

it("should return undefined body if readFileSync throws Error", () => {
const read_file_sync_stub = sinon.stub(fs, "readFileSync");

sync_stub.withArgs("package").returns(true);
get_installed_path_sync_stub
.withArgs("package")
.returns(
path.resolve(__dirname, "fixtures/globalnpm/node_modules/package")
);
read_file_sync_stub.throws("some error");

const callback = (err, body, import_path) => {
assert.strictEqual(err, null);
assert.strictEqual(body, undefined);
assert.strictEqual(import_path, "package/contracts/Test.sol");
};

global_npm.resolve(
"package/contracts/Test.sol",
"imported_from",
callback
);

read_file_sync_stub.restore();
});
});
});

0 comments on commit 3ce1d5e

Please sign in to comment.