xtask/util/
mod.rs

1use std::{
2    env,
3    path::{Path, PathBuf},
4    process::{Command, Stdio},
5};
6
7use anyhow::{bail, Context, Result};
8use serde_derive::Deserialize;
9
10pub fn wrap<F, Ret>(op: F) -> Result<Ret>
11where
12    F: FnOnce() -> Result<Ret>,
13{
14    op()
15}
16
17pub fn repository_root() -> Result<PathBuf> {
18    let dir = env::var("CARGO_MANIFEST_DIR").context("failed to get manifest dir")?;
19    Ok(Path::new(&*dir).parent().unwrap().to_path_buf())
20}
21
22pub fn run_cmd(cmd: &mut Command) -> Result<()> {
23    eprintln!("Running {:?}", *cmd);
24    cmd.stdin(Stdio::inherit());
25
26    let status = cmd.status()?;
27
28    if !status.success() {
29        anyhow::bail!("Failed to run cargo command");
30    }
31
32    Ok(())
33}
34
35pub fn get_commit_for_core_version(version: &str, last: bool) -> Result<String> {
36    wrap(|| {
37        eprintln!("Getting commit for swc_core@v{version}");
38
39        // We need to get the list of commits and pull requests which changed the
40        // version of swc_core.
41        let git_rev_list = Command::new("git")
42            .current_dir(repository_root()?)
43            .arg("rev-list")
44            .arg("--branches")
45            .arg("main")
46            .arg("--")
47            .arg("Cargo.lock")
48            .stderr(Stdio::inherit())
49            .output()
50            .context("failed to spwan git rev-list")?;
51
52        let git_rev_list =
53            String::from_utf8(git_rev_list.stdout).context("git rev-list output is not utf8")?;
54
55        let git_grep_output = Command::new("git")
56            .current_dir(repository_root()?)
57            .arg("grep")
58            .arg(format!("version = \"{version}\""))
59            .args(git_rev_list.lines())
60            .arg("--")
61            .arg("Cargo.lock")
62            .stderr(Stdio::piped())
63            // .stdin(Stdio::from(git_rev_list.stdout.unwrap()))
64            .output()
65            .context("failed to execute git grep")?;
66
67        // git grep returns all commits with the version string with the format, so we
68        // need to check if it's the version of swc_core
69        let output =
70            String::from_utf8(git_grep_output.stdout).context("git grep output is not utf8")?;
71
72        let line_count = output.lines().count();
73
74        if line_count == 0 {
75            bail!("swc_core@v{} is not found in the repository", version);
76        }
77
78        let iter: Box<dyn Iterator<Item = &str>> = if last {
79            Box::new(output.lines().rev())
80        } else {
81            Box::new(output.lines())
82        };
83
84        for line in iter {
85            let commit = line.split(':').next().unwrap().to_string();
86            let commit_version = get_version_of_swc_core_of_commit(&commit)?;
87            if Some(version) == commit_version.as_deref() {
88                eprintln!("\tFound commit for swc_core@v{version}: https://github.com/swc-project/swc/commits/{commit}");
89
90                return Ok(commit);
91            }
92        }
93
94        bail!("swc_core@v{} is not found in the repository", version);
95    })
96    .with_context(|| format!("failed to get the commit for swc_core@v{version}"))
97}
98
99/// Read the version of swc_core from `Cargo.lock`
100pub fn get_version_of_swc_core_of_commit(commit: &str) -> Result<Option<String>> {
101    wrap(|| {
102        let output = Command::new("git")
103            .current_dir(repository_root()?)
104            .arg("show")
105            .arg(format!("{commit}:Cargo.lock"))
106            .stderr(Stdio::inherit())
107            .output()
108            .context("failed to spwan git show")?;
109
110        let output_toml =
111            String::from_utf8(output.stdout).context("git show output is not utf8")?;
112
113        let content =
114            toml::from_str::<CargoLockfile>(&output_toml).context("failed to parse Cargo.lock")?;
115
116        for pkg in content.package {
117            if pkg.name == "swc_core" {
118                return Ok(Some(pkg.version));
119            }
120        }
121
122        Ok(None)
123    })
124    .with_context(|| format!("failed to get the version of swc_core of {commit}"))
125}
126
127#[derive(Debug, Deserialize)]
128struct CargoLockfile {
129    package: Vec<LockfilePkg>,
130}
131
132#[derive(Debug, Deserialize)]
133struct LockfilePkg {
134    name: String,
135    version: String,
136}