Skip to main content

floe_core/config/
location.rs

1use std::path::{Path, PathBuf};
2
3use tempfile::TempDir;
4
5use crate::config::{ConfigBase, StorageDefinition};
6use crate::io::storage::{self, StorageClient};
7use crate::FloeResult;
8
9pub struct ConfigLocation {
10    pub path: PathBuf,
11    pub base: ConfigBase,
12    pub display: String,
13    _temp_dir: Option<TempDir>,
14}
15
16pub fn resolve_config_location(input: &str) -> FloeResult<ConfigLocation> {
17    if is_remote_uri(input) {
18        let temp_dir = TempDir::new()?;
19        let local_path = download_remote_config(input, temp_dir.path())?;
20        let base = ConfigBase::remote_from_uri(temp_dir.path().to_path_buf(), input)?;
21        Ok(ConfigLocation {
22            path: local_path,
23            base,
24            display: input.to_string(),
25            _temp_dir: Some(temp_dir),
26        })
27    } else {
28        let path = PathBuf::from(input);
29        let absolute = if path.is_absolute() {
30            path
31        } else {
32            std::env::current_dir()?.join(path)
33        };
34        let canonical = std::fs::canonicalize(&absolute)?;
35        let base = ConfigBase::local_from_path(&canonical);
36        Ok(ConfigLocation {
37            path: canonical.clone(),
38            base,
39            display: canonical.display().to_string(),
40            _temp_dir: None,
41        })
42    }
43}
44
45fn download_remote_config(uri: &str, temp_dir: &Path) -> FloeResult<PathBuf> {
46    if uri.starts_with("s3://") {
47        let location = storage::s3::parse_s3_uri(uri)?;
48        let client = storage::s3::S3Client::new(location.bucket, None, None, None)?;
49        return client.download_to_temp(uri, temp_dir);
50    }
51    if uri.starts_with("gs://") {
52        let location = storage::gcs::parse_gcs_uri(uri)?;
53        let client = storage::gcs::GcsClient::new(location.bucket)?;
54        return client.download_to_temp(uri, temp_dir);
55    }
56    if uri.starts_with("abfs://") {
57        let location = storage::adls::parse_adls_uri(uri)?;
58        let definition = StorageDefinition {
59            name: "config".to_string(),
60            fs_type: "adls".to_string(),
61            bucket: None,
62            region: None,
63            account: Some(location.account),
64            container: Some(location.container),
65            prefix: None,
66            endpoint: None,
67            path_style_access: None,
68        };
69        let client = storage::adls::AdlsClient::new(&definition)?;
70        return client.download_to_temp(uri, temp_dir);
71    }
72    Err(format!("unsupported config uri: {}", uri).into())
73}
74
75/// Write `bytes` to a remote URI by staging them in a temp file then uploading.
76pub fn write_bytes_to_remote_uri(bytes: &[u8], uri: &str) -> FloeResult<()> {
77    let temp_dir = TempDir::new()?;
78    let local_path = temp_dir.path().join("upload");
79    std::fs::write(&local_path, bytes)?;
80    upload_to_remote_uri(&local_path, uri)
81}
82
83pub fn upload_to_remote_uri(local_path: &Path, uri: &str) -> FloeResult<()> {
84    if uri.starts_with("s3://") {
85        let location = storage::s3::parse_s3_uri(uri)?;
86        let client = storage::s3::S3Client::new(location.bucket, None, None, None)?;
87        return client.upload_from_path(local_path, uri);
88    }
89    if uri.starts_with("gs://") {
90        let location = storage::gcs::parse_gcs_uri(uri)?;
91        let client = storage::gcs::GcsClient::new(location.bucket)?;
92        return client.upload_from_path(local_path, uri);
93    }
94    if uri.starts_with("abfs://") {
95        let location = storage::adls::parse_adls_uri(uri)?;
96        let definition = StorageDefinition {
97            name: "manifest".to_string(),
98            fs_type: "adls".to_string(),
99            bucket: None,
100            region: None,
101            account: Some(location.account),
102            container: Some(location.container),
103            prefix: None,
104            endpoint: None,
105            path_style_access: None,
106        };
107        let client = storage::adls::AdlsClient::new(&definition)?;
108        return client.upload_from_path(local_path, uri);
109    }
110    Err(format!("unsupported manifest output uri: {uri}").into())
111}
112
113pub(crate) fn is_remote_uri(value: &str) -> bool {
114    value.starts_with("s3://") || value.starts_with("gs://") || value.starts_with("abfs://")
115}