请在 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)的函数,它忽略 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提示。 我尝试多次按Enter键,但这没有起作用。 在我这里,关闭浏览器会返回错误,并使clojure退出。

我还尝试更改默认浏览器(尝试了Firefox和Chromium),结果都是一样的。

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

总之,感谢补丁,它在我这里也有效。
感谢反馈 - 这个问题将在Clojure 1.11的候选列表中进行考虑。
by
查看 1.11.0-alpha4版:

新的 clojure.java.shell/launch 可能看起来可以用于 xdg-open 打开网页浏览器,这仅仅是因为 xdg-open 和打包的网页浏览器通常不会在其标准流中写入多少或没有写入。

根据 Java 文档(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。
...