hakari/cli_ops/
manage_deps.rs1use crate::{
7 cli_ops::{WorkspaceOp, WorkspaceOps},
8 hakari::DepFormatVersion,
9 HakariBuilder, WorkspaceHackLineStyle,
10};
11use guppy::{
12 graph::{DependencyDirection, PackageLink, PackageMetadata, PackageSet},
13 VersionReq,
14};
15
16impl<'g> HakariBuilder<'g> {
17 pub fn manage_dep_ops(&self, workspace_set: &PackageSet<'g>) -> Option<WorkspaceOps<'g, '_>> {
26 let graph = self.graph();
27 let hakari_package = self.hakari_package()?;
28
29 let (add_to, remove_from) =
30 workspace_set.filter_partition(DependencyDirection::Reverse, |package| {
31 let link_opt = package
32 .link_to(hakari_package.id())
33 .expect("valid package ID");
34 let should_be_included = !self.is_excluded(package.id()).expect("valid package ID");
35 match (link_opt, should_be_included) {
36 (None, true) => Some(true),
37 (Some(_), false) => Some(false),
38 (Some(link), true) => match self.dep_format_version {
39 DepFormatVersion::V1 => None,
40 DepFormatVersion::V2 | DepFormatVersion::V3 | DepFormatVersion::V4 => {
41 needs_update_v2(hakari_package, link, self.workspace_hack_line_style)
42 .then_some(true)
43 }
44 },
45 (None, false) => None,
46 }
47 });
48
49 let mut ops = Vec::with_capacity(2);
50 if !add_to.is_empty() {
51 ops.push(WorkspaceOp::AddDependency {
52 name: hakari_package.name(),
53 crate_path: hakari_package
54 .source()
55 .workspace_path()
56 .expect("hakari package is in workspace"),
57 version: hakari_package.version(),
58 dep_format: self.dep_format_version,
59 line_style: self.workspace_hack_line_style,
60 add_to,
61 });
62 }
63 if !remove_from.is_empty() {
64 ops.push(WorkspaceOp::RemoveDependency {
65 name: hakari_package.name(),
66 remove_from,
67 });
68 }
69 Some(WorkspaceOps::new(graph, ops))
70 }
71
72 pub fn add_dep_ops(
79 &self,
80 workspace_set: &PackageSet<'g>,
81 force: bool,
82 ) -> Option<WorkspaceOps<'g, '_>> {
83 let graph = self.graph();
84 let hakari_package = self.hakari_package()?;
85
86 let add_to = if force {
87 workspace_set.clone()
88 } else {
89 workspace_set.filter(DependencyDirection::Reverse, |package| {
90 let link_opt = package
91 .link_to(hakari_package.id())
92 .expect("valid package ID");
93 match link_opt {
94 Some(link) => {
95 needs_update_v2(hakari_package, link, self.workspace_hack_line_style)
96 }
97 None => true,
98 }
99 })
100 };
101
102 let op = if !add_to.is_empty() {
103 Some(WorkspaceOp::AddDependency {
104 name: hakari_package.name(),
105 version: hakari_package.version(),
106 crate_path: hakari_package
107 .source()
108 .workspace_path()
109 .expect("hakari package is in workspace"),
110 dep_format: self.dep_format_version,
111 line_style: self.workspace_hack_line_style,
112 add_to,
113 })
114 } else {
115 None
116 };
117 Some(WorkspaceOps::new(graph, op))
118 }
119
120 pub fn remove_dep_ops(
127 &self,
128 workspace_set: &PackageSet<'g>,
129 force: bool,
130 ) -> Option<WorkspaceOps<'g, '_>> {
131 let graph = self.graph();
132 let hakari_package = self.hakari_package()?;
133
134 let remove_from = if force {
135 workspace_set.clone()
136 } else {
137 workspace_set.filter(DependencyDirection::Reverse, |package| {
138 graph
139 .directly_depends_on(package.id(), hakari_package.id())
140 .expect("valid package ID")
141 })
142 };
143
144 let op = if !remove_from.is_empty() {
145 Some(WorkspaceOp::RemoveDependency {
146 name: hakari_package.name(),
147 remove_from,
148 })
149 } else {
150 None
151 };
152 Some(WorkspaceOps::new(graph, op))
153 }
154}
155
156#[allow(clippy::if_same_then_else, clippy::needless_bool)]
157fn needs_update_v2(
158 hakari_package: &PackageMetadata<'_>,
159 link: PackageLink<'_>,
160 line_style: WorkspaceHackLineStyle,
161) -> bool {
162 if !link.version_req().matches(hakari_package.version()) {
163 true
165 } else if link.version_req() == &VersionReq::STAR {
166 match line_style {
168 WorkspaceHackLineStyle::Full | WorkspaceHackLineStyle::VersionOnly => true,
169 WorkspaceHackLineStyle::WorkspaceDotted => false,
170 }
171 } else {
172 false
173 }
174}