Clojure 2024调查问卷中分享您的想法!

欢迎!请查看关于页面以了解更多关于其工作方式的信息。

+4
Clojure
已关闭

请注意,这不仅对clojure.java.shell(以及隐含的clojure.java.browse)很重要,这还将使ClojureScript浏览器的REPL正确地在xdg-open使用的平台上启动。目前,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的“快速入门”指南时,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和浏览器怎样工作)是在调用.start之前使用ProcessBuilder,并将.stderr和.stdout重定向到java.lang.ProcessBuilder$Redirect/DISCARD
...