BSP 构建服务协议

更多开源技术,请关注以上公众号
BSP (Build Server Protocol )协议是构建服务协议的简称,处于 IDE 和构建工具之间用于统一构建功能的通信的协议,它是 LSP (Language Server Protocol )协议的补充,在了解 BSP 之前我们先认识一下 LSP。
LSP 简介
LSP 是唯一基于 JSON 的语言服务器数据交换协定,并采用 CC 及 MIT 授权。该协定主要用来在编辑器及语言服务器之间进行通信,让开发人员在各种编辑器或整合开发环境中获取智能的程序语言工具,例如代码符号搜寻、语法分析、自动完成代码、移至定义、描绘轮廓或重构等。
现阶段 LSP 已支持 C++、 PowerShell、JSON、CSS/LESS/SASS、Xtext、GOLang、Ruby、Crane PHP、Haxe、Java 和 RAML。集成开发环境方面,Visual Studio Code 和 Eclipse Che 已经实现了 LSP 协议。1
BSP 协议
如上所述,LSP 语言服务协议统一了各类语言服务器提供的服务功能,让 IDE 能够轻松应对新的语言加入和语言服务器的功能变化。LSP 针对的是 IDE 中编辑器的代码编辑功能,而 BSP 则是针对 IDE 的构建功能,它的目标是减少开发人员在 IDE 和构建工具之间进行集成所需的工作量。
BSP 目前还不是一个标准协议,正处于完善过程中。在未使用 BSP的情况下,每个 IDE 都必须为其支持的构建工具实现自定义集成,以便提取源目录或编译器选项等信息,比如 qtcreator。但是随着新的编程语言的出现,新的编译工具也不断涌现,通过在每个 IDE 中去单独集成这些编译工具势必会造成开发人员投入大量精力,且各个 IDE 之间容易产生大量的重复工作。
BSP 协议就是用来解决上述问题,类似于 LSP 协议它定义了一系列通用的构建功能协议标准,这些标准可以让开发者专注于面向协议编程,不用花太多时间在整合编译工具上面。
BSP 的实现方式
BSP 作为 LSP 的补充,在使用时可以和 LSP 一起使用,也可以单独使用,下图展示了其使用方式:

BSP 协议分为两个部分,一个是基础协议,一个是构建扩展协议,其中基础协议就是 LSP,可参考官方介绍2,其中包含了基础JSON的结构和格式。
扩展格式
Build Target
Build Target 包含了工程的一些元数据,其 JSON 格式如下:
export interface BuildTarget {
/** The target’s unique identifier */
id: BuildTargetIdentifier;
/** A human readable name for this target.
* May be presented in the user interface.
* Should be unique if possible.
* The id.uri is used if None. */
displayName?: String;
/** The directory where this target belongs to. Multiple build targets are allowed to map
* to the same base directory, and a build target is not required to have a base directory.
* A base directory does not determine the sources of a target, see buildTarget/sources. */
baseDirectory?: Uri;
/** Free-form string tags to categorize or label this build target.
* For example, can be used by the client to:
* - customize how the target should be translated into the client's project model.
* - group together different but related targets in the user interface.
* - display icons or colors in the user interface.
* Pre-defined tags are listed in `BuildTargetTag` but clients and servers
* are free to define new tags for custom purposes.
*/
tags: String[];
/** The capabilities of this build target. */
capabilities: BuildTargetCapabilities;
/** The set of languages that this target contains.
* The ID string for each language is defined in the LSP. */
languageIds: String[];
/** The direct upstream build target dependencies of this build target */
dependencies: BuildTargetIdentifier[];
/** Kind of data to expect in the `data` field. If this field is not set, the kind of data is not specified. */
dataKind?: String;
/** Language-specific metadata about this target.
* See ScalaBuildTarget as an example. */
data?: any;
}
export namespace BuildTargetDataKind {
/** The `data` field contains a `ScalaBuildTarget` object. */
export const Scala = "scala";
/** The `data` field contains a `SbtBuildTarget` object. */
export const Sbt = "sbt";
}
export namespace BuildTargetTag {
/** Target contains re-usable functionality for downstream targets. May have any
* combination of capabilities. */
export const Library = "library";
/** Target contains source code for producing any kind of application, may have
* but does not require the `canRun` capability. */
export const Application = "application";
/** Target contains source code for testing purposes, may have but does not
* require the `canTest` capability. */
export const Test = "test";
/** Target contains source code for integration testing purposes, may have
* but does not require the `canTest` capability.
* The difference between "test" and "integration-test" is that
* integration tests traditionally run slower compared to normal tests
* and require more computing resources to execute.
*/
export const IntegrationTest = "integration-test";
/** Target contains source code to measure performance of a program, may have
* but does not require the `canRun` build target capability.
*/
export const Benchmark = "benchmark";
/** Target should be ignored by IDEs. */
export const NoIDE = "no-ide";
/** Actions on the target such as build and test should only be invoked manually
* and explicitly. For example, triggering a build on all targets in the workspace
* should by default not include this target.
*
* The original motivation to add the "manual" tag comes from a similar functionality
* that exists in Bazel, where targets with this tag have to be specified explicitly
* on the command line.
*/
export const Manual = "manual";
}
export interface BuildTargetCapabilities {
/** This target can be compiled by the BSP server. */
canCompile: Boolean;
/** This target can be tested by the BSP server. */
canTest: Boolean;
/** This target can be run by the BSP server. */
canRun: Boolean;
/** This target can be debugged by the BSP server. */
canDebug: Boolean;
}
Build Target Identifier
export interface BuildTargetIdentifier {
/** The target’s Uri */
uri: Uri;
}
目标的唯一标识符可以使用任何与 URI 兼容的编码,只要它在工作区中是唯一的。 客户端不应从 URI 结构中推断出元数据,例如路径或查询参数,而是使用 BuildTarget。
Task Id
export interface TaskId {
/** A unique identifier */
id: String;
/** The parent task ids, if any. A non-empty parents field means
* this task is a sub-task of every parent task id. The child-parent
* relationship of tasks makes it possible to render tasks in
* a tree-like user interface or inspect what caused a certain task
* execution. */
parents?: String[];
}
任务 ID 允许客户端唯一标识一个 BSP 任务并与另一个任务 ID 建立客户端-父级关系。
Status Code
export namespace StatusCode {
/** Execution was successful. */
export const Ok = 1;
/** Execution failed. */
export const Error = 2;
/** Execution was cancelled. */
export const Cancelled = 3;
}
包含任务里面的一些通知信息或者一些完成信号。
URI
/** A resource identifier that is a valid URI according
* to rfc3986: * https://tools.ietf.org/html/rfc3986 */
type Uri = String;
资源标识符,这里用标准的 URI 标准。
参考:
https://build-server-protocol.github.io/docs/specification
8685

被折叠的 条评论
为什么被折叠?



