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