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)函数,忽略 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的行为可能已经改变。自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 master加上clj-2493.patch

0
_评论由:jafingerhut_ 提出

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

我认为我不应该包含{:added "1.11"},特别是鉴于它到现在还未被添加。我应该添加元数据并构建一个新的补丁——要么是更新要么是替代品吗?
0

评论由: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提示符。  我多次尝试按回车键,但没有效果。  在我的情况下,关闭浏览器会返回错误,并且clojure会退出。

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

在我克隆了clojure仓库、应用这个补丁并在修补后的clojure上进行构建/运行后,我终于能够打开浏览器窗口,在REPL上显示文本,并且出现REPL提示符。  最后胜利了! :-D

总之,感谢这个补丁,它对我也很有效。
感谢反馈 - 这正在排队等待考虑纳入Clojure 1.11。
查看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和浏览器特定情况下的工作方式),是在调用.start之前使用ProcessBuilder,并将.java.lang.ProcessBuilder$Redirect/DISCARD应用到`.redirectError`和`.redirectOutput`。
...