Skip to content

Commit 7ef9f8a

Browse files
authored
feat(download): add DEB/RPM packages and Script/DEB/RPM install tabs (#91)
1 parent c5c9b76 commit 7ef9f8a

2 files changed

Lines changed: 118 additions & 3 deletions

File tree

app/download/components/download-page-client.tsx

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ type ServerInstallPath = {
191191
Icon: ComponentType<{ className?: string }>;
192192
commandTitle: string;
193193
command: string[];
194+
commands?: InstallCommand[];
194195
chips: string[];
195196
actions?: {
196197
href: string;
@@ -199,6 +200,54 @@ type ServerInstallPath = {
199200
}[];
200201
};
201202

203+
type InstallCommand = {
204+
id: string;
205+
label: string;
206+
title: string;
207+
command: string[];
208+
};
209+
210+
function InstallCommandTabs({
211+
commands,
212+
}: {
213+
commands: InstallCommand[];
214+
}) {
215+
const [activeCommandId, setActiveCommandId] = useState(commands[0].id);
216+
const activeCommand =
217+
commands.find((command) => command.id === activeCommandId) ?? commands[0];
218+
219+
return (
220+
<div>
221+
<div className="mb-3 flex border-b border-border" role="tablist" aria-label="Linux install methods">
222+
{commands.map((command) => {
223+
const isActive = command.id === activeCommand.id;
224+
225+
return (
226+
<button
227+
key={command.id}
228+
type="button"
229+
role="tab"
230+
aria-selected={isActive}
231+
onClick={() => setActiveCommandId(command.id)}
232+
className={cn(
233+
"border-b-2 border-b-transparent px-4 py-2 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground",
234+
isActive && "border-b-brand text-brand"
235+
)}
236+
>
237+
{command.label}
238+
</button>
239+
);
240+
})}
241+
</div>
242+
<CodeBlock
243+
title={activeCommand.title}
244+
code={activeCommand.command}
245+
className="border-brand/60 shadow-[0_0_0_1px_rgba(39,112,246,0.18),0_18px_60px_rgba(39,112,246,0.12)]"
246+
/>
247+
</div>
248+
);
249+
}
250+
202251
function KubernetesInstallCommands() {
203252
const methods = [
204253
{
@@ -262,6 +311,18 @@ function ServerInstallTabs({ release }: { release: GitHubRelease | null }) {
262311
const x86Gnu = findReleaseAsset(release, [/rustfs-linux-x86_64-gnu.*\.zip/i], 'rustfs-linux-x86_64-gnu-latest.zip');
263312
const armMusl = findReleaseAsset(release, [/rustfs-linux-aarch64-musl.*\.zip/i], 'rustfs-linux-aarch64-musl-latest.zip');
264313
const armGnu = findReleaseAsset(release, [/rustfs-linux-aarch64-gnu.*\.zip/i], 'rustfs-linux-aarch64-gnu-latest.zip');
314+
315+
// DEB/RPM native packages from R2
316+
const R2_PKG_BASE = 'https://dl.rustfs.com/artifacts/rustfs/packages/release';
317+
const tagName = release?.tag_name ?? '';
318+
const debVersion = tagName.replace('-', '~'); // 1.0.0-rc.1 -> 1.0.0~rc.1
319+
const rpmVersion = tagName.replace('-', '_'); // 1.0.0-rc.1 -> 1.0.0_rc.1
320+
const debAmd64Url = tagName ? `${R2_PKG_BASE}/rustfs_${debVersion}_amd64.deb` : '';
321+
const debArm64Url = tagName ? `${R2_PKG_BASE}/rustfs_${debVersion}_arm64.deb` : '';
322+
const rpmX86Url = tagName ? `${R2_PKG_BASE}/rustfs-${rpmVersion}-1.x86_64.rpm` : '';
323+
const rpmArm64Url = tagName ? `${R2_PKG_BASE}/rustfs-${rpmVersion}-1.aarch64.rpm` : '';
324+
const debAmd64Filename = debAmd64Url.split('/').pop() ?? '';
325+
const rpmX86Filename = rpmX86Url.split('/').pop() ?? '';
265326
const macArmUrl = release
266327
? getDownloadUrlForPlatform(release, 'macos', 'aarch64')
267328
: null;
@@ -284,12 +345,54 @@ function ServerInstallTabs({ release }: { release: GitHubRelease | null }) {
284345
command: [
285346
'curl -O https://rustfs.com/install_rustfs.sh && bash install_rustfs.sh',
286347
],
287-
chips: ['MUSL / GNU', 'x86_64 / ARM64', 'system service'],
348+
commands: [
349+
{
350+
id: 'script',
351+
label: 'Script',
352+
title: 'Fast validation',
353+
command: [
354+
'curl -O https://rustfs.com/install_rustfs.sh && bash install_rustfs.sh',
355+
],
356+
},
357+
...(debAmd64Url
358+
? [
359+
{
360+
id: 'deb',
361+
label: 'DEB',
362+
title: 'Debian / Ubuntu package',
363+
command: [
364+
`curl -O ${debAmd64Url}`,
365+
`sudo dpkg -i ${debAmd64Filename}`,
366+
'rustfs --version',
367+
],
368+
},
369+
]
370+
: []),
371+
...(rpmX86Url
372+
? [
373+
{
374+
id: 'rpm',
375+
label: 'RPM',
376+
title: 'RHEL / Fedora package',
377+
command: [
378+
`curl -O ${rpmX86Url}`,
379+
`sudo rpm -ivh ${rpmX86Filename}`,
380+
'rustfs --version',
381+
],
382+
},
383+
]
384+
: []),
385+
],
386+
chips: ['MUSL / GNU', 'DEB / RPM', 'x86_64 / ARM64', 'system service'],
288387
actions: [
289388
{ href: x86Musl.url, label: 'x86_64 MUSL', icon: <LinuxIcon className="size-4" /> },
290389
{ href: x86Gnu.url, label: 'x86_64 GNU', icon: <LinuxIcon className="size-4" /> },
291390
{ href: armMusl.url, label: 'ARM64 MUSL', icon: <LinuxIcon className="size-4" /> },
292391
{ href: armGnu.url, label: 'ARM64 GNU', icon: <LinuxIcon className="size-4" /> },
392+
...(debAmd64Url ? [{ href: debAmd64Url, label: 'DEB amd64', icon: <LinuxIcon className="size-4" /> }] : []),
393+
...(debArm64Url ? [{ href: debArm64Url, label: 'DEB arm64', icon: <LinuxIcon className="size-4" /> }] : []),
394+
...(rpmX86Url ? [{ href: rpmX86Url, label: 'RPM x86_64', icon: <LinuxIcon className="size-4" /> }] : []),
395+
...(rpmArm64Url ? [{ href: rpmArm64Url, label: 'RPM aarch64', icon: <LinuxIcon className="size-4" /> }] : []),
293396
],
294397
},
295398
{
@@ -444,7 +547,9 @@ function ServerInstallTabs({ release }: { release: GitHubRelease | null }) {
444547
</div>
445548

446549
<div className="grid gap-5 p-5 sm:p-6">
447-
{activePath.id === 'kubernetes' ? (
550+
{activePath.commands ? (
551+
<InstallCommandTabs commands={activePath.commands} />
552+
) : activePath.id === 'kubernetes' ? (
448553
<KubernetesInstallCommands />
449554
) : (
450555
<CodeBlock
@@ -542,7 +647,7 @@ export default function DownloadPageClient() {
542647
eyebrow="Data service"
543648
title="RustFS Server"
544649
description="Server binary, Docker image, and source archive."
545-
methods={['Linux', 'Docker', 'Compose', 'Kubernetes', 'macOS', 'Windows']}
650+
methods={['Linux', 'DEB / RPM', 'Docker', 'Compose', 'Kubernetes', 'macOS', 'Windows']}
546651
Icon={ServerIcon}
547652
/>
548653
<ProductDownloadLink

lib/github.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,19 @@ async function fetchGitHub(
3131
const controller = new AbortController();
3232
const timeoutId = setTimeout(() => controller.abort(), GITHUB_FETCH_TIMEOUT_MS);
3333

34+
const headers: Record<string, string> = {
35+
...(init.headers as Record<string, string>),
36+
};
37+
38+
const token = process.env.GITHUB_TOKEN;
39+
if (token) {
40+
headers['Authorization'] = `Bearer ${token}`;
41+
}
42+
3443
try {
3544
return await fetch(url, {
3645
...init,
46+
headers,
3747
signal: controller.signal,
3848
});
3949
} finally {

0 commit comments

Comments
 (0)