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_files() -> Vec<&'static str> {
55 loop {
56 let multiselect = MultiSelect::new("Add files")
57 .description("Do you want to add some of these files?")
58 .filterable(true)
59 .option(DemandOption::new("Changelog"))
60 .option(DemandOption::new("Swift Package Index"))
61 .option(DemandOption::new("Readme"))
62 .option(DemandOption::new("SwiftLint with mise"));
63
64 let result = match multiselect.run() {
65 Ok(selection) => selection,
66 Err(e) => {
67 if e.kind() == std::io::ErrorKind::Interrupted {
68 println!("Operation interrupted.");
69 exit(0);
70 } else {
71 panic!("Error: {}", e);
72 }
73 }
74 };
75
76 let selected: Vec<&str> = result
77 .iter()
78 .filter(|opt| !opt.is_empty())
79 .copied()
80 .collect();
81
82 if selected.is_empty() {
83 println!("{}", "You need to choose in order to follow".yellow());
84 continue;
85 }
86
87 return selected;
88 }
89 }
90
91 fn multiselect_platform() -> Vec<&'static str> {
92 loop {
93 let multiselect = MultiSelect::new("Choose platform")
94 .description("Which platform do you want to choose?")
95 .filterable(true)
96 .option(DemandOption::new("iOS"))
97 .option(DemandOption::new("macOS"))
98 .option(DemandOption::new("tvOS"))
99 .option(DemandOption::new("watchOS"))
100 .option(DemandOption::new("visionOS"));
101
102 let result = match multiselect.run() {
103 Ok(selection) => selection,
104 Err(e) => {
105 if e.kind() == std::io::ErrorKind::Interrupted {
106 println!("Operation interrupted.");
107 exit(0);
108 } else {
109 panic!("Error: {}", e);
110 }
111 }
112 };
113
114 let selected: Vec<&str> = result
115 .iter()
116 .filter(|opt| !opt.is_empty())
117 .copied()
118 .collect();
119
120 if selected.is_empty() {
121 println!("{}", "You need to choose in order to follow".yellow());
122 continue;
123 }
124
125 return selected;
126 }
127 }
128
129 fn loading() {
130 Spinner::new("Building the Package...")
131 .style(&SpinnerStyle::line())
132 .run(|_| {
133 sleep(Duration::from_secs(5));
134 })
135 .expect("error running spinner");
136 }
137
138 fn command_open_xcode(project_name: String) {
139 let command = format!("cd {} && open Package.swift", project_name);
140 let mut child = Command::new("sh")
141 .arg("-c")
142 .arg(&command)
143 .spawn()
144 .expect("Failed to open Xcode");
145
146 child.wait().expect("Failed to wait on child");
147 }
148}