diff --git a/crates/qt-build-utils/src/installation/qt_minimal/artifact.rs b/crates/qt-build-utils/src/installation/qt_minimal/artifact.rs index cb5442723..9cf20f0a4 100644 --- a/crates/qt-build-utils/src/installation/qt_minimal/artifact.rs +++ b/crates/qt-build-utils/src/installation/qt_minimal/artifact.rs @@ -3,9 +3,9 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use std::path::{Path, PathBuf}; - +use semver::Version; use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; #[derive(Debug, Serialize, Deserialize)] /// A Qt manifest.json file, which specifies a set of artifacts needed for installation @@ -17,7 +17,7 @@ pub(crate) struct ParsedQtManifest { #[derive(Debug, Serialize, Deserialize, PartialEq)] /// Descriptor for a Qt artifact, included download information pub(crate) struct ParsedQtArtifact { - pub(crate) version: semver::Version, + pub(crate) version: Version, pub(crate) arch: String, pub(crate) os: String, pub(crate) url: String, @@ -29,7 +29,10 @@ impl ParsedQtArtifact { /// Download the artifact and extract to the given target path pub fn download_and_extract(&self, target_path: &Path) -> PathBuf { // Download to a temporary location - let http_client = reqwest::blocking::Client::new(); + let http_client = reqwest::blocking::Client::builder() + .timeout(None) + .build() + .expect("Http client failed to build"); let temp_dir = tempfile::TempDir::new().expect("Could not create temporary directory"); let archive_path = super::download::download_from_url(&self.url, &self.sha256, &temp_dir, &http_client) @@ -46,6 +49,24 @@ impl ParsedQtArtifact { target_path.to_path_buf() } + /// Used to create a found artifact without a checksum, used by local artifact discovery + pub fn new( + version: Version, + arch: String, + os: String, + url: String, + content_type: String, + ) -> Self { + Self { + version, + arch, + os, + url, + sha256: "".to_string(), + content: vec![content_type], + } + } + /// Assert that the hashes are the same, from bytes pub fn verify(&self, hash: &[u8]) -> anyhow::Result<()> { let mut hash_string = String::new(); diff --git a/crates/qt-build-utils/src/installation/qt_minimal/mod.rs b/crates/qt-build-utils/src/installation/qt_minimal/mod.rs index 63174819f..4aacc3d90 100644 --- a/crates/qt-build-utils/src/installation/qt_minimal/mod.rs +++ b/crates/qt-build-utils/src/installation/qt_minimal/mod.rs @@ -8,8 +8,10 @@ mod checksum; mod download; mod extract; -use std::path::PathBuf; +use std::fs::DirEntry; +use std::path::{Path, PathBuf}; +use crate::installation::qt_minimal::artifact::ParsedQtArtifact; use crate::{QtBuildError, QtInstallation}; /// A implementation of [QtInstallation] using qtminimal @@ -84,7 +86,7 @@ impl TryFrom for QtInstallationQtMinimal { let os = target_parts .get(2) .expect("TARGET to have a component"); - let artifacts: Vec = manifest + let artifacts: Vec = manifest .artifacts .into_iter() .filter(|artifact| { @@ -185,4 +187,70 @@ impl QtInstallationQtMinimal { path } + + /// Get a collection of the locally installed Qt artifacts + pub(crate) fn local_artifacts() -> anyhow::Result> { + let base_dir = Self::qt_minimal_root(); + + // Expects folder structure like: + // version/os/arch/qt/{bin, include} + // e.g. will find an artifact at 6.10.0/linux/x86_64/qt/bin + let mut artifacts = vec![]; + + // Iterate versions + for version in list_dirs(&base_dir) { + let path = version; + // TODO: Later skip unknown folders, + // this will error if a directory exists which isn't a version number + let semver = semver::Version::parse(path.file_name().to_str().unwrap()) + .expect("Could not parse semver from directory name"); + + for os in list_dirs(&path.path()) { + let path = os; + let os = path.file_name().to_str().unwrap().to_string(); + + for arch in list_dirs(&path.path()) { + let path = arch; + let dir_entries = list_dirs(&path.path()); + + // Expects one qt dir + let qt_dir_path = dir_entries + .iter() + .filter(|dir| dir.file_name() == "qt") + .last() + .expect("Expected to find a Qt dir in this folder"); + + let qt_folders = list_dirs(&qt_dir_path.path()); + for dir in qt_folders { + let filename = dir.file_name(); + // Will be set if bin or include dirs are found + let mut artifact_type = None; + + if filename == "bin" { + artifact_type = Some("bin"); + } else if filename == "include" { + artifact_type = Some("include"); + } + + if let Some(artifact_type) = artifact_type { + artifacts.push(ParsedQtArtifact::new( + semver.clone(), + path.file_name().to_string_lossy().to_string(), + os.clone(), + qt_dir_path.path().to_string_lossy().to_string(), + artifact_type.to_string(), + )) + } + } + } + } + } + + Ok(artifacts) + } +} + +/// Get all valid directories in path bufs, ignoring errors +fn list_dirs(path: &Path) -> Vec { + path.read_dir().unwrap().flatten().collect() } diff --git a/crates/qt-build-utils/src/lib.rs b/crates/qt-build-utils/src/lib.rs index 1abaa68a7..b05f35927 100644 --- a/crates/qt-build-utils/src/lib.rs +++ b/crates/qt-build-utils/src/lib.rs @@ -145,6 +145,7 @@ impl QtBuild { // Search existing installed qt_minimal versions // // TODO: have API to do this + let _ = QtInstallationQtMinimal::local_artifacts(); // Download from Qt artifacts //