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提示。我最后一次修改了这个函数以添加xdg-open功能是在2012年,我相当确信那时并没有这样做,但从那时起xdg-open的行为可能已经发生了变化。Clojure源文件包含clojure.java.browse/browse-url和clojure.java.shell/sh的文件自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时的测试失败,我认为这是因为新的启动函数在文档字符串之后没有 {: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

总的来说,感谢补丁,它对我 också worked.
感谢您的反馈 - 它正在排队等待在Clojure 1.11中考虑。
查看1.11.0-alpha4版本,

新的clojure.java.shell/launch看起来可以用来打开';

根据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")
       
一般来说,解决这个问题的方法之一是使用ProcessBuilder,在调用.start之前,使用.redirectError和.redirectOutput将java.lang.ProcessBuilder$Redirect/DISCARD重定向到java.lang.Process
...