Browse Source

简化Git的镜像选择

黄中银 1 month ago
parent
commit
c4e050e646

+ 5 - 11
ApqInstaller/electron/modules/constants.ts

@@ -107,28 +107,22 @@ export const APP_NAME = 'ApqInstaller'
 
 // Git for Windows 镜像配置
 export const GIT_MIRRORS = {
-  // 华为云镜像(默认)
+  // 华为云镜像(默认,国内推荐
   huaweicloud: {
     name: '华为云镜像',
     // 华为云镜像下载地址格式: https://mirrors.huaweicloud.com/git-for-windows/v{version}.windows.1/Git-{version}-64-bit.exe
     getDownloadUrl: (version: string, arch: '64' | '32') =>
       `https://mirrors.huaweicloud.com/git-for-windows/v${version}.windows.1/Git-${version}-${arch}-bit.exe`,
-    // 华为云没有 API,需要从 GitHub API 获取版本列表
-    apiUrl: null
-  },
-  // 清华大学镜像
-  tuna: {
-    name: '清华大学镜像',
-    getDownloadUrl: (version: string, arch: '64' | '32') =>
-      `https://mirrors.tuna.tsinghua.edu.cn/github-release/git-for-windows/git/v${version}.windows.1/Git-${version}-${arch}-bit.exe`,
-    apiUrl: null
+    // 华为云镜像版本列表 API
+    versionsUrl: 'https://mirrors.huaweicloud.com/git-for-windows/'
   },
   // GitHub 官方(需要代理)
   github: {
     name: 'GitHub 官方',
     getDownloadUrl: (version: string, arch: '64' | '32') =>
       `https://github.com/git-for-windows/git/releases/download/v${version}.windows.1/Git-${version}-${arch}-bit.exe`,
-    apiUrl: 'https://api.github.com/repos/git-for-windows/git/releases'
+    // GitHub API 获取版本列表
+    versionsUrl: 'https://api.github.com/repos/git-for-windows/git/releases'
   }
 } as const
 

+ 1 - 8
ApqInstaller/electron/modules/ipc-handlers.ts

@@ -7,7 +7,7 @@ import { execa } from 'execa'
 import type { SoftwareType, SoftwareTypeWithAll, Platform } from './types'
 import { ERROR_MESSAGES } from './constants'
 import { commandExists, checkNetworkConnection } from './utils'
-import { getVersions, setGitMirror, setCustomGitMirrorUrl, getGitMirrorConfig } from './version-fetcher'
+import { getVersions, setGitMirror, getGitMirrorConfig } from './version-fetcher'
 import type { GitMirrorType } from './constants'
 import {
   checkInstalled,
@@ -371,12 +371,6 @@ export function registerHandlers(): void {
     setGitMirror(mirror)
   })
 
-  // 设置自定义 Git 镜像 URL
-  ipcMain.handle('set-custom-git-mirror-url', (_event, url: string | null) => {
-    logger.info(`设置自定义 Git 镜像 URL: ${url}`)
-    setCustomGitMirrorUrl(url)
-  })
-
   // 获取 Git 镜像配置
   ipcMain.handle('get-git-mirror-config', () => {
     return getGitMirrorConfig()
@@ -530,7 +524,6 @@ export function removeHandlers(): void {
     'install',
     // Git 镜像配置
     'set-git-mirror',
-    'set-custom-git-mirror-url',
     'get-git-mirror-config',
     // 自动更新相关
     'updater:check',

+ 2 - 4
ApqInstaller/electron/modules/types.ts

@@ -116,8 +116,7 @@ export interface UpdateResult {
 
 // Git 镜像配置接口(GitMirrorType 从 constants.ts 导出)
 export interface GitMirrorConfig {
-  mirror: 'huaweicloud' | 'tuna' | 'github'
-  customUrl: string | null
+  mirror: 'huaweicloud' | 'github'
 }
 
 // IPC API 类型定义
@@ -140,8 +139,7 @@ export interface ElectronAPI {
   checkUpdate: (software: SoftwareType) => Promise<{ hasUpdate: boolean; latestVersion?: string }>
 
   // Git 镜像配置
-  setGitMirror: (mirror: 'huaweicloud' | 'tuna' | 'github') => Promise<void>
-  setCustomGitMirrorUrl: (url: string | null) => Promise<void>
+  setGitMirror: (mirror: 'huaweicloud' | 'github') => Promise<void>
   getGitMirrorConfig: () => Promise<GitMirrorConfig>
 
   // 历史和日志

+ 67 - 41
ApqInstaller/electron/modules/version-fetcher.ts

@@ -413,31 +413,20 @@ async function getVSCodeVersions(): Promise<VersionResult> {
 // 当前使用的 Git 镜像
 let currentGitMirror: GitMirrorType = DEFAULT_GIT_MIRROR
 
-// 自定义镜像 URL(用户输入)
-let customGitMirrorUrl: string | null = null
-
 /**
  * 设置 Git 镜像
  */
 export function setGitMirror(mirror: GitMirrorType): void {
   currentGitMirror = mirror
-  customGitMirrorUrl = null
-}
-
-/**
- * 设置自定义 Git 镜像 URL
- * @param url 自定义镜像 URL,格式应包含 {version} 和 {arch} 占位符
- *            例如: https://example.com/git/{version}/Git-{version}-{arch}-bit.exe
- */
-export function setCustomGitMirrorUrl(url: string | null): void {
-  customGitMirrorUrl = url
+  // 清除版本缓存,以便重新获取
+  clearCache()
 }
 
 /**
  * 获取当前 Git 镜像配置
  */
-export function getGitMirrorConfig(): { mirror: GitMirrorType; customUrl: string | null } {
-  return { mirror: currentGitMirror, customUrl: customGitMirrorUrl }
+export function getGitMirrorConfig(): { mirror: GitMirrorType } {
+  return { mirror: currentGitMirror }
 }
 
 /**
@@ -445,20 +434,11 @@ export function getGitMirrorConfig(): { mirror: GitMirrorType; customUrl: string
  */
 export function getGitDownloadUrl(version: string): string {
   const arch = os.arch() === 'x64' ? '64' : '32'
-
-  // 如果有自定义 URL,使用自定义 URL
-  if (customGitMirrorUrl) {
-    return customGitMirrorUrl
-      .replace('{version}', version)
-      .replace('{arch}', arch)
-  }
-
-  // 使用预设镜像
   const mirror = GIT_MIRRORS[currentGitMirror]
   return mirror.getDownloadUrl(version, arch)
 }
 
-// 备用版本列表(当无法从 API 获取时使用)
+// 备用版本列表(当无法从任何源获取时使用)
 const FALLBACK_GIT_VERSIONS = [
   '2.47.1', '2.47.0',
   '2.46.2', '2.46.1', '2.46.0',
@@ -469,8 +449,7 @@ const FALLBACK_GIT_VERSIONS = [
 ]
 
 /**
- * 从 Git for Windows 官方 GitHub API 获取版本列表
- * API: https://api.github.com/repos/git-for-windows/git/releases
+ * 从 GitHub API 获取版本列表
  */
 async function getGitVersionsFromGitHub(): Promise<string[]> {
   try {
@@ -479,7 +458,7 @@ async function getGitVersionsFromGitHub(): Promise<string[]> {
         'Accept': 'application/vnd.github.v3+json',
         'User-Agent': 'ApqInstaller'
       },
-      signal: AbortSignal.timeout(10000) // 10秒超时
+      signal: AbortSignal.timeout(10000)
     })
 
     if (!response.ok) {
@@ -490,17 +469,10 @@ async function getGitVersionsFromGitHub(): Promise<string[]> {
     const versions: string[] = []
 
     for (const release of releases) {
-      // 跳过预发布版本
       if (release.prerelease) continue
-
-      // tag_name 格式: v2.47.1.windows.1
       const match = release.tag_name.match(/^v?(\d+\.\d+\.\d+)/)
-      if (match) {
-        const version = match[1]
-        // 避免重复版本
-        if (!versions.includes(version)) {
-          versions.push(version)
-        }
+      if (match && !versions.includes(match[1])) {
+        versions.push(match[1])
       }
     }
 
@@ -511,11 +483,66 @@ async function getGitVersionsFromGitHub(): Promise<string[]> {
   }
 }
 
+/**
+ * 从华为云镜像获取版本列表
+ * 通过解析目录页面获取可用版本
+ */
+async function getGitVersionsFromHuaweicloud(): Promise<string[]> {
+  try {
+    const response = await fetch('https://mirrors.huaweicloud.com/git-for-windows/', {
+      headers: { 'User-Agent': 'ApqInstaller' },
+      signal: AbortSignal.timeout(10000)
+    })
+
+    if (!response.ok) {
+      throw new Error(`华为云镜像请求失败: ${response.status}`)
+    }
+
+    const html = await response.text()
+    const versions: string[] = []
+
+    // 解析 HTML 页面,查找版本目录链接
+    // 格式: <a href="v2.47.1.windows.1/">v2.47.1.windows.1/</a>
+    const regex = /href="v(\d+\.\d+\.\d+)\.windows\.\d+\/"/g
+    let match
+    while ((match = regex.exec(html)) !== null) {
+      const version = match[1]
+      if (!versions.includes(version)) {
+        versions.push(version)
+      }
+    }
+
+    // 按版本号降序排序
+    versions.sort((a, b) => {
+      const partsA = a.split('.').map(Number)
+      const partsB = b.split('.').map(Number)
+      for (let i = 0; i < 3; i++) {
+        if (partsA[i] !== partsB[i]) {
+          return partsB[i] - partsA[i]
+        }
+      }
+      return 0
+    })
+
+    return versions
+  } catch (error) {
+    console.error('从华为云镜像获取 Git 版本失败:', error)
+    return []
+  }
+}
+
 async function getGitVersionsWindows(): Promise<VersionResult> {
   const versionsByMajor = new Map<string, VersionItem[]>()
 
-  // 尝试从 GitHub API 获取版本列表
-  let versions = await getGitVersionsFromGitHub()
+  // 根据当前镜像源获取版本列表
+  let versions: string[] = []
+
+  if (currentGitMirror === 'github') {
+    versions = await getGitVersionsFromGitHub()
+  } else {
+    // 华为云镜像
+    versions = await getGitVersionsFromHuaweicloud()
+  }
 
   // 如果获取失败,使用备用版本列表
   if (versions.length === 0) {
@@ -533,8 +560,7 @@ async function getGitVersionsWindows(): Promise<VersionResult> {
     throw new Error(ERROR_MESSAGES.VERSION_FETCH_ERROR)
   }
 
-  // 获取当前镜像名称
-  const mirrorName = customGitMirrorUrl ? '自定义镜像' : GIT_MIRRORS[currentGitMirror].name
+  const mirrorName = GIT_MIRRORS[currentGitMirror].name
 
   return {
     versions: buildVersionList(versionsByMajor, {

+ 0 - 3
ApqInstaller/electron/preload.ts

@@ -49,9 +49,6 @@ const electronAPI: ElectronAPI = {
   // 设置 Git 镜像
   setGitMirror: (mirror) => ipcRenderer.invoke('set-git-mirror', mirror),
 
-  // 设置自定义 Git 镜像 URL
-  setCustomGitMirrorUrl: (url) => ipcRenderer.invoke('set-custom-git-mirror-url', url),
-
   // 获取 Git 镜像配置
   getGitMirrorConfig: () => ipcRenderer.invoke('get-git-mirror-config'),
 

+ 2 - 6
ApqInstaller/src/i18n/en-US.ts

@@ -66,12 +66,8 @@ export default {
       name: 'Git',
       description: 'Distributed version control system',
       mirror: 'Download Mirror',
-      mirrorHuaweicloud: 'Huawei Cloud Mirror (Recommended)',
-      mirrorTuna: 'Tsinghua University Mirror',
-      mirrorGithub: 'GitHub Official (Proxy Required)',
-      mirrorCustom: 'Custom Mirror',
-      customMirrorUrl: 'Custom Mirror URL',
-      customMirrorPlaceholder: 'Enter mirror URL, use {version} and {arch} placeholders'
+      mirrorHuaweicloud: 'Huawei Cloud Mirror (China Recommended)',
+      mirrorGithub: 'GitHub Official (Proxy Required)'
     },
     all: {
       name: 'Install All',

+ 2 - 6
ApqInstaller/src/i18n/zh-CN.ts

@@ -66,12 +66,8 @@ export default {
       name: 'Git',
       description: '分布式版本控制系统',
       mirror: '下载镜像',
-      mirrorHuaweicloud: '华为云镜像(推荐)',
-      mirrorTuna: '清华大学镜像',
-      mirrorGithub: 'GitHub 官方(需代理)',
-      mirrorCustom: '自定义镜像',
-      customMirrorUrl: '自定义镜像地址',
-      customMirrorPlaceholder: '输入镜像地址,使用 {version} 和 {arch} 占位符'
+      mirrorHuaweicloud: '华为云镜像(国内推荐)',
+      mirrorGithub: 'GitHub 官方(需代理)'
     },
     all: {
       name: '一键安装全部',

+ 1 - 3
ApqInstaller/src/types/electron.d.ts

@@ -77,11 +77,10 @@ export interface LogEntry {
 }
 
 // Git 镜像类型
-export type GitMirrorType = 'huaweicloud' | 'tuna' | 'github'
+export type GitMirrorType = 'huaweicloud' | 'github'
 
 export interface GitMirrorConfig {
   mirror: GitMirrorType
-  customUrl: string | null
 }
 
 export interface ElectronAPI {
@@ -104,7 +103,6 @@ export interface ElectronAPI {
 
   // Git 镜像配置
   setGitMirror: (mirror: GitMirrorType) => Promise<void>
-  setCustomGitMirrorUrl: (url: string | null) => Promise<void>
   getGitMirrorConfig: () => Promise<GitMirrorConfig>
 
   // 历史和日志

+ 18 - 75
ApqInstaller/src/views/GitView.vue

@@ -58,12 +58,9 @@ function handleCancel() {
 
 // Git 镜像相关
 const gitMirror = ref<GitMirrorType>('huaweicloud')
-const useCustomMirror = ref(false)
-const customMirrorUrl = ref('')
 
-const gitMirrorOptions = [
+const gitMirrorOptions: { value: GitMirrorType; label: string }[] = [
   { value: 'huaweicloud', label: 'software.git.mirrorHuaweicloud' },
-  { value: 'tuna', label: 'software.git.mirrorTuna' },
   { value: 'github', label: 'software.git.mirrorGithub' }
 ]
 
@@ -72,45 +69,18 @@ async function loadGitMirrorConfig() {
   try {
     const config = await window.electronAPI.getGitMirrorConfig()
     gitMirror.value = config.mirror
-    if (config.customUrl) {
-      useCustomMirror.value = true
-      customMirrorUrl.value = config.customUrl
-    }
   } catch {
     // 使用默认值
   }
 }
 
-// 监听镜像变化
+// 监听镜像变化,切换时重新获取版本列表
 watch(gitMirror, async (newMirror) => {
-  if (!useCustomMirror.value) {
-    await window.electronAPI.setGitMirror(newMirror)
-    await window.electronAPI.setCustomGitMirrorUrl(null)
-    // 刷新版本列表以更新下载源提示
-    versionsStore.loadVersionForSoftware('git')
-  }
-})
-
-watch(useCustomMirror, async (isCustom) => {
-  if (isCustom && customMirrorUrl.value) {
-    await window.electronAPI.setCustomGitMirrorUrl(customMirrorUrl.value)
-  } else if (!isCustom) {
-    await window.electronAPI.setCustomGitMirrorUrl(null)
-    await window.electronAPI.setGitMirror(gitMirror.value)
-  }
-  // 刷新版本列表以更新下载源提示
+  await window.electronAPI.setGitMirror(newMirror)
+  // 刷新版本列表
   versionsStore.loadVersionForSoftware('git')
 })
 
-// 自定义镜像 URL 变化时更新
-async function handleCustomMirrorUrlChange() {
-  if (useCustomMirror.value && customMirrorUrl.value) {
-    await window.electronAPI.setCustomGitMirrorUrl(customMirrorUrl.value)
-    // 刷新版本列表以更新下载源提示
-    versionsStore.loadVersionForSoftware('git')
-  }
-}
-
 // 初始化加载 Git 镜像配置
 onMounted(() => {
   loadGitMirrorConfig()
@@ -131,6 +101,20 @@ onMounted(() => {
     </div>
 
     <SkeletonLoader :loading="isLoading">
+      <!-- Git 镜像选择 -->
+      <div class="git-mirror-option">
+        <div class="mirror-header">
+          <span class="mirror-title">{{ t('software.git.mirror') }}</span>
+        </div>
+        <div class="mirror-select">
+          <el-radio-group v-model="gitMirror" :disabled="status.installing">
+            <el-radio v-for="option in gitMirrorOptions" :key="option.value" :value="option.value">
+              {{ t(option.label) }}
+            </el-radio>
+          </el-radio-group>
+        </div>
+      </div>
+
       <div class="version-select">
         <label>{{ t('common.selectVersion') }}</label>
         <el-select v-model="selectedVersion" :disabled="isLoading || hasError" style="width: 100%">
@@ -149,35 +133,6 @@ onMounted(() => {
         </el-select>
       </div>
 
-      <!-- Git 镜像选择 -->
-      <div class="git-mirror-option">
-        <div class="mirror-header">
-          <span class="mirror-title">{{ t('software.git.mirror') }}</span>
-        </div>
-        <div class="mirror-select">
-          <el-radio-group v-model="gitMirror" :disabled="useCustomMirror || status.installing">
-            <el-radio v-for="option in gitMirrorOptions" :key="option.value" :value="option.value">
-              {{ t(option.label) }}
-            </el-radio>
-          </el-radio-group>
-        </div>
-        <div class="custom-mirror">
-          <el-checkbox v-model="useCustomMirror" :disabled="status.installing">
-            {{ t('software.git.mirrorCustom') }}
-          </el-checkbox>
-          <el-input
-            v-if="useCustomMirror"
-            v-model="customMirrorUrl"
-            :placeholder="t('software.git.customMirrorPlaceholder')"
-            :disabled="status.installing"
-            size="small"
-            class="custom-mirror-input"
-            @blur="handleCustomMirrorUrlChange"
-            @keyup.enter="handleCustomMirrorUrlChange"
-          />
-        </div>
-      </div>
-
       <div class="button-group">
         <el-button type="primary" :disabled="isDisabled" :loading="status.installing" @click="handleInstall">
           {{ buttonText }}
@@ -223,24 +178,12 @@ onMounted(() => {
     }
 
     .mirror-select {
-      margin-bottom: var(--spacing-sm);
-
       .el-radio-group {
         display: flex;
         flex-direction: column;
         gap: var(--spacing-xs);
       }
     }
-
-    .custom-mirror {
-      display: flex;
-      flex-direction: column;
-      gap: var(--spacing-xs);
-
-      .custom-mirror-input {
-        margin-top: var(--spacing-xs);
-      }
-    }
   }
 }
 </style>