如何在Clojure中的URL路由中嵌入当前git sha

如何在Clojure中的URL路由中嵌入当前git sha,git,clojure,leiningen,compojure,http-kit,Git,Clojure,Leiningen,Compojure,Http Kit,通常,我有一个用于所有服务器端应用程序的URL GET路由,该路由返回当前git哈希,这是检查给定实例上运行的代码的确切版本的一种简单方法。在解释语言(例如Python、Node.js)中,这很简单,只需检查在子流程中运行shell命令的输出。但我正在通过使用leinuberjar打包Clojure应用程序,将其分发给实例 因此,我可以使用clojure.java.shell以编程方式获取当前git sha,如下所示: (defn get-git-sha [_req] (trim ((s

通常,我有一个用于所有服务器端应用程序的URL GET路由,该路由返回当前git哈希,这是检查给定实例上运行的代码的确切版本的一种简单方法。在解释语言(例如Python、Node.js)中,这很简单,只需检查在子流程中运行shell命令的输出。但我正在通过使用
leinuberjar
打包Clojure应用程序,将其分发给实例

因此,我可以使用
clojure.java.shell
以编程方式获取当前git sha,如下所示:

(defn get-git-sha
  [_req]
  (trim ((sh "/bin/sh" "-c" "git rev-parse HEAD") :out)))

(defroutes server-routes
  (GET "/revision" [] get-git-sha))

(defn serve-http
  [port]
  (http-server/run-server server-routes {:port port}))
但我需要一种方法,在uberjar过程中(而不是在运行时,当jar不再在repo中时)将其嵌入到代码中,从我使用compojure定义的URL路由返回,并通过http工具包提供服务。如何在编译时或构建时运行该函数并将其转储到常量或其他我可以从路由返回的内容

虽然我希望有这样一个解决方案,但正如前面所述,这里的最终目的是能够通过HTTP查询正在运行的实例,并找到在生产中给定实例上运行的代码的确切版本(强烈偏好git sha,而不是semver编号)

我意识到我可以通过将repo克隆到所有实例并通过ansible在本地构建jar,并在已知目录中查找sha来解决这个问题,但这似乎是黑客行为,与在构建时对jar文件进行“签名”相比,更容易出错

编辑: My project.clj如下所示:

(defproject gps-server "0.1.0-SNAPSHOT"
  :description "Receives GPS data over TCP"
  :url "http://someurl"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [...]
  :main ^:skip-aot gps-server.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot [gps-server.core]}})

我不认为我做了什么特别的事情来实现这一点,所以检查一下你的罐子里面有没有

 META-INF/maven/your-project/name/pom.properties
其中,
您的项目/名称
来自用于构建uberjar的project.clj

(defproject your-project/name "4.2.6"
  ...
在pom.properties中,我有:

#Leiningen
#Tue Oct 01 13:20:45 CEST 2019
version=4.2.6
revision=4625a070a34ddc3c563b71025fa5dd907b406331
groupId=your-project
artifactId=name
其中修订版来自git

我有一个
/version
端点,它使用此函数返回此信息

defn- get-version []
  (let [rsrc (io/resource "META-INF/maven/your-project/name/pom.properties")
        rdr (io/reader rsrc)
        props (java.util.Properties.)]
    (.load props rdr)
    (into {} (for [[k v] props] [k v]))))

我不认为我做了什么特别的事情来实现这一点,所以检查一下你的罐子里面有没有

 META-INF/maven/your-project/name/pom.properties
其中,
您的项目/名称
来自用于构建uberjar的project.clj

(defproject your-project/name "4.2.6"
  ...
在pom.properties中,我有:

#Leiningen
#Tue Oct 01 13:20:45 CEST 2019
version=4.2.6
revision=4625a070a34ddc3c563b71025fa5dd907b406331
groupId=your-project
artifactId=name
其中修订版来自git

我有一个
/version
端点,它使用此函数返回此信息

defn- get-version []
  (let [rsrc (io/resource "META-INF/maven/your-project/name/pom.properties")
        rdr (io/reader rsrc)
        props (java.util.Properties.)]
    (.load props rdr)
    (into {} (for [[k v] props] [k v]))))

我在一个项目中遇到了这个问题,他们使用了一些疯狂的未记录的黑客,通过lein将git-SHA转换成一个全局变量。不要那样做

相反,要意识到构建过程不止一个步骤。在最简单的情况下,两个步骤是:

  • 捕获git SHA并将其保存到文件中(通常类似于
    /resources/build info.txt
    (或者更好的是,
    build info.edn
  • 调用
    leinuberjar
    将所有内容打包到部署工件中
  • 因此,不要只是从命令行调用
    lein uberjar
    ,而是创建一个包含上述步骤的两行部署脚本。可能简单到:

    #!/bin/bash
    
    # Capture current git SHA (or:  git log -n1 --format=format:"%H")
    git rev-parse HEAD  > ./resources/build-info.txt   
    
    # Create uberjar
    lein clean ; lein uberjar
    
    # Copy output someplace, etc...
    

    以上内容可以简单地保存到
    /scripts/deploy.bash
    或类似的文件中(当然,这些文件会被签入
    git
    !)。

    我在一个项目中遇到了这个问题,他们使用了一些疯狂的未记录的黑客手段,通过lein将git SHA放入一个全局变量。不要这样做

    相反,要意识到构建过程有不止一个步骤。在最简单的情况下,这两个步骤是:

  • 捕获git SHA并将其保存到文件中(通常类似于
    /resources/build info.txt
    (或者更好的是,
    build info.edn
  • 调用
    leinuberjar
    将所有内容打包到部署工件中
  • 因此,不要只是从命令行调用
    lein uberjar
    ,而是创建一个包含上述步骤的两行部署脚本。可能简单到:

    #!/bin/bash
    
    # Capture current git SHA (or:  git log -n1 --format=format:"%H")
    git rev-parse HEAD  > ./resources/build-info.txt   
    
    # Create uberjar
    lein clean ; lein uberjar
    
    # Copy output someplace, etc...
    

    上面的内容可以简单地保存到
    /scripts/deploy.bash
    或类似的文件中(当然,这些文件可以签入
    git
    !)。

    我添加了
    clojure.java.io
    ,复制了你的函数,并用我的项目名称替换了“你的项目”(我还用我的project.clj更新了这个问题),构建了jar,并使用
    java-jar
    运行它,但是
    rsrc
    似乎为零:
    线程“main”中的异常java.lang.IllegalArgumentException:无法作为阅读器打开。
    。有趣的是:你的SO句柄也是我的首字母缩写。事实上,我想你让我知道我现在正在进行实验……成功了,谢谢。现在我觉得没有阅读常见问题解答很傻:/I添加了
    clojure.java.io
    ,复制了你的函数并替换了“你的项目”使用我的项目名称(我还用project.clj更新了这个问题),构建了jar,并使用
    java-jar
    运行它,但是
    rsrc
    似乎为零:
    线程“main”中的异常java.lang.IllegalArgumentException:无法作为阅读器打开。
    。有趣的是:你的SO句柄也是我的首字母缩写。事实上,我想你让我知道我现在正在进行实验……这就完成了,谢谢。现在我觉得很傻,因为我没有阅读编译时运行的FAQ:/宏,它们的目的是生成实际编译的代码。有吗您尝试在宏中执行git get sha,AOT编译对该宏的调用(即,最终编译的代码将sha作为文本字符串包含),并将生成的类文件包含在uberjar中?@BipedPhill我没有,但你当然是对的。如果我离开leiningen,这似乎是自动完成的,我可能会。宏在编译时运行,其目的是生成实际编译的代码。你试过在宏AOT comp中执行git get sha吗我调用该宏(即,最终编译的代码将SHA作为文本字符串包含在内),并将生成的类文件包含在uberjar?@BipedPhill中,我没有这样做,但你当然是对的。如果我离开leiningen,这似乎是自动完成的,我可能会这样做。这肯定会起作用。但是