Skip to content

Commit b67d890

Browse files
committed
Fix extension match
1 parent db0569c commit b67d890

File tree

1 file changed

+131
-21
lines changed

1 file changed

+131
-21
lines changed

crates/zeta_cli/src/example.rs

Lines changed: 131 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
use std::{
2+
borrow::Cow,
3+
env,
24
fmt::{self, Display},
5+
fs,
36
io::Write,
47
mem,
58
os::unix::ffi::OsStrExt,
69
path::{Path, PathBuf},
710
};
811

9-
use anyhow::Result;
12+
use anyhow::{Context as _, Result};
1013
use clap::ValueEnum;
14+
use gpui::http_client::Url;
1115
use pulldown_cmark::CowStr;
1216
use serde::{Deserialize, Serialize};
1317

@@ -18,23 +22,24 @@ const EXPECTED_EXCERPTS_HEADING: &str = "Expected Excerpts";
1822
const REPOSITORY_URL_FIELD: &str = "repository_url";
1923
const REVISION_FIELD: &str = "revision";
2024

25+
#[derive(Debug)]
2126
pub struct NamedExample {
22-
name: String,
23-
example: Example,
27+
pub name: String,
28+
pub example: Example,
2429
}
2530

26-
#[derive(Serialize, Deserialize)]
31+
#[derive(Debug, Serialize, Deserialize)]
2732
pub struct Example {
28-
repository_url: String,
29-
commit: String,
30-
cursor_path: PathBuf,
31-
cursor_position: String,
32-
edit_history: Vec<String>,
33-
expected_patch: String,
34-
expected_excerpts: Vec<ExpectedExcerpt>,
33+
pub repository_url: String,
34+
pub revision: String,
35+
pub cursor_path: PathBuf,
36+
pub cursor_position: String,
37+
pub edit_history: Vec<String>,
38+
pub expected_patch: String,
39+
pub expected_excerpts: Vec<ExpectedExcerpt>,
3540
}
3641

37-
#[derive(Serialize, Deserialize)]
42+
#[derive(Debug, Serialize, Deserialize)]
3843
pub struct ExpectedExcerpt {
3944
path: PathBuf,
4045
text: String,
@@ -53,16 +58,16 @@ impl NamedExample {
5358
let content = std::fs::read_to_string(path)?;
5459
let ext = path.extension();
5560

56-
match ext.map(|s| s.as_bytes()) {
57-
Some(b"json") => Ok(Self {
61+
match ext.and_then(|s| s.to_str()) {
62+
Some("json") => Ok(Self {
5863
name: path.file_name().unwrap_or_default().display().to_string(),
5964
example: serde_json::from_str(&content)?,
6065
}),
61-
Some(b"toml") => Ok(Self {
66+
Some("toml") => Ok(Self {
6267
name: path.file_name().unwrap_or_default().display().to_string(),
6368
example: toml::from_str(&content)?,
6469
}),
65-
Some(b"md") => Self::parse_md(&content),
70+
Some("md") => Self::parse_md(&content),
6671
Some(_) => {
6772
anyhow::bail!("Unrecognized example extension: {}", ext.unwrap().display());
6873
}
@@ -83,7 +88,7 @@ impl NamedExample {
8388
name: String::new(),
8489
example: Example {
8590
repository_url: String::new(),
86-
commit: String::new(),
91+
revision: String::new(),
8792
cursor_path: PathBuf::new(),
8893
cursor_position: String::new(),
8994
edit_history: Vec::new(),
@@ -106,12 +111,12 @@ impl NamedExample {
106111
// in h1 section
107112
&& let Some((field, value)) = line.split_once('=')
108113
{
109-
match field {
114+
match field.trim() {
110115
REPOSITORY_URL_FIELD => {
111-
named.example.repository_url = value.to_string();
116+
named.example.repository_url = value.trim().to_string();
112117
}
113118
REVISION_FIELD => {
114-
named.example.commit = value.to_string();
119+
named.example.revision = value.trim().to_string();
115120
}
116121
_ => {
117122
eprintln!("Warning: Unrecognized field `{field}`");
@@ -188,6 +193,111 @@ impl NamedExample {
188193
ExampleFormat::Md => Ok(write!(out, "{}", self)?),
189194
}
190195
}
196+
197+
pub async fn setup_worktree(&self) -> Result<PathBuf> {
198+
let worktrees_dir = env::current_dir()?.join("target").join("zeta-worktrees");
199+
let repos_dir = env::current_dir()?.join("target").join("zeta-repos");
200+
fs::create_dir_all(&repos_dir)?;
201+
fs::create_dir_all(&worktrees_dir)?;
202+
203+
let (repo_owner, repo_name) = self.repo_name()?;
204+
205+
let repo_dir = repos_dir.join(repo_owner.as_ref()).join(repo_name.as_ref());
206+
dbg!(&repo_dir);
207+
if !repo_dir.is_dir() {
208+
fs::create_dir_all(&repo_dir)?;
209+
run_git(&repo_dir, &["init"]).await?;
210+
run_git(
211+
&repo_dir,
212+
&["remote", "add", "origin", &self.example.repository_url],
213+
)
214+
.await?;
215+
}
216+
217+
run_git(
218+
&repo_dir,
219+
&["fetch", "--depth", "1", "origin", &self.example.revision],
220+
)
221+
.await?;
222+
223+
let worktree_path = worktrees_dir.join(&self.name);
224+
225+
dbg!(&worktree_path);
226+
227+
if worktree_path.is_dir() {
228+
run_git(&worktree_path, &["clean", "--force", "-d"]).await?;
229+
run_git(&worktree_path, &["reset", "--hard", "HEAD"]).await?;
230+
run_git(&worktree_path, &["checkout", &self.example.revision]).await?;
231+
} else {
232+
let worktree_path_string = worktree_path.to_string_lossy();
233+
run_git(
234+
&repo_dir,
235+
&[
236+
"worktree",
237+
"add",
238+
"-f",
239+
&worktree_path_string,
240+
&self.example.revision,
241+
],
242+
)
243+
.await?;
244+
}
245+
246+
Ok(worktree_path)
247+
}
248+
249+
fn repo_name(&self) -> Result<(Cow<str>, Cow<str>)> {
250+
// [email protected]:owner/repo.git
251+
if self.example.repository_url.contains('@') {
252+
let (owner, repo) = self
253+
.example
254+
.repository_url
255+
.split_once(':')
256+
.context("expected : in git url")?
257+
.1
258+
.split_once('/')
259+
.context("expected / in git url")?;
260+
Ok((
261+
Cow::Borrowed(owner),
262+
Cow::Borrowed(repo.trim_end_matches(".git")),
263+
))
264+
// http://github.com/owner/repo.git
265+
} else {
266+
let url = Url::parse(&self.example.repository_url)?;
267+
let mut segments = url.path_segments().context("empty http url")?;
268+
let owner = segments
269+
.next()
270+
.context("expected owner path segment")?
271+
.to_string();
272+
let repo = segments
273+
.next()
274+
.context("expected repo path segment")?
275+
.trim_end_matches(".git")
276+
.to_string();
277+
assert!(segments.next().is_none());
278+
279+
Ok((owner.into(), repo.into()))
280+
}
281+
}
282+
}
283+
284+
async fn run_git(repo_path: &Path, args: &[&str]) -> Result<String> {
285+
let output = smol::process::Command::new("git")
286+
.current_dir(repo_path)
287+
.args(args)
288+
.output()
289+
.await?;
290+
291+
anyhow::ensure!(
292+
output.status.success(),
293+
"`git {}` within `{}` failed with status: {}\nstderr:\n{}\nstdout:\n{}",
294+
args.join(" "),
295+
repo_path.display(),
296+
output.status,
297+
String::from_utf8_lossy(&output.stderr),
298+
String::from_utf8_lossy(&output.stdout),
299+
);
300+
Ok(String::from_utf8(output.stdout)?.trim().to_string())
191301
}
192302

193303
impl Display for NamedExample {
@@ -198,7 +308,7 @@ impl Display for NamedExample {
198308
"{REPOSITORY_URL_FIELD} = {}\n",
199309
self.example.repository_url
200310
)?;
201-
write!(f, "{REVISION_FIELD} = {}\n\n", self.example.commit)?;
311+
write!(f, "{REVISION_FIELD} = {}\n\n", self.example.revision)?;
202312

203313
write!(
204314
f,

0 commit comments

Comments
 (0)