summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcknight <cknight1234@gmail.com>2020-01-30 01:57:29 +0000
committerGitHub <noreply@github.com>2020-01-29 20:57:29 -0500
commitf0a6062012c4e09553877c9feedb3fbc3d4625b9 (patch)
treed3e847c285718a4a8a422525cbc9d1e74220a3ec
parent161adfc51b750a7c8c62a898ea9948c2ad5b6cd9 (diff)
Partial implementation of node os polyfill based on currently available Deno functionality (#3821)
-rw-r--r--std/node/README.md2
-rw-r--r--std/node/module.ts2
-rw-r--r--std/node/module_test.ts6
-rw-r--r--std/node/os.ts221
-rw-r--r--std/node/os_test.ts275
5 files changed, 505 insertions, 1 deletions
diff --git a/std/node/README.md b/std/node/README.md
index d0d638d05..8d9f4ff40 100644
--- a/std/node/README.md
+++ b/std/node/README.md
@@ -23,7 +23,7 @@ deno standard library as it's a compatiblity module.
- [ ] https
- [x] module
- [ ] net
-- [ ] os
+- [x] os _partly_
- [x] path
- [ ] perf_hooks
- [x] process _partly_
diff --git a/std/node/module.ts b/std/node/module.ts
index 599ae2325..f27ef25f2 100644
--- a/std/node/module.ts
+++ b/std/node/module.ts
@@ -25,6 +25,7 @@ import * as nodeFS from "./fs.ts";
import * as nodeUtil from "./util.ts";
import * as nodePath from "./path.ts";
import * as nodeTimers from "./timers.ts";
+import * as nodeOs from "./os.ts";
import * as path from "../path/mod.ts";
import { assert } from "../testing/asserts.ts";
@@ -582,6 +583,7 @@ nativeModulePolyfill.set("fs", createNativeModule("fs", nodeFS));
nativeModulePolyfill.set("util", createNativeModule("util", nodeUtil));
nativeModulePolyfill.set("path", createNativeModule("path", nodePath));
nativeModulePolyfill.set("timers", createNativeModule("timers", nodeTimers));
+nativeModulePolyfill.set("os", createNativeModule("os", nodeOs));
function loadNativeModule(
_filename: string,
request: string
diff --git a/std/node/module_test.ts b/std/node/module_test.ts
index 91744d94d..a869179dd 100644
--- a/std/node/module_test.ts
+++ b/std/node/module_test.ts
@@ -42,3 +42,9 @@ test(function requireIndexJS() {
const { isIndex } = require_("./tests/cjs");
assert(isIndex);
});
+
+test(function requireNodeOs() {
+ const os = require_("os");
+ assert(os.arch);
+ assert(typeof os.arch() == "string");
+});
diff --git a/std/node/os.ts b/std/node/os.ts
new file mode 100644
index 000000000..ee64bfceb
--- /dev/null
+++ b/std/node/os.ts
@@ -0,0 +1,221 @@
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+import { notImplemented } from "./_utils.ts";
+
+const SEE_GITHUB_ISSUE = "See https://github.com/denoland/deno/issues/3802";
+
+interface CPUTimes {
+ /** The number of milliseconds the CPU has spent in user mode */
+ user: number;
+
+ /** The number of milliseconds the CPU has spent in nice mode */
+ nice: number;
+
+ /** The number of milliseconds the CPU has spent in sys mode */
+ sys: number;
+
+ /** The number of milliseconds the CPU has spent in idle mode */
+ idle: number;
+
+ /** The number of milliseconds the CPU has spent in irq mode */
+ irq: number;
+}
+
+interface CPUCoreInfo {
+ model: string;
+
+ /** in MHz */
+ speed: number;
+
+ times: CPUTimes;
+}
+
+interface NetworkAddress {
+ /** The assigned IPv4 or IPv6 address */
+ address: string;
+
+ /** The IPv4 or IPv6 network mask */
+ netmask: string;
+
+ family: "IPv4" | "IPv6";
+
+ /** The MAC address of the network interface */
+ mac: string;
+
+ /** true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false */
+ internal: boolean;
+
+ /** The numeric IPv6 scope ID (only specified when family is IPv6) */
+ scopeid?: number;
+
+ /** The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. */
+ cidr: string;
+}
+
+interface NetworkInterfaces {
+ [key: string]: NetworkAddress[];
+}
+
+export interface UserInfoOptions {
+ encoding: string;
+}
+
+interface UserInfo {
+ username: string;
+ uid: number;
+ gid: number;
+ shell: string;
+ homedir: string;
+}
+
+/** Returns the operating system CPU architecture for which the Deno binary was compiled */
+export function arch(): string {
+ return Deno.build.arch;
+}
+
+/** Not yet implemented */
+export function cpus(): CPUCoreInfo[] {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function endianness(): "BE" | "LE" {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function freemem(): number {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function getPriority(pid = 0): number {
+ validateInt32(pid, "pid");
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Returns the string path of the current user's home directory. */
+export function homedir(): string {
+ return Deno.dir("home");
+}
+
+/** Returns the host name of the operating system as a string. */
+export function hostname(): string {
+ return Deno.hostname();
+}
+
+/** Not yet implemented */
+export function loadavg(): number[] {
+ if (Deno.build.os == "win") {
+ return [0, 0, 0];
+ }
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function networkInterfaces(): NetworkInterfaces {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function platform(): string {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function release(): string {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function setPriority(pid: number, priority?: number): void {
+ /* The node API has the 'pid' as the first parameter and as optional.
+ This makes for a problematic implementation in Typescript. */
+ if (priority === undefined) {
+ priority = pid;
+ pid = 0;
+ }
+ validateInt32(pid, "pid");
+ validateInt32(priority, "priority", -20, 19);
+
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function tmpdir(): string {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function totalmem(): number {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function type(): string {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function uptime(): number {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+/** Not yet implemented */
+export function userInfo(
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+ options: UserInfoOptions = { encoding: "utf-8" }
+): UserInfo {
+ notImplemented(SEE_GITHUB_ISSUE);
+}
+
+export const constants = {
+ // UV_UDP_REUSEADDR: 4, //see https://nodejs.org/docs/latest-v12.x/api/os.html#os_libuv_constants
+ dlopen: {
+ // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_dlopen_constants
+ },
+ errno: {
+ // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_error_constants
+ },
+ signals: Deno.Signal,
+ priority: {
+ // see https://nodejs.org/docs/latest-v12.x/api/os.html#os_priority_constants
+ }
+};
+
+export const EOL = Deno.build.os == "win" ? "\r\n" : "\n";
+
+const validateInt32 = (
+ value: number,
+ name: string,
+ min = -2147483648,
+ max = 2147483647
+): void => {
+ // The defaults for min and max correspond to the limits of 32-bit integers.
+ if (!Number.isInteger(value)) {
+ throw new Error(`${name} must be 'an integer' but was ${value}`);
+ }
+ if (value < min || value > max) {
+ throw new Error(
+ `${name} must be >= ${min} && <= ${max}. Value was ${value}`
+ );
+ }
+};
diff --git a/std/node/os_test.ts b/std/node/os_test.ts
new file mode 100644
index 000000000..88f0113ec
--- /dev/null
+++ b/std/node/os_test.ts
@@ -0,0 +1,275 @@
+import { test } from "../testing/mod.ts";
+import {
+ assert,
+ assertThrows,
+ assertEquals,
+ AssertionError
+} from "../testing/asserts.ts";
+import * as os from "./os.ts";
+
+test({
+ name: "build architecture is a string",
+ fn() {
+ assertEquals(typeof os.arch(), "string");
+ }
+});
+
+test({
+ name: "home directory is a string",
+ fn() {
+ assertEquals(typeof os.homedir(), "string");
+ }
+});
+
+test({
+ name: "hostname is a string",
+ fn() {
+ assertEquals(typeof os.hostname(), "string");
+ }
+});
+
+test({
+ name: "getPriority(): PID must be a 32 bit integer",
+ fn() {
+ assertThrows(
+ () => {
+ os.getPriority(3.15);
+ },
+ Error,
+ "pid must be 'an integer'"
+ );
+ assertThrows(
+ () => {
+ os.getPriority(9999999999);
+ },
+ Error,
+ "must be >= -2147483648 && <= 2147483647"
+ );
+ }
+});
+
+test({
+ name: "setPriority(): PID must be a 32 bit integer",
+ fn() {
+ assertThrows(
+ () => {
+ os.setPriority(3.15, 0);
+ },
+ Error,
+ "pid must be 'an integer'"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(9999999999, 0);
+ },
+ Error,
+ "pid must be >= -2147483648 && <= 2147483647"
+ );
+ }
+});
+
+test({
+ name: "setPriority(): priority must be an integer between -20 and 19",
+ fn() {
+ assertThrows(
+ () => {
+ os.setPriority(0, 3.15);
+ },
+ Error,
+ "priority must be 'an integer'"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(0, -21);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(0, 20);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(0, 9999999999);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ }
+});
+
+test({
+ name:
+ "setPriority(): if only one argument specified, then this is the priority, NOT the pid",
+ fn() {
+ assertThrows(
+ () => {
+ os.setPriority(3.15);
+ },
+ Error,
+ "priority must be 'an integer'"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(-21);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(20);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(9999999999);
+ },
+ Error,
+ "priority must be >= -20 && <= 19"
+ );
+ }
+});
+
+test({
+ name: "Signals are as expected",
+ fn() {
+ // Test a few random signals for equality
+ assertEquals(os.constants.signals.SIGKILL, Deno.Signal.SIGKILL);
+ assertEquals(os.constants.signals.SIGCONT, Deno.Signal.SIGCONT);
+ assertEquals(os.constants.signals.SIGXFSZ, Deno.Signal.SIGXFSZ);
+ }
+});
+
+test({
+ name: "EOL is as expected",
+ fn() {
+ assert(os.EOL == "\r\n" || os.EOL == "\n");
+ }
+});
+
+// Method is currently implemented correctly for windows but not for any other os
+test({
+ name: "Load average is an array of 3 numbers",
+ fn() {
+ try {
+ const result = os.loadavg();
+ assert(result.length == 3);
+ assertEquals(typeof result[0], "number");
+ assertEquals(typeof result[1], "number");
+ assertEquals(typeof result[2], "number");
+ } catch (error) {
+ if (!(Object.getPrototypeOf(error) === Error.prototype)) {
+ const errMsg = `Unexpected error class: ${error.name}`;
+ throw new AssertionError(errMsg);
+ } else if (!error.message.includes("Not implemented")) {
+ throw new AssertionError(
+ "Expected this error to contain 'Not implemented'"
+ );
+ }
+ }
+ }
+});
+
+test({
+ name: "APIs not yet implemented",
+ fn() {
+ assertThrows(
+ () => {
+ os.cpus();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.endianness();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.freemem();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.getPriority();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.networkInterfaces();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.platform();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.release();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.setPriority(0);
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.tmpdir();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.totalmem();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.type();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.uptime();
+ },
+ Error,
+ "Not implemented"
+ );
+ assertThrows(
+ () => {
+ os.userInfo();
+ },
+ Error,
+ "Not implemented"
+ );
+ }
+});