feat: add file system utility functions

This commit is contained in:
2026-03-04 01:52:44 +08:00
parent c4a25fced2
commit 5e00e36e57

106
lib/fs-utils.ts Normal file
View File

@@ -0,0 +1,106 @@
// lib/fs-utils.ts
import fs from 'fs/promises';
import path from 'path';
import { RESOURCE_PATH } from './constants';
/**
* 获取所有项目目录
*/
export async function getProjects(): Promise<string[]> {
const dirs = await fs.readdir(RESOURCE_PATH);
const projectDirs = dirs.filter(dir => {
const dirPath = path.join(RESOURCE_PATH, dir);
// 检查是否是目录
return fs.stat(dirPath).then(stats => stats.isDirectory()).catch(() => false);
});
return projectDirs;
}
/**
* 获取指定项目的所有版本目录
*/
export async function getVersions(project: string): Promise<string[]> {
const projectPath = path.join(RESOURCE_PATH, project);
const dirs = await fs.readdir(projectPath);
const versionDirs = dirs.filter(dir => {
const dirPath = path.join(projectPath, dir);
return fs.stat(dirPath).then(stats => stats.isDirectory()).catch(() => false);
});
return versionDirs.sort();
}
/**
* 获取指定项目版本的 APK 文件列表
*/
export async function getApks(project: string, version: string, commitId?: string): Promise<{
name: string;
commit: string | null;
size: number;
modifiedAt: Date;
}[]> {
const apksPath = path.join(RESOURCE_PATH, project, version, 'apks');
try {
const files = await fs.readdir(apksPath);
const apkFiles = files.filter(file => file.endsWith('.apk'));
const apks = await Promise.all(
apkFiles.map(async (file) => {
const filePath = path.join(apksPath, file);
const stats = await fs.stat(filePath);
// 提取 commit id (假设文件名格式为 xxx-{commit}-xxx.apk)
const commitMatch = file.match(/([a-f0-9]{7,})/i);
const commit = commitMatch ? commitMatch[1] : null;
return {
name: file,
commit,
size: stats.size,
modifiedAt: stats.mtime,
};
})
);
// 如果指定了 commit id进行过滤
if (commitId) {
return apks.filter(apk =>
apk.commit && apk.commit.toLowerCase().includes(commitId.toLowerCase())
);
}
return apks.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
} catch (error) {
// 如果 apks 目录不存在,返回空数组
return [];
}
}
/**
* 格式化版本号显示 (0_42 -> 0.42)
*/
export function formatVersion(version: string): string {
return version.replace('_', '.');
}
/**
* 格式化文件大小
*/
export function formatFileSize(bytes: number): string {
if (bytes < 1024) return bytes + ' B';
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB';
if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
}
/**
* 格式化日期时间
*/
export function formatDateTime(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}