1use crate::{Formats, Verbosity, get_compose_filename};
2use colored::Colorize;
3use regex::Regex;
4use std::cmp::min;
5use std::ops::Add;
6use std::{fs, process};
7
8pub fn unwrap_filter_tag(filter: Option<&str>) -> Option<&str> {
11 filter.map(|f| {
12 if let Some(val) = f.strip_prefix("tag=") {
13 val
14 } else {
15 eprintln!(
16 "{}: wrong filter '{}', only '{}' filter supported",
17 "ERROR".red(),
18 f.yellow(),
19 "tag=".yellow()
20 );
21 process::exit(2);
22 }
23 })
24}
25
26pub fn unwrap_filter_regex(filter: Option<&str>) -> Option<(Regex, bool)> {
54 filter.as_ref().map(|f| {
55 if let Some(val) = f.strip_prefix("regex=") {
56 let regex = Regex::new(val).unwrap_or_else(|e| {
57 invalid_regex_exit(e, val);
58 });
59 return (regex, true);
60 }
61 if let Some(val) = f.strip_prefix("regex!=") {
62 let regex = Regex::new(val).unwrap_or_else(|e| {
63 invalid_regex_exit(e, val);
64 });
65 return (regex, false);
66 }
67 eprintln!(
68 "{}: wrong filter '{}', only '{}' or '{}' filters are supported",
69 "ERROR".red(),
70 f.yellow(),
71 "regex=".yellow(),
72 "regex!=".yellow()
73 );
74 process::exit(2);
75 })
76}
77
78fn invalid_regex_exit(e: regex::Error, val: &str) -> ! {
79 eprintln!(
80 "{}: invalid regex expression '{}' in filter - {}",
81 "ERROR".red(),
82 val.yellow(),
83 e
84 );
85 process::exit(2);
86}
87
88pub fn print_names<'a>(iter: impl Iterator<Item = &'a str>, pretty: Formats) {
89 match pretty {
90 Formats::Full => iter.for_each(|service| println!("{}", service)),
91 Formats::Oneline => println!(
92 "{}",
93 iter.fold(String::with_capacity(1024), |a, b| {
94 let s = if !a.is_empty() { a.add(" ") } else { a };
95 s.add(b)
96 }),
97 ),
98 }
99}
100
101pub fn print_service_not_found(service_not_found: &str) -> ! {
102 eprintln!(
103 "{}: No such service found: {}",
104 "ERROR".red(),
105 service_not_found.yellow()
106 );
107 process::exit(16);
108}
109
110pub fn print_services_not_found(not_found_list: Vec<String>) -> Vec<String> {
111 eprintln!(
112 "{}: No such service/s found: {}",
113 "ERROR".red(),
114 not_found_list
115 .iter()
116 .map(|s| s.as_str())
117 .collect::<Vec<_>>()
118 .join(" ")
119 .yellow()
120 );
121 process::exit(16);
122}
123
124pub fn get_yml_content(filename: Option<&str>, verbosity: Verbosity) -> String {
125 let filename = get_compose_filename(filename, verbosity).unwrap_or_else(|err| {
126 eprintln!("{}: {}", "ERROR".red(), err);
127 if err.contains("no such file or directory") {
128 process::exit(1);
129 }
130 process::exit(10);
131 });
132 fs::read_to_string(filename).unwrap_or_else(|err| {
133 eprintln!("{}: reading compose file: {}", "ERROR".red(), err);
134 process::exit(11);
135 })
136}
137
138pub fn get_slug(input: &str) -> String {
150 let text = input.trim();
151 let text = text.to_lowercase();
152 let len = min(text.len(), 63);
153 let mut result = String::with_capacity(len);
154
155 for c in text.chars() {
156 if result.len() >= len {
157 break;
158 }
159 if c.is_ascii_alphanumeric() || c == '.' {
160 result.push(c);
161 } else {
162 result.push('-');
163 }
164 }
165 result
166}