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

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

+4
Clojure
关闭

请注意,这不仅对 clojure.java.shell 和由此暗示的 clojure.java.browse 重要,这还将使用 xdg-open 使用的平台上的 ClojureScript 浏览器 REPL 正确启动。目前,ClojureScript 快速入门说明在许多系统上是基本无效的。大多数 ClojureScript 的新用户不会享受调试这样的东西(或者也许我只是比大多数人固执一些 :))。

在某些平台上,clojure.java.browse/browse-url 调用 clojure.java.shell/sh 来执行一个 cmdline,使用 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的源代码文件都没有改变。

以下是我取得了良好测试结果的系统

Ubuntu 16.04.6桌面Linux,截至2019-03-21的最新更新
从openjdk-8-jre-headless和openjdk-8-jdk-headless Ubuntu软件包安装的OpenJDK 1.8.0_191
截至2019年3月21日的最新Clojure master版本,以及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 提示。&nhsp;我尝试多次按回车键,但不起作用。&nhsp;在这种情况下,关闭浏览器会返回错误,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和浏览器的具体实现是否有效)是在调用.start之前使用ProcessBuilder,并将错误的输出和标准的输出使用java.lang.ProcessBuilder$Redirect/DISCARD重定向。
...