【问题标题】:Automatically convert scala import sentences into library dependencies自动将scala导入语句转换为库依赖
【发布时间】:2020-07-30 23:33:05
【问题描述】:

我是 Scala 的新手 :)

如果我理解正确,您必须先将所需的库包含在 build.sbt 文件的 Library Dependencies 中,然后才能将所需的库import 到 scala脚本。

但是,我必须反其道而行之。我必须编写一个 Python 脚本来将 自动 Scala 的导入语句转换为库依赖语句,以便将它们插入到@987654323 @文件。

例如

发件人:

import org.apache.spark.sql.SparkSession
import json._

到:

libraryDependencies += "org.apache.spark" %% "spark-sql" % sparkVersion % "provided"
libraryDependencies += "com.mediamath" %%% "scala-json" % "1.0"


我知道库依赖的语法如下:

libraryDependencies += groupID % artifactID % revision % configuration

我们应该在maven central repository 中查找groupIDartifactIDrevision

但是,此手动查找不允许我对转​​换进行自动编程。有什么我错过的吗?我可以用来完成此任务的其他语法?还有其他方法吗?

【问题讨论】:

  • 一般来说是不可能的,充其量你可以有启发式。您可以拥有多个在同一命名空间下提供定义的库。即使不是,您也可以为来自同一组织/项目的所有库使用公共前缀。包名称不必与组织/包名称对齐(例如,有很多 cats 库,它们共享 cats 命名空间,但在 Maven 上它们位于 org.typelevel 组织中)。在很多情况下它可以工作,但这不能完全自动化。
  • 如果这些 Scala 脚本工作,它们应该已经构建或以某种方式运行 - 我会在那里搜索依赖项名称。
  • @MateuszKubuszok 非常感谢您的 cmets! “搜索依赖项名称”是指,例如,
    如果导入语句中有sql,我会自动输入"org.apache.spark" %% "spark-sql" % sparkVersion。如果导入语句中有json,我会自动输入"com.mediamath" %%% "scala-json" % "1.0"?非常感谢您!
  • 我的意思是 scala 脚本并不存在于真空中。如果这是菊石,它将具有import $ivy.organization::library:version`,笔记本通常也具有类似的功能。 Scastie 有一个用于运行脚本的库列表。所以通常依赖关系已经在某个地方定义了。
  • 几乎不可能构建一个完全自动化的工具来“猜测”基于导入的库,因为为此必须废弃所有存在的库,检查每个 JAR 的内容,构建索引的包 -> 库名映射,然后解决多个库具有相同包的问题,​​因为没有规则禁止这样做。由于工作量大,甚至没有现有工具尝试将其自动化。充其量您可以维护映射列表并在新案例到来时手动扩展它。询问作者他们使用了什么应该更简单。

标签: regex scala sbt dependency-management


【解决方案1】:

所以在某些语言中,导入必须以某种方式完成。这种方式看起来像“导入所有东西,然后开始做事”

在 Scala 中,可以在源代码中的任何位置导入项目。这会使事情复杂化。例如,在 Spark 代码中,您间接向 Spark 应用程序主控器询问它提供了哪些符号,这些符号存储在运行时传回给您的变量中,然后您导入这些符号。

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark SQL basic example")
  .config("spark.some.config.option", "some-value")
  .getOrCreate()

// For implicit conversions like converting RDDs to DataFrames
import spark.implicits._

(注意示例中的最后一行导入了已创建 spark 变量的 implicits 字段中的所有内容。

最后,一个 Maven 工件的版本不止一个。不能安全地引用特定 Maven 工件的任何版本,因为并非所有项目都尝试在所有版本号之间提供向后兼容性(即使他们尝试这样做,兼容性错误仍然存​​在)。

https://mvnrepository.com/artifact/org.apache.spark/spark-core 列出了大约 30 个不同版本的 spark-core,其他 spark 库使用的核心例程。如果您选择与现有 spark 服务不同的版本,您的应用程序将无法正常运行,因为 spark 通常不兼容主要版本号,而是主要和次要版本号(2.3 编译代码将无法与 2.4 环境一起使用)

此外,Scala 代码在其编译阶段使用了大量的优化例程。这些优化例程意味着通常不能在 Scala 2.12 运行时环境中使用 Scala 2.11 类。所有类必须完全匹配它们的运行时环境。要发现运行时环境,不检查导入语句,而是检查发生编译的机器中的 Scala 运行时设置,并确保它们与运行输出的目标环境相同。这就是为什么对于许多库,您会看到多次构建相同的版本号,例如

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.12</artifactId>
    <version>2.4.5</version>
</dependency>

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.11</artifactId>
    <version>2.4.5</version>
</dependency>

(上面的示例是虚构的,但说明了为 2.11 和 2.12 编译的相同版本的库)

最后,导入不是对 Maven 工件名称的引用。相反,它们是 JAR 文件中的元素(这是一种 Maven 工件)。因此,您将遇到一个额外的问题,即发现哪个 JAR 文件包含导入的项目,而无需事先知道您正在使用哪个 JAR 文件。

简而言之,您正试图用例程来扭转在这种环境中编写程序的自然过程,因为您正试图修复一个没有记录他们打算使用什么的程序员。但是,您的例行程序必须

  1. 获取导入,其中一些可能是在运行时构建的,然后列出。
  2. 获取该项目列表,并以某种方式找到所有可以提供这些项目的 JAR 文件。
  3. 对于不同工件提供的每个导入项目,确定(无需输入)开发人员打算使用哪个工件。
  4. 对于项目,发现所需的 Scala 版本(由部署环境确定),并查找该工件的 Scala 匹配版本。
  5. 有关该工件的版本列表,请查找可与 Spark 基础架构的其余部分一起使用的版本。

第 3 步和第 5 步需要解决类似于“我把车停好,这是钥匙,去找它”的解决方案,其中汽车可能在世界任何地方,而您无法从该人那里获得比“我停好车”更多的信息我的车”

第 4 步需要发现一些无法确定的内容,因为您可能不知道所有部署位置,但您可以针对每个版本的 Scala 进行编译。

这篇文章的主要观点是你在做傻事。 sbt 文件是开发人员所需/需要的文档。开发人员懒得为他们正在使用的东西编写一行配置是一场噩梦。忘记写那一行的开发人员是一种烦恼,可以通过要求开发人员做他们忘记做的事情来轻松解决。

这忽略了构建 SBT 的 Maven 核心概念。因为假设您实际上成功地完成了第 1 步到第 5 步,并不是所有的库版本组合都可以一起工作,因为 Maven 和 SBT 都可以自动解决依赖关系。这意味着如果您导入 org:item:1.1 和 org:item2:1.0,org:item2:1.0 可能需要 org:item:1.3,并且您将在完全解决的 Maven 依赖项中出现版本号冲突。在这样的情况下,Java 1.8 项目中只使用了其中一个库,如果使用的库与某些代码不兼容,人们(称为构建大师)通常需要调查构建配置并确定哪些工件的版本需要更新以修复不兼容性。

如果你的项目可以写出来,那就太棒了。祝你好运!

【讨论】:

    猜你喜欢
    • 2019-08-21
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 2021-07-28
    • 2020-08-04
    • 1970-01-01
    相关资源
    最近更新 更多