cargo_uv/packages/
package.rs1use crate::{
2 Action, Bumpable, CargoFile, PackageName, ReadToml, Result, VersionLocation, current_span,
3 manifest::version_location::VersionType,
4};
5use miette::bail;
6use semver::{BuildMetadata, Prerelease, Version};
7use std::path::{Path, PathBuf};
8use tracing::instrument;
9
10#[derive(Debug, Eq, Clone)]
11pub struct Package<CargoFileState> {
12 name: PackageName,
13 version_type: VersionType,
14 version: Version,
15 manifest_path: PathBuf,
16 cargo_file: CargoFile<CargoFileState>,
17}
18
19impl<CargoFileState: PartialEq> PartialEq for Package<CargoFileState> {
20 fn eq(&self, other: &Self) -> bool {
21 self.name == other.name && self.manifest_path == other.manifest_path
22 }
23}
24
25impl<CargoFileState: std::hash::Hash> std::hash::Hash for Package<CargoFileState> {
26 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
27 self.name.hash(state);
28 }
32}
33
34impl<CargoFileState> Package<CargoFileState> {
35 pub fn name(&self) -> &PackageName {
36 &self.name
37 }
38
39 pub fn version(&self) -> &Version {
40 &self.version
41 }
42
43 pub fn version_mut(&mut self) -> &mut Version {
44 &mut self.version
45 }
46
47 pub fn manifest_path(&self) -> &PathBuf {
48 &self.manifest_path
49 }
50
51 pub fn cargo_file(&self) -> &CargoFile<CargoFileState> {
52 &self.cargo_file
53 }
54
55 pub fn cargo_file_mut(&mut self) -> &mut CargoFile<CargoFileState> {
56 &mut self.cargo_file
57 }
58
59 pub fn version_type(&self) -> VersionType {
60 self.version_type
61 }
62}
63
64impl From<cargo_metadata::Package> for Package<ReadToml> {
65 fn from(meta_package: cargo_metadata::Package) -> Package<ReadToml> {
66 let manifest_path: PathBuf = meta_package.manifest_path.into();
67 let cargo_file = CargoFile::new(manifest_path.clone()).expect("from cargo manifest");
68 Self {
69 name: meta_package.name.to_string().into(),
70 version: meta_package.version,
71 version_type: Package::set_version_type(&cargo_file)
72 .expect("Cargo manifest run with no error"),
73 cargo_file: cargo_file,
74 manifest_path,
75 }
76 }
77}
78impl Package<ReadToml> {
79 #[instrument(skip_all)]
80 pub fn set_version_type(cargo_file: &CargoFile<ReadToml>) -> Result<VersionType> {
81 let package = match VersionLocation::Package.get_version(cargo_file) {
82 Ok(_v) => Ok(VersionType::Package),
83 Err(e) => match e.kind() {
84 crate::VersionLocationErrorKind::SetByWorkspace => Ok(VersionType::SetByWorkspace),
85 _ => Err(e),
86 },
87 };
88
89 if let Ok(ver_type) = package {
90 return Ok(ver_type);
91 }
92
93 let ws = match VersionLocation::WorkspacePackage.get_version(cargo_file) {
94 Ok(_v) => VersionType::WorkspacePackage,
95 Err(e) => {
96 tracing::error!("Invalid version: {}", cargo_file.path().display());
97 return Err(miette::miette!(e)
98 .wrap_err(package.map_err(|e| e.to_string()).err().unwrap_or_default()));
99 }
100 };
101 Ok(ws)
102 }
103
104 pub fn set_version(&mut self, version: Version) -> Result<Version> {
105 self.version = version.clone();
106 let cargo_file = self.cargo_file_mut();
107 let res = cargo_file.set_version(version);
108 res?;
109 Ok(self.version().clone())
110 }
111
112 #[instrument(skip(self, pre, build), fields(from, to))]
113 pub fn bump_version(
114 &mut self,
115 action: Action,
116 pre: Option<Prerelease>,
117 build: Option<BuildMetadata>,
118 force: bool,
119 ) -> Result<Version> {
120 let span = current_span!();
121 span.record("from", self.version.to_string());
122 let name = self.name().clone();
123 tracing::trace!("Package {}: Bump Version", name);
124
125 let version = self.version_mut();
126 let new_version = version.bump(action, pre, build, force)?;
127 self.cargo_file_mut().set_version(new_version)?;
128 span.record("to", self.version().to_string());
129 println!("{name}: {}", self.version());
130 Ok(self.version().clone())
131 }
132
133 pub fn write_cargo_file(&mut self) -> Result<Version> {
134 if self.version_type() == VersionType::SetByWorkspace {
135 let msg = format!(
136 "Can't modify SetByWorkspace version from a bool: {}",
137 self.manifest_path.as_os_str().display()
138 );
139 tracing::error!("{}", msg);
140 bail!("{msg}")
141 }
142 self.cargo_file_mut().write_cargo_file()?;
143 match self.version_type() {
144 VersionType::Package => Ok(VersionLocation::Package.get_version(self.cargo_file())?),
145 VersionType::SetByWorkspace => unreachable!(),
146
147 VersionType::WorkspacePackage => {
148 Ok(VersionLocation::WorkspacePackage.get_version(self.cargo_file())?)
149 }
150 }
151 }
152
153 #[track_caller]
154 pub fn workspace_package(manifest_path: &Path) -> Result<Package<ReadToml>> {
155 let cargo_file = CargoFile::new(manifest_path)?;
156 let version = VersionLocation::WorkspacePackage.get_version(&cargo_file)?;
157
158 Ok(Package {
159 name: PackageName("workspace.package".into()),
160 version_type: VersionType::WorkspacePackage,
161 version,
162 manifest_path: manifest_path.into(),
163 cargo_file,
164 })
165 }
166}