请在 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 来执行 cmd 命令,使用 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),该函数忽略 I/O 流但返回退出代码,并将 browse-url 修改为使用 launch。好多了!浏览器和 REPL 都非常好,就像快速入门指南中承诺的那样。

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

由: Alex Miller 审筛

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

7 答案

0

评论者:jdjohnston

clj-2493.patch 已附加,于2019年3月21日

0

评论者:jafingerhut

我已在本地机器上Clojure 1.10.0的clj REPL中测试了(clojure.java.browse/browse-url "https://github.com"),并确实没有给出另一个REPL提示,除非关闭浏览器。我于2012年对此函数做出最后更改以添加xdg-open功能,我确信那时并没有这样做,但也许自那时起xdg-open的行为已改变。clojure.java.browse/browse-url和clojure.java.shell/sh包含的Clojure源文件自2012年以来没有变化。

以下是获得良好测试结果的我使用的系统

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 master加上clj-2493.patch

0
评论者:jafingerhut

这些更改会导致构建Clojure时测试失败,我认为是因为新的启动功能在文档字符串后面没有include {:added "1.11"}元数据。
0
评论者:jdjohnston

我认为不包括{:added "1.11"}是我份内之事,尤其是因为它还没有在此时期内包含。我应该添加元数据并构建一个新的补丁——要么是更新要么是替代品吗?
0

评论者:alexmiller

当我应用补丁时有两个尾部空白错误——当前补丁的第43行和第49行。如果您能将这些清理一下将很感激。

关于元数据,可以有以下两种选择之一:使用1.11版本添加元数据,并在描述中留下注释 OR 不添加元数据,但在描述中注明测试将失败直至添加该元数据。无论哪种方式,当到达需要进行发布的筛查时,我都可以对其进行修正。

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的处理队列中。
by
查看 1.11.0-alpha4 版本,

新的 clojure.java.shell/launch 可能看起来可以用于打开网页浏览器,但这仅因为 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 重定向到 java.lang.ProcessBuilder。
...