Skip to content

Commit

Permalink
fix(kernel): error raised during rename operation on win32 (#1702)
Browse files Browse the repository at this point in the history
When loading a new library into the jsii kernel, the provided `tarball`
was extracted to a temporary directory, then moved into it's final
location. On Windows, this operation could fail on an `EACCESS` or
`EPERM` error (often due to malware scanners accessing the file for
inspection on file systems which do not support renaming files that are
being accessed).

This changes how the `load` API works so taht the `tarball` is extracted
directly in it's final install location, so that no rename operation is
needed.

Fixes #992 

---

By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license].

[Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0
  • Loading branch information
RomainMuller committed May 26, 2020
1 parent a877f34 commit 38ee336
Showing 1 changed file with 29 additions and 41 deletions.
70 changes: 29 additions & 41 deletions packages/@jsii/kernel/lib/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,51 +104,39 @@ export class Kernel {
types: Object.keys(assm.metadata.types ?? {}).length,
};
}
// untar the archive to a staging directory, read the jsii spec from it
// and then move it to the node_modules directory of the kernel.
const staging = fs.mkdtempSync(
path.join(os.tmpdir(), 'jsii-kernel-install-staging-'),
);
try {
tar.extract({
strict: true,
file: req.tarball,
cwd: staging,
sync: true,
});

// read .jsii metadata from the root of the package
const jsiiMetadataFile = path.join(
staging,
'package',
spec.SPEC_FILE_NAME,
);
if (!fs.pathExistsSync(jsiiMetadataFile)) {
throw new Error(
`Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`,
);
}
const assmSpec = fs.readJsonSync(jsiiMetadataFile) as spec.Assembly;

// "install" to "node_modules" directory
fs.moveSync(path.join(staging, 'package'), packageDir);
// Create the install directory (there may be several path components for @scoped/packages)
fs.mkdirpSync(packageDir);
// untar the archive to its final location
tar.extract({
strict: true,
file: req.tarball,
cwd: packageDir,
strip: 1, // Removes the 'package/' path element from entries
sync: true,
});

// load the module and capture it's closure
const closure = this._execute(
`require(String.raw\`${packageDir}\`)`,
packageDir,
// read .jsii metadata from the root of the package
const jsiiMetadataFile = path.join(packageDir, spec.SPEC_FILE_NAME);
if (!fs.pathExistsSync(jsiiMetadataFile)) {
throw new Error(
`Package tarball ${req.tarball} must have a file named ${spec.SPEC_FILE_NAME} at the root`,
);
const assm = new Assembly(assmSpec, closure);
this._addAssembly(assm);

return {
assembly: assmSpec.name,
types: Object.keys(assmSpec.types ?? {}).length,
};
} finally {
this._debug('removing staging directory:', staging);
fs.removeSync(staging);
}
const assmSpec = fs.readJsonSync(jsiiMetadataFile) as spec.Assembly;

// load the module and capture it's closure
const closure = this._execute(
`require(String.raw\`${packageDir}\`)`,
packageDir,
);
const assm = new Assembly(assmSpec, closure);
this._addAssembly(assm);

return {
assembly: assmSpec.name,
types: Object.keys(assmSpec.types ?? {}).length,
};
}

public create(req: api.CreateRequest): api.CreateResponse {
Expand Down

0 comments on commit 38ee336

Please sign in to comment.