Repository: denoland/deno_core
Pull request #638 (2024-03-05 22:48:26)

Add `op_is_terminal` to deno_core

CLAassistant: [![CLA assistant check](https://cla-assistant.io/pull/badge/not_signed)](https://cla-assistant.io/denoland/deno_core?pullRequest=638) <br/>Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla-assistant.io/denoland/deno_core?pullRequest=638) before we can accept your contribution.<br/><sub>You have signed the CLA already but the status is still pending? Let us [recheck](https://cla-assistant.io/check/denoland/deno_core?pullRequest=638) it.</sub>
codecov-commenter: ## [Codecov](https://app.codecov.io/gh/denoland/deno_core/pull/638?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=denoland) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 80.56%. Comparing base [(`c27a29b`)](https://app.codecov.io/gh/denoland/deno_core/commit/c27a29b6ff799540eca4db6f49ce7913cd0bf1c2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=denoland) to head [(`fd220a9`)](https://app.codecov.io/gh/denoland/deno_core/pull/638?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=denoland).


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #638      +/-   ##
==========================================
+ Coverage   80.34%   80.56%   +0.22%     
==========================================
  Files          97       97              
  Lines       23774    23806      +32     
==========================================
+ Hits        19101    19180      +79     
+ Misses       4673     4626      -47     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/denoland/deno_core/pull/638?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=denoland).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=denoland).


Patch:
diff --git a/core/01_core.js b/core/01_core.js
index b039e2b..fd23a6d 100644
--- a/core/01_core.js
+++ b/core/01_core.js
@@ -427,6 +427,7 @@
     op_read_sync: readSync,
     op_write_sync: writeSync,
     op_shutdown: shutdown,
+    op_is_terminal: isTerminal,
   } = ensureFastOps(true);
 
   const callSiteRetBuf = new Uint32Array(2);
@@ -640,6 +641,7 @@
     readSync,
     writeSync,
     shutdown,
+    isTerminal,
     print: (msg, isErr) => op_print(msg, isErr),
     setLeakTracingEnabled: (enabled) => {
       __setLeakTracingEnabled(enabled);
diff --git a/core/lib.deno_core.d.ts b/core/lib.deno_core.d.ts
index 4d18de3..7a76c7b 100644
--- a/core/lib.deno_core.d.ts
+++ b/core/lib.deno_core.d.ts
@@ -96,6 +96,11 @@ declare namespace Deno {
      */
     function print(message: string, is_err?: boolean): void;
 
+    /**
+     * Returns whether the given (file-like) resource is a TTY.
+     */
+    function isTerminal(rid: number): boolean;
+
     /**
      * Shutdown a resource
      */
diff --git a/core/ops_builtin.rs b/core/ops_builtin.rs
index f496e97..9c22baf 100644
--- a/core/ops_builtin.rs
+++ b/core/ops_builtin.rs
@@ -58,6 +58,7 @@ builtin_ops! {
   op_panic,
   op_cancel_handle,
   op_encode_binary_string,
+  op_is_terminal,
   ops_builtin_types::op_is_any_array_buffer,
   ops_builtin_types::op_is_arguments_object,
   ops_builtin_types::op_is_array_buffer,
@@ -395,3 +396,12 @@ pub fn op_cancel_handle(state: &mut OpState) -> u32 {
 fn op_encode_binary_string(#[buffer] s: &[u8]) -> ByteString {
   ByteString::from(s)
 }
+
+#[op2(fast)]
+fn op_is_terminal(
+  state: &mut OpState,
+  #[smi] rid: ResourceId,
+) -> Result<bool, Error> {
+  let handle = state.resource_table.get_handle(rid)?;
+  Ok(handle.is_terminal())
+}


Test patch:
diff --git a/testing/checkin/runner/mod.rs b/testing/checkin/runner/mod.rs
index 580957a..fe9df59 100644
--- a/testing/checkin/runner/mod.rs
+++ b/testing/checkin/runner/mod.rs
@@ -47,6 +47,7 @@ deno_core::extension!(
     ops::op_stats_dump,
     ops::op_stats_delete,
     ops_io::op_pipe_create,
+    ops_io::op_file_open,
     ops_async::op_async_yield,
     ops_async::op_async_barrier_create,
     ops_async::op_async_barrier_await,
diff --git a/testing/checkin/runner/ops_io.rs b/testing/checkin/runner/ops_io.rs
index f02c05e..6bd53a1 100644
--- a/testing/checkin/runner/ops_io.rs
+++ b/testing/checkin/runner/ops_io.rs
@@ -1,13 +1,17 @@
 // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+use anyhow::Error;
 use deno_core::op2;
 use deno_core::AsyncRefCell;
 use deno_core::BufView;
 use deno_core::OpState;
 use deno_core::RcRef;
 use deno_core::Resource;
+use deno_core::ResourceHandle;
 use deno_core::ResourceId;
 use deno_core::WriteOutcome;
 use futures::FutureExt;
+use std::cell::RefCell;
+use std::rc::Rc;
 use tokio::io::AsyncReadExt;
 use tokio::io::AsyncWriteExt;
 use tokio::io::DuplexStream;
@@ -65,3 +69,39 @@ pub fn op_pipe_create(op_state: &mut OpState) -> (ResourceId, ResourceId) {
   });
   (rid1, rid2)
 }
+
+struct FileResource {
+  handle: deno_core::ResourceHandle,
+}
+
+impl FileResource {
+  fn new(file: tokio::fs::File) -> Self {
+    let handle = ResourceHandle::from_fd_like(&file);
+    Self { handle }
+  }
+}
+
+impl Resource for FileResource {
+  fn backing_handle(self: Rc<Self>) -> Option<ResourceHandle> {
+    Some(self.handle)
+  }
+}
+
+#[op2(async)]
+#[serde]
+pub async fn op_file_open(
+  #[string] path: String,
+  op_state: Rc<RefCell<OpState>>,
+) -> Result<ResourceId, Error> {
+  let tokio_file = tokio::fs::OpenOptions::new()
+    .read(true)
+    .write(false)
+    .create(false)
+    .open(&path)
+    .await?;
+  let rid = op_state
+    .borrow_mut()
+    .resource_table
+    .add(FileResource::new(tokio_file));
+  Ok(rid)
+}
diff --git a/testing/unit/resource_test.ts b/testing/unit/resource_test.ts
index 2050555..39872cf 100644
--- a/testing/unit/resource_test.ts
+++ b/testing/unit/resource_test.ts
@@ -1,7 +1,7 @@
 // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
 import { assert, assertArrayEquals, assertEquals, test } from "checkin:testing";
 
-const { op_pipe_create } = Deno.core.ensureFastOps();
+const { op_pipe_create, op_file_open } = Deno.core.ensureFastOps();
 
 test(async function testPipe() {
   const [p1, p2] = op_pipe_create();
@@ -47,3 +47,8 @@ test(function opsSyncBadResource() {
     assert(e instanceof Deno.core.BadResource);
   }
 });
+
+test(async function testFileIsNotTerminal() {
+  const file = await op_file_open("./README.md");
+  assert(!Deno.core.isTerminal(file));
+});