2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!有关如何工作的更多信息,请参阅关于页面。

+4
Clojure
已关闭

请注意,这不仅对 clojure.java.shell 很重要,而且对 clojure.java.browse 也同样重要,而且这还将使 ClojureScript 浏览器 REPL 能够在 xdg-open 使用的平台上正确启动。目前,ClojureScript 快速入门指南在许多系统中实际上是损坏的。大多数 ClojureScript 的新用户不会喜欢调试这样的东西(或者我只是比大多数人更固执:))。

在某些平台上,clojure.java.browse/browse-url 调用 clojure.java.shell/sh 来执行使用 xdg-open 启动网页浏览器的命令行。作为良好的 **Nix 工具,xdg-open 将其打开的文件描述符传递给新的进程。(我不知道这在 xdg-open 的某个地方是否有文档说明,但这很容易证明。)

clojure.java.shell/sh 总是读取执行的进程的 STDOUT 和 STDERR 流。当目的是收集子进程的输出时,这当然是一件好事。然而,在用 xdg-open 启动浏览器时,直到浏览器退出,流才关闭。对于 clojure.java.browse/browse-url 的调用者来说,这个函数看起来“永不”返回。

我们需要的是 clojure.java.shell/sh 的一个变体(或 sh 的选项)来忽略输出流,并且仅返回退出代码。我们使用子进程完全是为了其副作用。这与使用 doseq 替代 map 部分类似,但我们确实需要子进程的退出代码。

为了使 ClojureScript 浏览器 REPL 工作正常,我创建了 clojure.java.{browse,shell} 的本地副本,向 clojure.java.shell 中添加了一个名为 (launch) 的函数,它忽略了输入输出流但返回退出代码,并将 browse-url 修改为使用 launch。好多了!浏览器和 REPL 都按快速入门指南中的承诺工作。

个人笔记:虽然我刚开始尝试 ClojureScript,但我已经用 Clojure 使用了好几年。

由: Alex Miller

以以下备注关闭:发布在 1.11.0-alpha4

7 个答案

0
by

评论者:jdjohnston

clj-2493.patch 已附上,附上时间为 2019 年 3 月 21 日

0
by

评论者:jafingerhut

我在 Clojure 1.10.0 的 clj REPL 上测试了 (clojure.java.browse/browse-url "https://github.com"),并且它确实不会在浏览器关闭之前实现另一个 REPL 提示。我在 2012 年更新了这个函数以添加 xdg-open 功能,我相当确信当时它没有这样做,但也许自那时起 xdg-open 的行为已发生变化。从 2012 年起,包含 clojure.java.browse/browse-url 和 clojure.java.shell/sh 的文件的 Clojure 来源没有变化。

以下是我有良好测试结果的系统

Ubuntu 16.04.6 桌面 Linux,截至 2019 年 3 月 21 日有最新更新
从 openjdk-8-jre-headless 和 openjdk-8-jdk-headless Ubuntu 软件包安装了 OpenJDK 1.8.0_191
截至 2019 年 3 月 21 日的最新 Clojure 主版本以及 clj-2493.patch

0
by
_评论者:jafingerhut_

这些更改会导致在构建 Clojure 时测试失败,我认为这是由于新的启动函数在文档字符串之后没有 {:added "1.11"} 元数据。
0
by
_评论者:jdjohnston_

我认为包括 {:added "1.11"} 不是一个合适的行为,特别是鉴于它 _尚未_ 在这个时候添加。我应该添加元数据并构建一个新的补丁——或者是更新或者是替换吗?
0
by

评论者:alexmiller

我在应用补丁时发现有两个尾随空格错误——最新补丁的第 43 行和第 49 行。如果您能将这些清理一下就最好了。

关于元数据,可以选择使用1.11版本添加元数据,并在描述中注明,或者不添加元数据,并在描述中注明测试将失败直到添加元数据。无论是哪种情况,当到达进行发布审核的阶段时,我会解决它。

0

评论者:jdjohnston

2019年3月21日的第二个补丁 - 替换第一个补丁
- 移除了尾随空格
- 为了便于接受而预添加了元数据 :)

0
参考: [https://clojure.atlassian.net/browse/CLJ-2493 (报告者:jdjohnston)]
我在debian stretch上也有完全相同的问题,openjdk版本1.8.0_222,通过linux-install-1.10.1.469.sh脚本安装clojure。

在遵循clojurescript的“快速入门”指南(https://script.clojure.org/guides/quick-start)时,clj命令会启动浏览器显示“Hello World!”文本,但是永远不会显示REPL提示。我尝试多次按下Enter键,但不起作用。在我的情况下,关闭浏览器会返回错误,并退出clojure。

我尝试更改默认浏览器(尝试了Firefox和Chromium)但结果相同。

在克隆了clojure存储库,应用了这个补丁,并使用修改后的clojure进行构建/运行后,我终于能够成功打开浏览器窗口,显示REPL上的文本,以及REPL提示。最终胜利!:-D

以上都是为了说,谢谢补丁,它也对我来说是有效的。
感谢您的反馈 - 该反馈已在Clojure 1.11的生产清单中。
查阅1.11.0-alpha4版本,

新的clojure.java.shell/launch在尝试使用xdg-open打开网页浏览器时似乎可以正常工作,但这仅仅是因为xdg-open和封装的浏览器通常很少或将输出写入其标准流。

根据Javadoc(《https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/lang/Process.html》)所述,“由于一些本地平台只提供有限的标准输入输出流缓冲区大小,未能及时写入输入流或读取程序输出流可能会导致进程阻塞,甚至死锁。”

例如,

    (require '[clojure.java.shell :as shell])

    ;; 使用'sh'执行 - 不挂起
    (time (:exit (shell/sh "bash" "-c" "sleep 1; z=0; while [ $z -lt 25000 ] ; do echo $z; z=$((z+1)) ; done")))

    ;; 使用'launch'执行 - 挂起
    (shell/launch "bash" "-c" "sleep 1; z=0; while [ $z -lt 25000 ] ; do echo $z; z=$((z+1)) ; done")
       
一种避免问题的方法(我不清楚它对特定地使用xdg-open和浏览器的兼容性如何)是使用ProcessBuilder,并在调用.start之前使用.redirectError和.redirectOutput将java.lang.ProcessBuilder$Redirect/DISCARD重新定向。
...