请分享您的观点至 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 提示。我于 2012 年对此函数进行了最后更改,以添加 xdg-open 功能,我相当确定当时没有这样做,但也许自那时起 xdg-open 的行为已经改变。包含 clojure.java.browse/browse-url 和 clojure.java.shell/sh 文件的 Clojure 源代码自 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上,我也有相同的问题,使用1.8.0_222版本的openjdk,通过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])

    ;; 使用'bash'执行不挂起
    (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重定向到。我不清楚这会与xdg-open和浏览器具体如何工作。
...