feat: support generic linux-only releases without architecture · airscripts/gitclaw@062e531 · GitHub
Skip to content

Commit 062e531

Browse files
committed
feat: support generic linux-only releases without architecture
1 parent 46aa152 commit 062e531

7 files changed

Lines changed: 196 additions & 376 deletions

File tree

‎.github/workflows/build.yml‎

Lines changed: 0 additions & 24 deletions

‎.github/workflows/test.yml‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,3 @@ jobs:
1515
- uses: actions/checkout@v4
1616
- run: apt-get update && apt-get install -y pkg-config libssl-dev
1717
- run: cargo test
18-
19-
macos:
20-
name: macOS
21-
runs-on: macos-latest
22-
steps:
23-
- uses: actions/checkout@v4
24-
- uses: dtolnay/rust-toolchain@1.75
25-
- run: cargo test
26-
27-
windows:
28-
name: Windows
29-
runs-on: windows-latest
30-
steps:
31-
- uses: actions/checkout@v4
32-
- uses: dtolnay/rust-toolchain@1.75
33-
- run: cargo test

‎src/github.rs‎

Lines changed: 134 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,18 @@ pub struct Asset {
5959
pub size: u64,
6060
}
6161

62-
/// Platform specification for asset matching
62+
/// Platform specification for asset matching (Linux only)
6363
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6464
pub enum Platform {
6565
LinuxX86_64,
6666
LinuxAarch64,
67-
DarwinX86_64,
68-
DarwinAarch64,
69-
WindowsX86_64,
70-
WindowsAarch64,
7167
}
7268

7369
impl std::fmt::Display for Platform {
7470
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7571
match self {
7672
Platform::LinuxX86_64 => write!(f, "linux-x86_64"),
7773
Platform::LinuxAarch64 => write!(f, "linux-aarch64"),
78-
Platform::DarwinX86_64 => write!(f, "darwin-x86_64"),
79-
Platform::DarwinAarch64 => write!(f, "darwin-aarch64"),
80-
Platform::WindowsX86_64 => write!(f, "windows-x86_64"),
81-
Platform::WindowsAarch64 => write!(f, "windows-aarch64"),
8274
}
8375
}
8476
}
@@ -100,51 +92,21 @@ impl Platform {
10092
"aarch64-unknown-linux-gnu",
10193
"aarch64-unknown-linux-musl",
10294
],
103-
Platform::DarwinX86_64 => &[
104-
"darwin-x86_64",
105-
"darwin-amd64",
106-
"darwin-x64",
107-
"macos-x86_64",
108-
"osx-x86_64",
109-
"x86_64-apple-darwin",
110-
],
111-
Platform::DarwinAarch64 => &[
112-
"darwin-aarch64",
113-
"darwin-arm64",
114-
"macos-aarch64",
115-
"macos-arm64",
116-
"osx-arm64",
117-
"aarch64-apple-darwin",
118-
],
119-
Platform::WindowsX86_64 => &[
120-
"windows-x86_64",
121-
"windows-amd64",
122-
"windows-x64",
123-
"win-x86_64",
124-
"win-amd64",
125-
"x86_64-pc-windows-msvc",
126-
"x86_64-pc-windows-gnu",
127-
],
128-
Platform::WindowsAarch64 => &[
129-
"windows-aarch64",
130-
"windows-arm64",
131-
"win-aarch64",
132-
"win-arm64",
133-
"aarch64-pc-windows-msvc",
134-
],
13595
}
13696
}
13797

98+
/// Get supported archive extensions
99+
#[allow(dead_code)]
100+
fn extensions(&self) -> &[&'static str] {
101+
&[".tar.gz", ".tar.xz", ".tar.bz2", ".tgz", ".zip"]
102+
}
103+
138104
/// Detect the current platform
139105
pub fn current() -> Result<Self> {
140-
match (std::env::consts::OS, std::env::consts::ARCH) {
141-
("linux", "x86_64") => Ok(Platform::LinuxX86_64),
142-
("linux", "aarch64") => Ok(Platform::LinuxAarch64),
143-
("macos", "x86_64") => Ok(Platform::DarwinX86_64),
144-
("macos", "aarch64") | ("macos", "arm64") => Ok(Platform::DarwinAarch64),
145-
("windows", "x86_64") => Ok(Platform::WindowsX86_64),
146-
("windows", "aarch64") | ("windows", "arm64") => Ok(Platform::WindowsAarch64),
147-
(os, arch) => bail!("Unsupported platform: {}-{}", os, arch),
106+
match std::env::consts::ARCH {
107+
"x86_64" => Ok(Platform::LinuxX86_64),
108+
"aarch64" | "arm64" => Ok(Platform::LinuxAarch64),
109+
arch => bail!("Unsupported architecture: {}", arch),
148110
}
149111
}
150112
}
@@ -404,24 +366,38 @@ pub fn find_matching_asset(
404366
let name_lower = asset.name.to_lowercase();
405367
let mut score = 0;
406368

407-
// Check platform aliases
369+
// Check platform aliases (specific arch match = +10)
408370
for alias in aliases {
409371
if name_lower.contains(alias) {
410372
score += 10;
411373
break;
412374
}
413375
}
414376

377+
// Generic "linux" match (no arch specified) = +5
378+
if score == 0 && name_lower.contains("linux") {
379+
score += 5;
380+
}
381+
415382
// Only consider archives if platform matched
416-
if score >= 10 {
417-
// Prefer archives over bare binaries (but still allow bare binaries)
383+
if score >= 5 {
384+
// Prefer archives over bare binaries
418385
if name_lower.ends_with(".tar.gz")
419386
|| name_lower.ends_with(".tgz")
420387
|| name_lower.ends_with(".tar.xz")
388+
|| name_lower.ends_with(".tar.bz2")
421389
|| name_lower.ends_with(".zip")
390+
|| name_lower.ends_with(".appimage")
391+
|| name_lower.ends_with(".deb")
392+
|| name_lower.ends_with(".rpm")
393+
|| name_lower.ends_with(".tar")
422394
{
423395
score += 5;
424396
}
397+
// Shell scripts get small bonus
398+
if name_lower.ends_with(".sh") {
399+
score += 2;
400+
}
425401
}
426402

427403
// Avoid checksum-like names
@@ -598,8 +574,8 @@ mod tests {
598574
},
599575
Asset {
600576
id: 2,
601-
name: "app-darwin-arm64.tar.gz".to_string(),
602-
browser_download_url: "https://example.com/darwin".to_string(),
577+
name: "app-linux-aarch64.tar.gz".to_string(),
578+
browser_download_url: "https://example.com/aarch64".to_string(),
603579
size: 1000,
604580
},
605581
Asset {
@@ -614,8 +590,110 @@ mod tests {
614590
let asset = find_matching_asset(&release, Platform::LinuxX86_64).unwrap();
615591
assert_eq!(asset.name, "app-linux-x86_64.tar.gz");
616592

617-
let asset = find_matching_asset(&release, Platform::DarwinAarch64).unwrap();
618-
assert_eq!(asset.name, "app-darwin-arm64.tar.gz");
593+
let asset = find_matching_asset(&release, Platform::LinuxAarch64).unwrap();
594+
assert_eq!(asset.name, "app-linux-aarch64.tar.gz");
595+
}
596+
597+
#[test]
598+
fn test_find_matching_asset_generic_linux() {
599+
// Test generic "linux" assets (no arch specified)
600+
let release = Release {
601+
tag_name: "v1.0.0".to_string(),
602+
name: None,
603+
body: None,
604+
assets: vec![Asset {
605+
id: 1,
606+
name: "app-linux.tar.gz".to_string(),
607+
browser_download_url: "https://example.com/linux".to_string(),
608+
size: 1000,
609+
}],
610+
};
611+
612+
// Generic linux should match both x86_64 and aarch64 (lower priority)
613+
let asset = find_matching_asset(&release, Platform::LinuxX86_64).unwrap();
614+
assert_eq!(asset.name, "app-linux.tar.gz");
615+
616+
let asset = find_matching_asset(&release, Platform::LinuxAarch64).unwrap();
617+
assert_eq!(asset.name, "app-linux.tar.gz");
618+
}
619+
620+
#[test]
621+
fn test_find_matching_asset_deb_rpm() {
622+
// Test .deb and .rpm packages
623+
let release = Release {
624+
tag_name: "v1.0.0".to_string(),
625+
name: None,
626+
body: None,
627+
assets: vec![
628+
Asset {
629+
id: 1,
630+
name: "app_1.0.0_linux_amd64.deb".to_string(),
631+
browser_download_url: "https://example.com/deb".to_string(),
632+
size: 1000,
633+
},
634+
Asset {
635+
id: 2,
636+
name: "app-1.0.0-linux-x86_64.rpm".to_string(),
637+
browser_download_url: "https://example.com/rpm".to_string(),
638+
size: 1000,
639+
},
640+
],
641+
};
642+
643+
let asset = find_matching_asset(&release, Platform::LinuxX86_64).unwrap();
644+
// Should prefer .deb or .rpm with archive bonus
645+
assert!(asset.name.ends_with(".deb") || asset.name.ends_with(".rpm"));
646+
}
647+
648+
#[test]
649+
fn test_find_matching_asset_shell_script() {
650+
// Test .sh shell scripts get small bonus
651+
let release = Release {
652+
tag_name: "v1.0.0".to_string(),
653+
name: None,
654+
body: None,
655+
assets: vec![Asset {
656+
id: 1,
657+
name: "install-linux-x86_64.sh".to_string(),
658+
browser_download_url: "https://example.com/sh".to_string(),
659+
size: 1000,
660+
}],
661+
};
662+
663+
let asset = find_matching_asset(&release, Platform::LinuxX86_64).unwrap();
664+
assert_eq!(asset.name, "install-linux-x86_64.sh");
665+
}
666+
667+
#[test]
668+
fn test_find_matching_asset_prefers_specific_arch() {
669+
// When specific arch is available, prefer it over generic
670+
let release = Release {
671+
tag_name: "v1.0.0".to_string(),
672+
name: None,
673+
body: None,
674+
assets: vec![
675+
Asset {
676+
id: 1,
677+
name: "app-linux.tar.gz".to_string(),
678+
browser_download_url: "https://example.com/generic".to_string(),
679+
size: 1000,
680+
},
681+
Asset {
682+
id: 2,
683+
name: "app-linux-x86_64.tar.gz".to_string(),
684+
browser_download_url: "https://example.com/specific".to_string(),
685+
size: 1000,
686+
},
687+
],
688+
};
689+
690+
// Should prefer the x86_64 specific asset
691+
let asset = find_matching_asset(&release, Platform::LinuxX86_64).unwrap();
692+
assert_eq!(asset.name, "app-linux-x86_64.tar.gz");
693+
694+
// aarch64 should fall back to generic
695+
let asset = find_matching_asset(&release, Platform::LinuxAarch64).unwrap();
696+
assert_eq!(asset.name, "app-linux.tar.gz");
619697
}
620698

621699
#[test]

‎src/install.rs‎

Lines changed: 10 additions & 38 deletions

0 commit comments

Comments
 (0)