xcodeproj/
lib.rs

1#![allow(dead_code)]
2#![deny(future_incompatible)]
3#![deny(nonstandard_style)]
4#![deny(missing_docs)]
5#![deny(rustdoc::broken_intra_doc_links)]
6#![doc = include_str!("../README.md")]
7
8use anyhow::Result;
9use pbxproj::PBXRootObject;
10use std::path::{Path, PathBuf};
11
12mod macros;
13pub mod pbxproj;
14mod scheme;
15pub mod xcode;
16pub use scheme::XCScheme;
17
18/// Main presentation of XCodeProject
19#[derive(Debug, Default, derive_deref_rs::Deref)]
20pub struct XCodeProject {
21    name: String,
22    root: PathBuf,
23    #[deref]
24    pbxproj: PBXRootObject,
25    schemes: Vec<XCScheme>,
26}
27
28impl XCodeProject {
29    // /xcshareddata/xcschemes
30    /// Create new XCodeProject object from xcodeproj_folder
31    pub fn new<P: AsRef<Path>>(xcodeproj_folder: P) -> Result<Self> {
32        let xcodeproj_folder = xcodeproj_folder.as_ref();
33        let name = xcodeproj_folder
34            .file_name()
35            .and_then(|name| Some(name.to_str()?.split_once(".")?.0.to_string()))
36            .unwrap();
37        let root = xcodeproj_folder.parent().unwrap().to_path_buf();
38        let mut schemes = vec![];
39        let xcworkspace_folder = root.join(format!("{name}.xcworkspace"));
40        let schemes_folder = xcworkspace_folder.join("xcshareddata").join("xcschemes");
41
42        // NOTE: Should xcodeproj folder be accounted for?
43        if schemes_folder.exists() {
44            let mut files = std::fs::read_dir(schemes_folder)?;
45            while let Some(Ok(entry)) = files.next() {
46                if let Ok(xcscheme) = XCScheme::new(entry.path()) {
47                    schemes.push(xcscheme);
48                }
49            }
50        }
51
52        let pbxproj = PBXRootObject::try_from(xcodeproj_folder.join("project.pbxproj"))?;
53
54        Ok(Self {
55            name,
56            root,
57            pbxproj,
58            schemes,
59        })
60    }
61
62    /// Get a reference to the xcode project's name.
63    #[must_use]
64    pub fn name(&self) -> &str {
65        self.name.as_ref()
66    }
67
68    /// Get a reference to the xcode project's root.
69    #[must_use]
70    pub fn root(&self) -> &PathBuf {
71        &self.root
72    }
73
74    /// Get a reference to the xcode project's pbxproj.
75    #[must_use]
76    pub fn pbxproj(&self) -> &PBXRootObject {
77        &self.pbxproj
78    }
79
80    /// Get build file names with all targets
81    pub fn build_file_names(&self) -> Vec<String> {
82        self.build_files()
83            .into_iter()
84            .flat_map(|f| {
85                let file = f.file.as_ref()?;
86                Some(file.path.or(file.name)?.to_string())
87            })
88            .collect::<Vec<_>>()
89    }
90
91    /// Get XCSchemes
92    pub fn schemes(&self) -> &[XCScheme] {
93        self.schemes.as_ref()
94    }
95}