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 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 .output()
65 .context("failed to execute git grep")?;
66
67 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
99pub 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}