spm_swift_package/domain/file/
project_file.rs

1use std::{
2	fs,
3	io::Write,
4	path::{Path, PathBuf},
5};
6
7use crate::domain::file::project_templates::*;
8
9/// Convenience alias for results that return a String error
10type Result<T> = std::result::Result<T, String>;
11
12/// Converts a path into a displayable String
13fn display<P: AsRef<Path>>(p: P) -> String {
14	p.as_ref().display().to_string()
15}
16
17/// Handles creation of all project files and folders
18pub struct ProjectFile;
19
20impl ProjectFile {
21	/// Creates the main Swift module directory and source file
22	pub fn create_project(project_name: &str) -> Result<()> {
23		let module_dir = Self::module_dir(project_name);
24		Self::create_dir(&module_dir)?;
25
26		let content = ProjectTemplates::project_swift_content();
27		let file_path = module_dir.join(format!("{name}.swift", name = project_name));
28		Self::write_file(&file_path, &content)
29	}
30
31	/// Creates the tests folder and the main test file
32	pub fn create_test_folder(project_name: &str) -> Result<()> {
33		let tests_dir = Self::tests_dir(project_name);
34		Self::create_dir(&tests_dir)?;
35
36		let content = ProjectTemplates::test_content(project_name);
37		let file_path = tests_dir.join(format!("{name}Tests.swift", name = project_name));
38		Self::write_file(&file_path, &content)
39	}
40
41	/// Creates the Package.swift file with the configured template
42	pub fn create_package(
43		project_name: &str,
44		platform: &str,
45		version: &str,
46		is_plugin: bool,
47	) -> Result<()> {
48		let content =
49			ProjectTemplates::package_swift_content(project_name, platform, version, is_plugin);
50		Self::create_root_file(project_name, "Package.swift", content)
51	}
52
53	/// Creates the CHANGELOG.md file in the project root
54	pub fn create_changelog(project_name: &str) -> Result<()> {
55		let content = ProjectTemplates::changelog_content();
56		Self::create_root_file(project_name, "CHANGELOG.md", content)
57	}
58
59	/// Creates the README.md file in the project root
60	pub fn create_readme(project_name: &str) -> Result<()> {
61		let content = ProjectTemplates::readme_content(project_name);
62		Self::create_root_file(project_name, "README.md", content)
63	}
64
65	/// Creates the .spi.yml file used by Swift Package Index
66	pub fn create_spi(project_name: &str) -> Result<()> {
67		let content = ProjectTemplates::spi_content(project_name);
68		Self::create_root_file(project_name, ".spi.yml", content)
69	}
70
71	/// Creates the .swiftlint.yml configuration file
72	pub fn create_swiftlint(project_name: &str) -> Result<()> {
73		let content = ProjectTemplates::swiftlint_content();
74		Self::create_root_file(project_name, ".swiftlint.yml", content)
75	}
76
77	/// Private methods
78
79	/// Returns the path for the module Sources directory
80	fn module_dir(project_name: &str) -> PathBuf {
81		Path::new(project_name).join("Sources").join(project_name)
82	}
83
84	/// Returns the path for the Tests directory of the project
85	fn tests_dir(project_name: &str) -> PathBuf {
86		Path::new(project_name)
87			.join("Tests")
88			.join(format!("{name}Tests", name = project_name))
89	}
90
91	/// Creates a file in the project root with the given content
92	fn create_root_file(project_name: &str, filename: &str, content: String) -> Result<()> {
93		let root = Path::new(project_name);
94		Self::create_dir(root)?;
95		let file_path = root.join(filename);
96		Self::write_file(&file_path, &content)
97	}
98
99	/// Creates a directory and all missing parent directories
100	fn create_dir<P: AsRef<Path>>(path: P) -> Result<()> {
101		fs::create_dir_all(&path)
102			.map_err(|e| format!("Error creating directory '{}': {}", display(path), e))
103	}
104
105	/// Writes content to a file, overwriting any existing content
106	fn write_file<P: AsRef<Path>>(path: P, content: &str) -> Result<()> {
107		let mut file = fs::File::create(&path)
108			.map_err(|e| format!("Error creating file '{}': {}", display(&path), e))?;
109		file
110			.write_all(content.as_bytes())
111			.map_err(|e| format!("Error writing to file '{}': {}", display(&path), e))
112	}
113}