feat: add proxy support for SDK downloads (v1.1.0)

Add --proxy and --no-proxy global flags to control HTTP/HTTPS proxy
usage for all network operations (SDK installs, FTC SDK clone/fetch,
Android SDK download).

Proxy resolution priority:
  1. --no-proxy          → go direct, ignore everything
  2. --proxy <url>       → use the specified proxy
  3. HTTPS_PROXY / HTTP_PROXY env vars (auto-detected)
  4. Nothing             → go direct

Key implementation details:
- reqwest client is always built through ProxyConfig::client() rather
  than Client::new(), so --no-proxy actively suppresses env-var
  auto-detection instead of just being a no-op.
- git2/libgit2 has its own HTTP transport that doesn't use reqwest.
  GitProxyGuard is an RAII guard that temporarily sets/clears the
  HTTPS_PROXY env vars around clone and fetch operations, then restores
  the previous state on drop. This avoids mutating ~/.gitconfig.
- Gradle wrapper reads HTTPS_PROXY natively; no programmatic
  intervention needed.
- All network failure paths now print offline/air-gapped installation
  instructions automatically, covering manual SDK installs and Gradle
  distribution download.

Closes: v1.1.0 proxy support milestone
This commit is contained in:
Eric Ratliff
2026-02-01 09:44:53 -06:00
parent 5596f5bade
commit 54647a47b1
9 changed files with 1161 additions and 48 deletions

View File

@@ -1,16 +1,17 @@
use std::path::Path;
use anyhow::{Result, Context};
use indicatif::{ProgressBar, ProgressStyle};
use reqwest::blocking::Client;
use std::fs::File;
use std::io::Write;
use colored::*;
use super::proxy::ProxyConfig;
const ANDROID_SDK_URL_LINUX: &str = "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip";
const ANDROID_SDK_URL_MAC: &str = "https://dl.google.com/android/repository/commandlinetools-mac-11076708_latest.zip";
const ANDROID_SDK_URL_WINDOWS: &str = "https://dl.google.com/android/repository/commandlinetools-win-11076708_latest.zip";
pub fn install(sdk_path: &Path) -> Result<()> {
pub fn install(sdk_path: &Path, proxy: &ProxyConfig) -> Result<()> {
// Check if SDK exists AND is complete
if sdk_path.exists() {
match verify(sdk_path) {
@@ -42,10 +43,14 @@ pub fn install(sdk_path: &Path) -> Result<()> {
// Download
println!("Downloading from: {}", url);
let client = Client::new();
proxy.print_status();
let client = proxy.client()?;
let response = client.get(url)
.send()
.context("Failed to download Android SDK")?;
.map_err(|e| {
super::proxy::print_offline_instructions();
anyhow::anyhow!("Failed to download Android SDK: {}", e)
})?;
let total_size = response.content_length().unwrap_or(0);