apple_sdk/
simple_sdk.rs

1// Copyright 2022 Gregory Szorc.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use {
10    crate::{AppleSdk, Error, Platform, SdkPath, SdkVersion},
11    std::path::{Path, PathBuf},
12};
13
14#[cfg(feature = "parse")]
15use crate::parsed_sdk::ParsedSdk;
16
17/// A directory purported to hold an Apple SDK.
18#[derive(Clone, Debug)]
19pub struct SimpleSdk {
20    /// Root directory of the SDK.
21    path: PathBuf,
22
23    /// Whether the root directory is a symlink to another path.
24    is_symlink: bool,
25
26    sdk_path: SdkPath,
27}
28
29impl AsRef<Path> for SimpleSdk {
30    fn as_ref(&self) -> &Path {
31        &self.path
32    }
33}
34
35impl AppleSdk for SimpleSdk {
36    fn from_directory(path: &Path) -> Result<Self, Error> {
37        let sdk = SdkPath::from_path(path)?;
38
39        // Need to call symlink_metadata so symlinks aren't followed.
40        let metadata = std::fs::symlink_metadata(path)?;
41
42        let is_symlink = metadata.file_type().is_symlink();
43
44        let json_path = path.join("SDKSettings.json");
45        let plist_path = path.join("SDKSettings.plist");
46
47        if json_path.exists() || plist_path.exists() {
48            Ok(Self {
49                path: path.to_path_buf(),
50                is_symlink,
51                sdk_path: sdk,
52            })
53        } else {
54            Err(Error::PathNotSdk(path.to_path_buf()))
55        }
56    }
57
58    fn is_symlink(&self) -> bool {
59        self.is_symlink
60    }
61
62    fn platform(&self) -> &Platform {
63        &self.sdk_path.platform
64    }
65
66    fn version(&self) -> Option<&SdkVersion> {
67        self.sdk_path.version.as_ref()
68    }
69
70    fn supports_deployment_target(
71        &self,
72        _target_name: &str,
73        _target_version: &SdkVersion,
74    ) -> Result<bool, Error> {
75        Err(Error::FunctionalityNotSupported(
76            "evaluating deployment target support on UnparsedSdk instances",
77        ))
78    }
79}
80
81impl SimpleSdk {
82    #[cfg(feature = "parse")]
83    /// Attempt to convert into an [AppleSdk] by parsing an `SDKSettings.*` file.
84    pub fn try_parse(self) -> Result<ParsedSdk, Error> {
85        self.try_into()
86    }
87}
88
89#[cfg(test)]
90mod test {
91    use {
92        super::*,
93        crate::{DeveloperDirectory, COMMAND_LINE_TOOLS_DEFAULT_PATH},
94    };
95
96    #[test]
97    fn find_default_sdks() -> Result<(), Error> {
98        if let Ok(developer_dir) = DeveloperDirectory::find_default_required() {
99            assert!(!developer_dir.sdks::<SimpleSdk>()?.is_empty());
100        }
101
102        Ok(())
103    }
104
105    #[test]
106    fn find_command_line_tools_sdks() -> Result<(), Error> {
107        let sdk_path = PathBuf::from(COMMAND_LINE_TOOLS_DEFAULT_PATH).join("SDKs");
108
109        let res = SimpleSdk::find_command_line_tools_sdks()?;
110
111        if sdk_path.exists() {
112            assert!(res.is_some());
113            assert!(!res.unwrap().is_empty());
114        } else {
115            assert!(res.is_none());
116        }
117
118        Ok(())
119    }
120
121    #[test]
122    fn find_all_sdks() -> Result<(), Error> {
123        for dir in DeveloperDirectory::find_system_xcodes()? {
124            for sdk in dir.sdks::<SimpleSdk>()? {
125                assert!(!matches!(sdk.platform(), Platform::Unknown(_)));
126            }
127        }
128
129        Ok(())
130    }
131}