瀏覽代碼

feat(bundler): improve GitHub mirror URL generation with custom templates (#11096)

thep0y 10 月之前
父節點
當前提交
06718b4569

+ 6 - 0
.changes/bundler-github-mirror-template.md

@@ -0,0 +1,6 @@
+---
+"tauri-bundler": patch:feat
+"tauri-cli": patch:feat
+---
+
+Add the `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE` environment variable to specify a more accessible mirror template, facilitating companies, organizations, or individuals who cannot access GitHub to download the necessary files through their own mirror servers.

+ 1 - 3
crates/tauri-bundler/Cargo.toml

@@ -44,6 +44,7 @@ zip = { version = "2.0", default-features = false, features = ["deflate"] }
 dunce = "1"
 url = "2"
 uuid = { version = "1", features = ["v4", "v5"] }
+regex = "1"
 
 [target."cfg(target_os = \"windows\")".dependencies]
 bitness = "0.4"
@@ -60,9 +61,6 @@ time = { version = "0.3", features = ["formatting"] }
 plist = "1"
 tauri-macos-sign = { version = "0.1.1-rc.0", path = "../tauri-macos-sign" }
 
-[target."cfg(any(target_os = \"macos\", target_os = \"windows\"))".dependencies]
-regex = "1"
-
 [target."cfg(target_os = \"linux\")".dependencies]
 heck = "0.5"
 ar = "0.9.0"

+ 97 - 14
crates/tauri-bundler/src/bundle/windows/util.rs

@@ -8,8 +8,8 @@ use std::{
   path::{Path, PathBuf},
 };
 
+use regex::Regex;
 use sha2::Digest;
-use ureq::AgentBuilder;
 use url::Url;
 use zip::ZipArchive;
 
@@ -69,24 +69,53 @@ pub fn download_webview2_offline_installer(base_path: &Path, arch: &str) -> crat
   Ok(file_path)
 }
 
-fn create_agent_and_url(url: &str) -> crate::Result<(ureq::Agent, String)> {
-  match std::env::var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR") {
-    Ok(cdn) if url.starts_with("https://github.com/") => {
-      let mut parsed_cdn = Url::parse(&cdn)?;
-      parsed_cdn.set_path(url);
-      Ok((AgentBuilder::new().build(), parsed_cdn.into()))
-    }
-    _ => Ok((
-      AgentBuilder::new().try_proxy_from_env(true).build(),
-      url.to_owned(),
-    )),
+fn generate_github_mirror_url_from_template(github_url: &str) -> Option<String> {
+  std::env::var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE")
+    .ok()
+    .and_then(|template| {
+      let re =
+        Regex::new(r"https://github.com/([^/]+)/([^/]+)/releases/download/([^/]+)/(.*)").unwrap();
+      re.captures(github_url).map(|caps| {
+        template
+          .replace("<owner>", &caps[1])
+          .replace("<repo>", &caps[2])
+          .replace("<version>", &caps[3])
+          .replace("<asset>", &caps[4])
+      })
+    })
+}
+
+fn generate_github_mirror_url_from_base(github_url: &str) -> Option<String> {
+  std::env::var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR")
+    .ok()
+    .and_then(|cdn| Url::parse(&cdn).ok())
+    .map(|mut cdn| {
+      cdn.set_path(github_url);
+      cdn.to_string()
+    })
+}
+
+fn generate_github_alternative_url(url: &str) -> Option<(ureq::Agent, String)> {
+  if !url.starts_with("https://github.com/") {
+    return None;
   }
+
+  generate_github_mirror_url_from_template(url)
+    .or_else(|| generate_github_mirror_url_from_base(url))
+    .map(|alt_url| (ureq::AgentBuilder::new().build(), alt_url))
+}
+
+fn create_agent_and_url(url: &str) -> (ureq::Agent, String) {
+  generate_github_alternative_url(url).unwrap_or((
+    ureq::AgentBuilder::new().try_proxy_from_env(true).build(),
+    url.to_owned(),
+  ))
 }
 
 pub fn download(url: &str) -> crate::Result<Vec<u8>> {
-  log::info!(action = "Downloading"; "{}", url);
+  let (agent, final_url) = create_agent_and_url(url);
 
-  let (agent, final_url) = create_agent_and_url(url)?;
+  log::info!(action = "Downloading"; "{}", final_url);
 
   let response = agent.get(&final_url).call().map_err(Box::new)?;
   let mut bytes = Vec::new();
@@ -196,3 +225,57 @@ pub fn os_bitness<'a>() -> Option<&'a str> {
     _ => None,
   }
 }
+
+#[cfg(test)]
+mod tests {
+  use super::generate_github_mirror_url_from_template;
+  use std::env;
+
+  const GITHUB_ASSET_URL: &str =
+    "https://github.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip";
+  const NON_GITHUB_ASSET_URL: &str = "https://someotherwebsite.com/somefile.zip";
+
+  #[test]
+  fn test_generate_mirror_url_no_env_var() {
+    env::remove_var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE");
+
+    assert!(generate_github_mirror_url_from_template(GITHUB_ASSET_URL).is_none());
+  }
+
+  #[test]
+  fn test_generate_mirror_url_non_github_url() {
+    env::set_var(
+      "TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE",
+      "https://mirror.example.com/<owner>/<repo>/releases/download/<version>/<asset>",
+    );
+
+    assert!(generate_github_mirror_url_from_template(NON_GITHUB_ASSET_URL).is_none());
+  }
+
+  struct TestCase {
+    template: &'static str,
+    expected_url: &'static str,
+  }
+
+  #[test]
+  fn test_generate_mirror_url_correctly() {
+    let test_cases = vec![
+            TestCase {
+                template: "https://mirror.example.com/<owner>/<repo>/releases/download/<version>/<asset>",
+                expected_url: "https://mirror.example.com/wixtoolset/wix3/releases/download/wix3112rtm/wix311-binaries.zip",
+            },
+            TestCase {
+                template: "https://mirror.example.com/<asset>",
+                expected_url: "https://mirror.example.com/wix311-binaries.zip",
+            },
+        ];
+
+    for case in test_cases {
+      env::set_var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE", case.template);
+      assert_eq!(
+        generate_github_mirror_url_from_template(GITHUB_ASSET_URL),
+        Some(case.expected_url.to_string())
+      );
+    }
+  }
+}

+ 1 - 0
crates/tauri-cli/ENVIRONMENT_VARIABLES.md

@@ -16,6 +16,7 @@ These environment variables are inputs to the CLI which may have an equivalent C
 - `TAURI_LINUX_AYATANA_APPINDICATOR` — Set this var to `true` or `1` to force usage of `libayatana-appindicator` for system tray on Linux.
 - `TAURI_BUNDLER_WIX_FIPS_COMPLIANT` — Specify the bundler's WiX `FipsCompliant` option.
 - `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR` - Specify a GitHub mirror to download files and tools used by tauri bundler.
+- `TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE` - Specify a GitHub mirror template to download files and tools used by tauri bundler, for example: `https://mirror.example.com/<owner>/<repo>/releases/download/<version>/<asset>`.
 - `TAURI_SKIP_SIDECAR_SIGNATURE_CHECK` - Skip signing sidecars.
 - `TAURI_SIGNING_PRIVATE_KEY` — Private key used to sign your app bundles, can be either a string or a path to the file.
 - `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` — The signing private key password, see `TAURI_SIGNING_PRIVATE_KEY`.