6 个版本
0.1.5 | 2021年9月30日 |
---|---|
0.1.4 | 2021年9月29日 |
#1831 在 数据结构
每月 26 次下载
19KB
284 行
dependency-graph
Dependency-graph 是一个最小的库,公开了一个 DependencyGraph
结构和一个单个的 Node
特性。
要使用此库,只需为希望解析依赖的对象实现 Node
特性的两个函数。
示例
在这个例子中,我们将使用 dependency-graph
来解析我们 Package
结构之间的依赖关系。我们将使用自定义的 Dependency
类型,因为我们想在我们的依赖中包含语义版本约束。这样我们就能说,我们的包 mypackage
依赖于某个包 some-library
的版本 2.0。
我们的 Package
和 Dependency
结构使用 semver::Version
和 semver::VersionReq
类型来定义包的版本(如 1.2.3-beta.4)以及依赖需求,如 >=2.0
。更多关于 semver 包的信息。
首先,我们定义 Package
结构
struct Package {
name: &'static str,
version: Version,
dependencies: Vec<Dependency>,
}
其中 Dependency
是
struct Dependency {
name: &'static str,
version: VersionReq,
}
为我们的 Package
实现 Node
特性相当简单
impl Node for Package {
type DependencyType = Dependency;
fn dependencies(&self) -> &[Self::DependencyType] {
&self.dependencies[..]
}
fn matches(&self, dependency: &Self::DependencyType) -> bool {
// Check that name is an exact match, and that the dependency
// requirements are fulfilled by our own version
self.name == dependency.name && dependency.version.matches(&self.version)
}
}
让我们定义一些包和依赖
let packages = vec![
Package {
name: "base",
version: semver::Version {
major: 1,
minor: 2,
patch: 3,
pre: Prerelease::new("").unwrap(),
build: BuildMetadata::EMPTY,
},
dependencies: vec![],
},
Package {
name: "derived",
version: semver::Version {
major: 3,
minor: 2,
patch: 0,
pre: Prerelease::new("").unwrap(),
build: BuildMetadata::EMPTY,
},
dependencies: vec![Dependency {
name: "base",
version: "=1.2.3".parse().unwrap(),
}],
},
Package {
name: "second_order",
version: semver::Version {
major: 11,
minor: 2,
patch: 4,
pre: Prerelease::new("").unwrap(),
build: BuildMetadata::EMPTY,
},
dependencies: vec![Dependency {
name: "derived",
version: ">=3.0.0".parse().unwrap(),
}],
},
]
现在我们已经定义了所有包以及它们之间的依赖解析方式(通过实现 Node
),我们可以从它构建一个 DependencyGraph
并遍历它,知道依赖关系将始终在依赖它们的包之前被访问。
在我们的例子中,我们预计 base
包将首先被访问(因为 derived
依赖于它),然后是 derived
,因为 second_order
又依赖于它,因此不能在 derived
被解析之前解析。最后是 second_order
,因为现在它的所有依赖关系都已解析。
let graph = DependencyGraph::from(&packages[..]);
for package in graph {
match package {
// Print out the package name so we can verify the order in the console
Step::Resolved(package) => println!("Building {}!", package.name),
// Since we know that all our Packages only have internal references to each other,
// we can safely ignore any Unresolved steps in the graph.
//
// If for example `second_order` required some unknown package `external_package`,
// iterating over our graph would yield that as a Step::Unresolved *before*
// the `second_order` package.
Step::Unresolved(_) => unreachable!()
}
}
如果我们运行上述代码,我们可以验证它们确实按照正确的顺序构建
Building base!
Building derived!
Building second_order!
依赖项
~2MB
~29K SLoC