1use crate::git;
2use crate::metadata::WipMetadata;
3use crate::ref_name;
4
5pub struct WipEntry {
6 pub name: String,
7 pub user: String,
8 pub sha: String,
9 pub metadata: WipMetadata,
10 pub timestamp: i64,
11}
12
13pub struct ListResult {
14 pub entries: Vec<WipEntry>,
15}
16
17pub fn run(all: bool, task_filter: Option<String>, remote: String) -> Result<ListResult, String> {
18 let user = ref_name::user()?;
19
20 let pattern = if all {
21 ref_name::list_pattern(None)
22 } else {
23 ref_name::list_pattern(Some(&user))
24 };
25
26 let output = git::git_stdout(&["ls-remote", &remote, &format!("{pattern}*")])?;
28
29 if output.is_empty() {
30 return Ok(ListResult {
31 entries: Vec::new(),
32 });
33 }
34
35 let mut entries: Vec<WipEntry> = Vec::new();
36
37 for line in output.lines() {
38 let parts: Vec<&str> = line.split_whitespace().collect();
39 if parts.len() < 2 {
40 continue;
41 }
42 let sha = parts[0].to_string();
43 let refpath = parts[1];
44
45 let suffix = refpath.strip_prefix("refs/wip/").unwrap_or(refpath);
47 let (entry_user, entry_name) = match suffix.split_once('/') {
48 Some((u, n)) => (u.to_string(), n.to_string()),
49 None => (suffix.to_string(), String::new()),
50 };
51
52 git::git(&["fetch", &remote, refpath])?;
54 let msg = git::git_stdout(&["log", "-1", "--format=%B", "FETCH_HEAD"])?;
55 let meta = WipMetadata::from_commit_message(&msg);
56
57 if let Some(ref task_id) = task_filter
59 && meta.task.as_deref() != Some(task_id)
60 {
61 continue;
62 }
63
64 let timestamp_str = git::git_stdout(&["log", "-1", "--format=%ct", "FETCH_HEAD"])?;
65 let timestamp: i64 = timestamp_str
66 .parse()
67 .map_err(|_| format!("bad timestamp for {refpath}"))?;
68
69 entries.push(WipEntry {
70 name: entry_name,
71 user: entry_user,
72 sha,
73 metadata: meta,
74 timestamp,
75 });
76 }
77
78 Ok(ListResult { entries })
79}
80
81pub fn relative_time(timestamp: i64) -> String {
82 let now = chrono::Utc::now().timestamp();
83 let age = now - timestamp;
84
85 if age < 60 {
86 "just now".into()
87 } else if age < 3600 {
88 format!("{}m ago", age / 60)
89 } else if age < 86400 {
90 format!("{}h ago", age / 3600)
91 } else if age < 86400 * 30 {
92 format!("{}d ago", age / 86400)
93 } else {
94 format!("{}w ago", age / (86400 * 7))
95 }
96}