spm_swift_package/presentation/
cli_controller.rs1use demand::{
2 DemandOption,
3 Input,
4 MultiSelect,
5 Spinner,
6 SpinnerStyle
7};
8use std::process::{exit, Command};
9use std::{thread::sleep, time::Duration};
10use colored::Colorize;
11
12use crate::domain::usecase::usecase::*;
13
14pub struct CliController;
15
16impl CliController {
17
18 pub async fn execute_flow() {
19 let project_name = Self::project_name_input();
20 let file_selected = Self::multiselect_files();
21 let platform_selected = Self::multiselect_platform();
22
23 Self::loading();
24 SpmUseCase::execute(&project_name, file_selected, platform_selected).await;
25 Self::command_open_xcode(project_name);
26 }
27
28 fn project_name_input() -> String {
31 let validation_empty = |s: &str| {
32 if s.is_empty() {
33 return Err("Library name cannot be empty");
34 }
35
36 Ok(())
37 };
38
39 let input = Input::new("Library name")
40 .placeholder("Enter the library name")
41 .prompt("Library: ")
42 .validation(validation_empty);
43
44 input.run().unwrap_or_else(|e| {
45 if e.kind() == std::io::ErrorKind::Interrupted {
46 println!("{}", e);
47 exit(0)
48 } else {
49 panic!("Error: {}", e);
50 }
51 })
52 }
53
54 fn multiselect_options(
55 prompt: &str,
56 description: &str,
57 options: &[&'static str],
58 ) -> Vec<&'static str> {
59 loop {
60 let mut multiselect = MultiSelect::new(prompt)
61 .description(description)
62 .filterable(true);
63
64 for &option in options {
65 multiselect = multiselect.option(DemandOption::new(option));
66 }
67
68 let result = match multiselect.run() {
69 Ok(selection) => selection,
70 Err(e) => {
71 if e.kind() == std::io::ErrorKind::Interrupted {
72 println!("Operation interrupted.");
73 exit(0);
74 } else {
75 panic!("Error: {}", e);
76 }
77 }
78 };
79
80 let selected: Vec<&str> = result
81 .iter()
82 .filter(|opt| !opt.is_empty())
83 .copied()
84 .collect();
85
86 if selected.is_empty() {
87 println!("{}", "You need to choose in order to follow".yellow());
88 continue;
89 }
90
91 return selected;
92 }
93 }
94
95 fn multiselect_files() -> Vec<&'static str> {
96 Self::multiselect_options(
97 "Add files",
98 "Do you want to add some of these files?",
99 &["Changelog", "Swift Package Index", "Readme", "SwiftLint with mise"]
100 )
101 }
102
103 fn multiselect_platform() -> Vec<&'static str> {
104 Self::multiselect_options(
105 "Choose platform",
106 "Which platform do you want to choose?",
107 &["iOS", "macOS", "tvOS", "watchOS", "visionOS"]
108 )
109 }
110
111 fn loading() {
112 Spinner::new("Building the Package...")
113 .style(&SpinnerStyle::line())
114 .run(|_| {
115 sleep(Duration::from_secs(5));
116 })
117 .expect("error running spinner");
118 }
119
120 fn command_open_xcode(project_name: String) {
121 let command = format!("cd {} && open Package.swift", project_name);
122 let mut child = Command::new("sh")
123 .arg("-c")
124 .arg(&command)
125 .spawn()
126 .expect("Failed to open Xcode");
127
128 child.wait().expect("Failed to wait on child");
129 }
130}