6 个版本

0.1.5 2021年9月30日
0.1.4 2021年9月29日

#1831数据结构

每月 26 次下载

MIT 许可协议

19KB
284

dependency-graph

Dependency-graph 是一个最小的库,公开了一个 DependencyGraph 结构和一个单个的 Node 特性。

要使用此库,只需为希望解析依赖的对象实现 Node 特性的两个函数。

示例

在这个例子中,我们将使用 dependency-graph 来解析我们 Package 结构之间的依赖关系。我们将使用自定义的 Dependency 类型,因为我们想在我们的依赖中包含语义版本约束。这样我们就能说,我们的包 mypackage 依赖于某个包 some-library 的版本 2.0。

我们的 PackageDependency 结构使用 semver::Versionsemver::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