|
| 1 | +use crate::error::{ForemanError, ForemanResult}; |
| 2 | +use semver::Version; |
| 3 | +use std::io::{Error, ErrorKind}; |
| 4 | + |
| 5 | +// Redundant operating systems that Foreman recognizes are not included; |
| 6 | +static VALID_OS: &[&str] = &["windows", "macos", "linux"]; |
| 7 | +static VALID_ARCH: &[&str] = &["x86_64", "arm64", "aarch64", "i686"]; |
| 8 | + |
| 9 | +pub fn generate_artifactory_path<S: Into<String>>( |
| 10 | + repo: S, |
| 11 | + tool_name: S, |
| 12 | + version: S, |
| 13 | + operating_system: S, |
| 14 | + architecture: Option<S>, |
| 15 | +) -> ForemanResult<String> { |
| 16 | + let repo = repo.into(); |
| 17 | + let tool_name = tool_name.into(); |
| 18 | + let version = version.into(); |
| 19 | + let operating_system = operating_system.into(); |
| 20 | + |
| 21 | + check_valid_os(&operating_system)?; |
| 22 | + check_valid_version(&version)?; |
| 23 | + let mut full_tool_name = format!("{}-{}-{}", tool_name, version, operating_system); |
| 24 | + if let Some(architecture) = architecture { |
| 25 | + let architecture = architecture.into(); |
| 26 | + check_valid_arch(&architecture)?; |
| 27 | + full_tool_name.push('-'); |
| 28 | + full_tool_name.push_str(&architecture); |
| 29 | + } |
| 30 | + |
| 31 | + full_tool_name.push_str(".zip"); |
| 32 | + |
| 33 | + Ok(format!( |
| 34 | + "artifactory/{}/{}/{}/{}", |
| 35 | + repo, tool_name, version, full_tool_name |
| 36 | + )) |
| 37 | +} |
| 38 | + |
| 39 | +fn check_valid_os(operating_system: &str) -> ForemanResult<()> { |
| 40 | + if !VALID_OS.contains(&operating_system) { |
| 41 | + return Err(ForemanError::io_error_with_context( |
| 42 | + Error::new(ErrorKind::InvalidInput, "Invalid Argument"), |
| 43 | + format!( |
| 44 | + "Invalid operating system: {}. Please input a valid operating system: {}", |
| 45 | + operating_system, |
| 46 | + VALID_OS.join(", ") |
| 47 | + ), |
| 48 | + )); |
| 49 | + } else { |
| 50 | + Ok(()) |
| 51 | + } |
| 52 | +} |
| 53 | + |
| 54 | +fn check_valid_arch(architecture: &str) -> ForemanResult<()> { |
| 55 | + if !VALID_ARCH.contains(&architecture) { |
| 56 | + return Err(ForemanError::io_error_with_context( |
| 57 | + Error::new(ErrorKind::InvalidInput, "Invalid Argument"), |
| 58 | + format!( |
| 59 | + "Invalid architecture: {}. Please input a valid architecture: {}", |
| 60 | + architecture, |
| 61 | + VALID_ARCH.join(", ") |
| 62 | + ), |
| 63 | + )); |
| 64 | + } else { |
| 65 | + Ok(()) |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +fn check_valid_version(version: &str) -> ForemanResult<()> { |
| 70 | + if !version.starts_with('v') { |
| 71 | + return Err(ForemanError::io_error_with_context( |
| 72 | + Error::new(ErrorKind::InvalidInput, "Invalid Argument"), |
| 73 | + format!("Invalid version: {}. Versions must start with a v", version), |
| 74 | + )); |
| 75 | + } |
| 76 | + |
| 77 | + if let Err(err) = Version::parse(&version[1..]) { |
| 78 | + Err(ForemanError::io_error_with_context( |
| 79 | + Error::new(ErrorKind::InvalidInput, "Invalid Argument"), |
| 80 | + format!("Invalid version: {}. Error: {}", version, err), |
| 81 | + )) |
| 82 | + } else { |
| 83 | + Ok(()) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +#[cfg(test)] |
| 88 | +mod test { |
| 89 | + use super::generate_artifactory_path; |
| 90 | + |
| 91 | + #[test] |
| 92 | + fn simple_path() { |
| 93 | + let path = generate_artifactory_path("repo", "tool_name", "v0.1.0", "macos", None).unwrap(); |
| 94 | + assert_eq!( |
| 95 | + path, |
| 96 | + "artifactory/repo/tool_name/v0.1.0/tool_name-v0.1.0-macos.zip" |
| 97 | + ); |
| 98 | + } |
| 99 | + |
| 100 | + #[test] |
| 101 | + fn simple_path_with_arch() { |
| 102 | + let path = generate_artifactory_path("repo", "tool_name", "v0.1.0", "macos", Some("arm64")) |
| 103 | + .unwrap(); |
| 104 | + assert_eq!( |
| 105 | + path, |
| 106 | + "artifactory/repo/tool_name/v0.1.0/tool_name-v0.1.0-macos-arm64.zip" |
| 107 | + ); |
| 108 | + } |
| 109 | + |
| 110 | + #[test] |
| 111 | + fn invalid_version_no_v() { |
| 112 | + let path = generate_artifactory_path("repo", "tool_name", "0.1.0", "macos", Some("arm64")) |
| 113 | + .unwrap_err(); |
| 114 | + assert_eq!( |
| 115 | + path.to_string(), |
| 116 | + "Invalid version: 0.1.0. Versions must start with a v: Invalid Argument".to_string() |
| 117 | + ); |
| 118 | + } |
| 119 | + #[test] |
| 120 | + fn invalid_version_incomplete() { |
| 121 | + let path = generate_artifactory_path("repo", "tool_name", "v0.1", "macos", Some("arm64")) |
| 122 | + .unwrap_err(); |
| 123 | + assert_eq!( |
| 124 | + path.to_string(), |
| 125 | + "Invalid version: v0.1. Error: unexpected end of input while parsing minor version number: Invalid Argument".to_string() |
| 126 | + ); |
| 127 | + } |
| 128 | + |
| 129 | + #[test] |
| 130 | + fn invalid_operating_system() { |
| 131 | + let path = |
| 132 | + generate_artifactory_path("repo", "tool_name", "v0.1.0", "fake_os", Some("arm64")) |
| 133 | + .unwrap_err(); |
| 134 | + assert_eq!( |
| 135 | + path.to_string(), |
| 136 | + "Invalid operating system: fake_os. Please input a valid operating system: windows, macos, linux: Invalid Argument".to_string() |
| 137 | + ); |
| 138 | + } |
| 139 | + |
| 140 | + #[test] |
| 141 | + fn invalid_architecture() { |
| 142 | + let path = |
| 143 | + generate_artifactory_path("repo", "tool_name", "v0.1.0", "macos", Some("fake_arch")) |
| 144 | + .unwrap_err(); |
| 145 | + assert_eq!( |
| 146 | + path.to_string(), |
| 147 | + "Invalid architecture: fake_arch. Please input a valid architecture: x86_64, arm64, aarch64, i686: Invalid Argument".to_string() |
| 148 | + ); |
| 149 | + } |
| 150 | +} |
0 commit comments