1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 use std::env::current_dir;
16 use std::fs::{create_dir_all, remove_dir_all};
17 use std::path::{Path, PathBuf};
18 use std::process::Command;
19 use std::str::from_utf8;
20
21 use anyhow::{anyhow, Context, Result};
22 use semver::Version;
23 use thiserror::Error;
24
25 pub use self::crate_type::{diff_android_bp, Crate, Migratable};
26 mod crate_type;
27
28 pub use self::crate_collection::CrateCollection;
29 mod crate_collection;
30
31 pub use self::reports::{ReportEngine, SizeReport, Table};
32 mod reports;
33
34 pub use self::migration::migrate;
35 mod migration;
36
37 pub use self::pseudo_crate::PseudoCrate;
38 mod pseudo_crate;
39
40 pub use self::version_match::{CompatibleVersionPair, VersionMatch, VersionPair};
41 mod version_match;
42
43 pub use self::android_bp::{build_cargo_embargo, generate_android_bps, maybe_build_cargo_embargo};
44 mod android_bp;
45
46 pub use self::name_and_version::{
47 IsUpgradableTo, NameAndVersion, NameAndVersionRef, NamedAndVersioned,
48 };
49 mod name_and_version;
50
51 pub use self::repo_path::RepoPath;
52 mod repo_path;
53
54 #[cfg(test)]
55 pub use self::name_and_version_map::try_name_version_map_from_iter;
56 pub use self::name_and_version_map::{
57 crates_with_multiple_versions, crates_with_single_version, most_recent_version,
58 NameAndVersionMap,
59 };
60 mod name_and_version_map;
61
62 #[derive(Error, Debug)]
63 pub enum CrateError {
64 #[error("Virtual crate: {0}")]
65 VirtualCrate(PathBuf),
66
67 #[error("Duplicate crate version: {0} {1}")]
68 DuplicateCrateVersion(String, Version),
69 }
70
default_repo_root() -> Result<PathBuf>71 pub fn default_repo_root() -> Result<PathBuf> {
72 let cwd = current_dir().context("Could not get current working directory")?;
73 for cur in cwd.ancestors() {
74 for e in cur.read_dir()? {
75 if e?.file_name() == ".repo" {
76 return Ok(cur.to_path_buf());
77 }
78 }
79 }
80 Err(anyhow!(".repo directory not found in any ancestor of {}", cwd.display()))
81 }
82
default_output_dir(filename: &str) -> PathBuf83 pub fn default_output_dir(filename: &str) -> PathBuf {
84 PathBuf::from("/google/data/rw/users")
85 .join(&whoami::username()[..2])
86 .join(whoami::username())
87 .join("www")
88 .join(filename)
89 }
90
ensure_exists_and_empty(dir: &impl AsRef<Path>) -> Result<()>91 pub fn ensure_exists_and_empty(dir: &impl AsRef<Path>) -> Result<()> {
92 let dir = dir.as_ref();
93 if dir.exists() {
94 remove_dir_all(&dir).context(format!("Failed to remove {}", dir.display()))?;
95 }
96 create_dir_all(&dir).context(format!("Failed to create {}", dir.display()))
97 }
98
99 // The copy_dir crate doesn't handle symlinks.
copy_dir(src: &impl AsRef<Path>, dst: &impl AsRef<Path>) -> Result<()>100 pub fn copy_dir(src: &impl AsRef<Path>, dst: &impl AsRef<Path>) -> Result<()> {
101 let output =
102 Command::new("cp").arg("--archive").arg(src.as_ref()).arg(dst.as_ref()).output()?;
103 if !output.status.success() {
104 return Err(anyhow!(
105 "Failed to copy {} to {}\nstdout:\n{}\nstderr:\n{}",
106 src.as_ref().display(),
107 dst.as_ref().display(),
108 from_utf8(&output.stdout)?,
109 from_utf8(&output.stderr)?
110 ));
111 }
112 Ok(())
113 }
114