请分享您的想法,参加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 使用 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} 做了本地复制,添加了一个名为 (launch) 的函数到 clojure.java.shell,忽略 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的文件中没有改变。

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

Ubuntu 16.04.6桌面Linux,截至2019年3月21日的最新更新
OpenJDK 1.8.0_191由openjdk-8-jre-headless和openjdk-8-jdk-headless Ubuntu软件包安装
截至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中考虑。
查看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之前使用ProcessBuilder$Redirect/DISCARD来重定向错误和输出。
...