1pub(crate) mod crateinfo;
7
8#[cfg(test)]
9#[path = "mod_test.rs"]
10mod mod_test;
11
12use crate::command;
13use crate::condition;
14use crate::error::CargoMakeError;
15use crate::io;
16use crate::profile;
17use crate::scriptengine;
18use crate::time_summary;
19use crate::types::{
20 CliArgs, Config, CrateInfo, EnvFile, EnvInfo, EnvValue, EnvValueConditioned, EnvValueDecode,
21 EnvValuePathGlob, EnvValueScript, PackageInfo, ScriptValue, Step, Task, Workspace,
22};
23use ci_info::types::CiInfo;
24use envmnt::{ExpandOptions, ExpansionType};
25use fsio::path::from_path::FromPath;
26use git_info::types::GitInfo;
27use indexmap::IndexMap;
28use rust_info::types::{RustChannel, RustInfo};
29use std::env;
30use std::path::{Path, PathBuf};
31use std::time::SystemTime;
32
33fn evaluate_env_value(key: &str, env_value: &EnvValueScript) -> String {
34 match command::run_script_get_output(&env_value.script, None, &vec![], true, Some(false)) {
35 Ok(output) => {
36 let exit_code = output.0;
37 let stdout = output.1;
38 let stderr = output.2;
39
40 if exit_code != 0 {
41 error!(
42 concat!(
43 "Error while evaluating script for env: {}, exit code: {}\n",
44 "Script:\n{:#?}\n",
45 "Stdout:\n{}\n",
46 "Stderr:\n{}\n"
47 ),
48 key, exit_code, env_value.script, &stdout, &stderr
49 );
50 }
51
52 debug!("Env script stdout:\n{}", &stdout);
53
54 let multi_line = match env_value.multi_line {
55 Some(bool_value) => bool_value,
56 None => false,
57 };
58
59 if multi_line {
60 stdout.to_string()
61 } else {
62 let mut lines: Vec<&str> = stdout.split("\n").collect();
63 lines.retain(|&line| line.len() > 0);
64
65 if lines.len() > 0 {
66 let line = lines[lines.len() - 1].to_string();
67
68 let line_str = str::replace(&line, "\r", "");
69
70 line_str.to_string()
71 } else {
72 "".to_string()
73 }
74 }
75 }
76 _ => "".to_string(),
77 }
78}
79
80pub(crate) fn expand_value(value: &str) -> String {
81 let mut options = ExpandOptions::new();
82 options.expansion_type = Some(ExpansionType::UnixBracketsWithDefaults);
83 options.default_to_empty = false;
84
85 envmnt::expand(&value, Some(options))
86}
87
88fn evaluate_and_set_env(key: &str, value: &str) {
89 let env_value = expand_value(&value);
90
91 debug!("Setting Env: {} Value: {}", &key, &env_value);
92 envmnt::set(&key, &env_value);
93}
94
95fn set_env_for_bool(key: &str, value: bool) {
96 debug!("Setting Env: {} Value: {}", &key, &value);
97 envmnt::set_bool(&key, value);
98}
99
100fn set_env_for_list(key: &str, list: &Vec<String>) {
101 let mut expanded_list = vec![];
102
103 for value in list {
104 let env_value = expand_value(&value);
105 expanded_list.push(env_value);
106 }
107
108 envmnt::set_list(&key, &expanded_list);
109}
110
111fn set_env_for_script(key: &str, env_value: &EnvValueScript) {
112 let valid = match env_value.condition {
113 Some(ref condition) => condition::validate_conditions_without_context(condition.clone()),
114 None => true,
115 };
116
117 if valid {
118 let value = evaluate_env_value(&key, &env_value);
119
120 evaluate_and_set_env(&key, &value);
121 }
122}
123
124fn set_env_for_decode_info(key: &str, decode_info: &EnvValueDecode) {
125 let valid = match decode_info.condition {
126 Some(ref condition) => condition::validate_conditions_without_context(condition.clone()),
127 None => true,
128 };
129
130 if valid {
131 let source_value = expand_value(&decode_info.source);
132
133 let mapped_value = match decode_info.mapping.get(&source_value) {
134 Some(value) => value.to_string(),
135 None => match decode_info.default_value {
136 Some(ref value) => value.clone().to_string(),
137 None => source_value.clone(),
138 },
139 };
140
141 evaluate_and_set_env(&key, &mapped_value);
142 }
143}
144
145fn set_env_for_conditional_value(key: &str, conditional_value: &EnvValueConditioned) {
146 let valid = match conditional_value.condition {
147 Some(ref condition) => condition::validate_conditions_without_context(condition.clone()),
148 None => true,
149 };
150
151 if valid {
152 let value = expand_value(&conditional_value.value);
153
154 evaluate_and_set_env(&key, &value);
155 }
156}
157
158fn set_env_for_path_glob(key: &str, path_glob: &EnvValuePathGlob) {
159 let path_list = io::get_path_list(
160 &path_glob.glob,
161 path_glob.include_files.unwrap_or(true),
162 path_glob.include_dirs.unwrap_or(true),
163 path_glob.ignore_type.clone(),
164 );
165
166 set_env_for_list(key, &path_list);
167}
168
169fn set_env_for_profile(
170 profile_name: &str,
171 sub_env: &IndexMap<String, EnvValue>,
172 additional_profiles: Option<&Vec<String>>,
173) {
174 let current_profile_name = profile::get();
175 let profile_name_string = profile_name.to_string();
176
177 let found = match additional_profiles {
178 Some(profiles) => profiles.contains(&profile_name_string),
179 None => false,
180 };
181
182 if current_profile_name == profile_name_string || found {
183 debug!("Setting Up Profile: {} Env.", &profile_name);
184
185 set_env_for_config(sub_env.clone(), None, false);
186 }
187}
188
189pub(crate) fn set_env(env: IndexMap<String, EnvValue>) {
191 set_env_for_config(env, None, true)
192}
193
194fn unset_env(key: &str) {
195 envmnt::remove(key);
196}
197
198pub(crate) fn set_env_for_config(
200 env: IndexMap<String, EnvValue>,
201 additional_profiles: Option<&Vec<String>>,
202 allow_sub_env: bool,
203) {
204 debug!("Setting Up Env.");
205
206 for (key, env_value) in &env {
207 debug!("Setting env: {} = {:#?}", &key, &env_value);
208
209 match *env_value {
210 EnvValue::Value(ref value) => evaluate_and_set_env(&key, value),
211 EnvValue::Boolean(value) => set_env_for_bool(&key, value),
212 EnvValue::Number(value) => evaluate_and_set_env(&key, &value.to_string()),
213 EnvValue::List(ref value) => set_env_for_list(&key, value),
214 EnvValue::Script(ref script_info) => set_env_for_script(&key, script_info),
215 EnvValue::Decode(ref decode_info) => set_env_for_decode_info(&key, decode_info),
216 EnvValue::Conditional(ref conditioned_value) => {
217 set_env_for_conditional_value(&key, conditioned_value)
218 }
219 EnvValue::PathGlob(ref path_glob_info) => set_env_for_path_glob(&key, path_glob_info),
220 EnvValue::Profile(ref sub_env) => {
221 if allow_sub_env {
222 set_env_for_profile(&key, sub_env, additional_profiles)
223 }
224 }
225 EnvValue::Unset(ref value) => {
226 if value.unset {
227 unset_env(&key);
228 }
229 }
230 };
231 }
232
233 if allow_sub_env {
234 let profile_name = profile::get();
235
236 if env.contains_key(&profile_name) {
237 match env.get(&profile_name) {
238 Some(ref env_value) => {
239 match *env_value {
240 EnvValue::Profile(ref sub_env) => {
241 set_env_for_profile(&profile_name, sub_env, None)
242 }
243 _ => (),
244 };
245 }
246 None => (),
247 };
248 }
249 }
250}
251
252pub(crate) fn set_env_files(env_files: Vec<EnvFile>) {
253 set_env_files_for_config(env_files, None);
254}
255
256fn set_env_files_for_config(
257 env_files: Vec<EnvFile>,
258 additional_profiles: Option<&Vec<String>>,
259) -> bool {
260 let mut all_loaded = true;
261 for env_file in env_files {
262 let loaded = match env_file {
263 EnvFile::Path(file) => load_env_file(Some(file)),
264 EnvFile::Info(info) => {
265 let is_valid_profile = match info.profile {
266 Some(profile_name) => {
267 let current_profile_name = profile::get();
268
269 let found = match additional_profiles {
270 Some(profiles) => profiles.contains(&profile_name),
271 None => false,
272 };
273
274 current_profile_name == profile_name || found
275 }
276 None => true,
277 };
278
279 if is_valid_profile {
280 load_env_file_with_base_directory(
281 Some(info.path),
282 info.base_path,
283 info.defaults_only.unwrap_or(false),
284 )
285 } else {
286 false
287 }
288 }
289 };
290
291 all_loaded = all_loaded && loaded;
292 }
293
294 all_loaded
295}
296
297fn set_env_scripts(
298 env_scripts: Vec<String>,
299 cli_arguments: &Vec<String>,
300) -> Result<(), CargoMakeError> {
301 for env_script in env_scripts {
302 if !env_script.is_empty() {
303 scriptengine::invoke_script_pre_flow(
304 &ScriptValue::Text(vec![env_script]),
305 None,
306 None,
307 None,
308 true,
309 cli_arguments,
310 )?;
311 }
312 }
313 Ok(())
314}
315
316pub(crate) fn set_current_task_meta_info_env(env: IndexMap<String, EnvValue>) {
317 debug!("Setting Up Env.");
318
319 for (key, env_value) in &env {
320 if key.starts_with("CARGO_MAKE_CURRENT_TASK_") {
321 debug!("Setting env: {} = {:#?}", &key, &env_value);
322
323 match *env_value {
324 EnvValue::Value(ref value) => evaluate_and_set_env(&key, value),
325 _ => (),
326 };
327 }
328 }
329}
330
331fn initialize_env(config: &Config, cli_args: &Vec<String>) -> Result<(), CargoMakeError> {
333 debug!("Initializing Env.");
334
335 let additional_profiles = match config.config.additional_profiles {
336 Some(ref profiles) => Some(profiles),
337 None => None,
338 };
339
340 set_env_files_for_config(config.env_files.clone(), additional_profiles);
341
342 set_env_for_config(config.env.clone(), additional_profiles, true);
343
344 set_env_scripts(config.env_scripts.clone(), cli_args)
345}
346
347fn setup_env_for_duckscript() {
348 let mut version = duckscript::version();
349 envmnt::set("CARGO_MAKE_DUCKSCRIPT_VERSION", version);
350
351 version = duckscriptsdk::version();
352 envmnt::set("CARGO_MAKE_DUCKSCRIPT_SDK_VERSION", version);
353}
354
355fn setup_env_for_crate(home: Option<PathBuf>) -> Result<CrateInfo, CargoMakeError> {
356 let crate_info = crateinfo::load()?;
357 let crate_info_clone = crate_info.clone();
358
359 let package_info = crate_info.package.unwrap_or(PackageInfo::new());
360
361 if package_info.name.is_some() {
362 let crate_name = package_info.name.unwrap();
363 envmnt::set("CARGO_MAKE_CRATE_NAME", &crate_name);
364
365 let crate_fs_name = str::replace(&crate_name, "-", "_");
366 envmnt::set("CARGO_MAKE_CRATE_FS_NAME", &crate_fs_name);
367 }
368
369 envmnt::set_optional("CARGO_MAKE_CRATE_VERSION", &package_info.version);
370 envmnt::set_optional("CARGO_MAKE_CRATE_DESCRIPTION", &package_info.description);
371 envmnt::set_optional("CARGO_MAKE_CRATE_LICENSE", &package_info.license);
372 envmnt::set_optional(
373 "CARGO_MAKE_CRATE_DOCUMENTATION",
374 &package_info.documentation,
375 );
376 envmnt::set_optional("CARGO_MAKE_CRATE_HOMEPAGE", &package_info.homepage);
377 envmnt::set_optional("CARGO_MAKE_CRATE_REPOSITORY", &package_info.repository);
378
379 let has_dependencies = match crate_info.dependencies {
380 Some(ref dependencies) => dependencies.len() > 0,
381 None => crate_info.workspace.is_some(),
382 };
383
384 envmnt::set_bool("CARGO_MAKE_CRATE_HAS_DEPENDENCIES", has_dependencies);
385
386 let is_workspace = !crate_info.workspace.is_none();
387 envmnt::set_bool("CARGO_MAKE_CRATE_IS_WORKSPACE", is_workspace);
388 if is_workspace {
389 envmnt::set_bool("CARGO_MAKE_USE_WORKSPACE_PROFILE", true);
390 } else if !envmnt::exists("CARGO_MAKE_CRATE_CURRENT_WORKSPACE_MEMBER")
391 || envmnt::exists("CARGO_MAKE_WORKSPACE_EMULATION_ROOT_DIRECTORY")
392 {
393 search_and_set_workspace_cwd();
397 }
398
399 let workspace = crate_info.workspace.unwrap_or(Workspace::new());
400 let members = workspace.members.unwrap_or(vec![]);
401 let mut env_options = envmnt::ListOptions::new();
402 env_options.separator = Some(",".to_string());
403 envmnt::set_list_with_options("CARGO_MAKE_CRATE_WORKSPACE_MEMBERS", &members, &env_options);
404
405 if let Some(package) = workspace.package.as_ref() {
406 envmnt::set_optional("CARGO_MAKE_WORKSPACE_PACKAGE_NAME", &package.name);
407 envmnt::set_optional("CARGO_MAKE_WORKSPACE_PACKAGE_VERSION", &package.version);
408 envmnt::set_optional(
409 "CARGO_MAKE_WORKSPACE_PACKAGE_DESCRIPTION",
410 &package.description,
411 );
412 envmnt::set_optional("CARGO_MAKE_WORKSPACE_PACKAGE_LICENSE", &package.license);
413 envmnt::set_optional(
414 "CARGO_MAKE_WORKSPACE_PACKAGE_DOCUMENTATION",
415 &package.documentation,
416 );
417 envmnt::set_optional("CARGO_MAKE_WORKSPACE_PACKAGE_HOMEPAGE", &package.homepage);
418 envmnt::set_optional(
419 "CARGO_MAKE_WORKSPACE_PACKAGE_REPOSITORY",
420 &package.repository,
421 );
422 }
423
424 let lock_file = Path::new("Cargo.lock");
426 let lock_file_exists = lock_file.exists();
427 envmnt::set_bool("CARGO_MAKE_CRATE_LOCK_FILE_EXISTS", lock_file_exists);
428
429 let crate_target_dirs = crateinfo::crate_target_dirs(home);
430 envmnt::set("CARGO_MAKE_CRATE_TARGET_DIRECTORY", &crate_target_dirs.host);
431 match crate_target_dirs.custom {
432 Some(ref value) => envmnt::set("CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY", value),
433 None => envmnt::set(
434 "CARGO_MAKE_CRATE_CUSTOM_TRIPLE_TARGET_DIRECTORY",
435 &crate_target_dirs.host,
436 ),
437 }
438
439 Ok(crate_info_clone)
440}
441
442fn setup_env_for_git_repo() -> GitInfo {
443 let info = git_info::get();
444 let git_info_clone = info.clone();
445
446 envmnt::set_optional("CARGO_MAKE_GIT_BRANCH", &info.current_branch);
447 envmnt::set_optional("CARGO_MAKE_GIT_USER_NAME", &info.user_name);
448 envmnt::set_optional("CARGO_MAKE_GIT_USER_EMAIL", &info.user_email);
449 envmnt::set_optional(
450 "CARGO_MAKE_GIT_HEAD_LAST_COMMIT_HASH",
451 &info.head.last_commit_hash,
452 );
453 envmnt::set_optional(
454 "CARGO_MAKE_GIT_HEAD_LAST_COMMIT_HASH_PREFIX",
455 &info.head.last_commit_hash_short,
456 );
457
458 git_info_clone
459}
460
461fn setup_env_for_rust(home: Option<PathBuf>) -> RustInfo {
462 let rustinfo = rust_info::get();
463 let rust_info_clone = rustinfo.clone();
464
465 envmnt::set_optional("CARGO_MAKE_RUST_VERSION", &rustinfo.version);
466
467 if let Some(channel_option) = rustinfo.channel {
468 let channel = match channel_option {
469 RustChannel::Stable => "stable",
470 RustChannel::Beta => "beta",
471 RustChannel::Nightly => "nightly",
472 };
473
474 envmnt::set("CARGO_MAKE_RUST_CHANNEL", channel);
475 }
476
477 envmnt::set(
478 "CARGO_MAKE_RUST_TARGET_ARCH",
479 &rustinfo.target_arch.unwrap_or("unknown".to_string()),
480 );
481 envmnt::set(
482 "CARGO_MAKE_RUST_TARGET_ENV",
483 &rustinfo.target_env.unwrap_or("unknown".to_string()),
484 );
485 envmnt::set(
486 "CARGO_MAKE_RUST_TARGET_OS",
487 &rustinfo.target_os.unwrap_or("unknown".to_string()),
488 );
489 envmnt::set(
490 "CARGO_MAKE_RUST_TARGET_POINTER_WIDTH",
491 &rustinfo
492 .target_pointer_width
493 .unwrap_or("unknown".to_string()),
494 );
495 envmnt::set(
496 "CARGO_MAKE_RUST_TARGET_VENDOR",
497 &rustinfo.target_vendor.unwrap_or("unknown".to_string()),
498 );
499 envmnt::set_optional("CARGO_MAKE_RUST_TARGET_TRIPLE", &rustinfo.target_triple);
500 envmnt::set_or_remove(
501 "CARGO_MAKE_CRATE_TARGET_TRIPLE",
502 &crateinfo::crate_target_triple(rustinfo.target_triple, home.clone()),
503 );
504
505 rust_info_clone
506}
507
508fn setup_env_for_ci() -> CiInfo {
509 let ci_info_struct = ci_info::get();
510
511 envmnt::set_bool("CARGO_MAKE_CI", ci_info_struct.ci);
512 envmnt::set_bool("CARGO_MAKE_PR", ci_info_struct.pr.unwrap_or(false));
513 envmnt::set_optional("CARGO_MAKE_CI_BRANCH_NAME", &ci_info_struct.branch_name);
514 envmnt::set_optional("CARGO_MAKE_CI_VENDOR", &ci_info_struct.name);
515
516 ci_info_struct
517}
518
519fn get_base_directory_name() -> Option<String> {
520 match env::current_dir() {
521 Ok(path) => match path.file_name() {
522 Some(name) => Some(name.to_string_lossy().into_owned()),
523 None => None,
524 },
525 _ => None,
526 }
527}
528
529fn setup_env_for_project(config: &Config, crate_info: &CrateInfo) -> Result<(), CargoMakeError> {
530 let project_name = match crate_info.package {
531 Some(ref package) => match package.name {
532 Some(ref name) => Some(name.to_string()),
533 None => get_base_directory_name(),
534 },
535 None => get_base_directory_name(),
536 };
537
538 envmnt::set_or_remove("CARGO_MAKE_PROJECT_NAME", &project_name);
539
540 let project_version = match crate_info.workspace {
541 Some(_) => {
542 let main_member = match config.config.main_project_member {
543 Some(ref name) => Some(name.to_string()),
544 None => match project_name {
545 Some(name) => Some(name),
546 None => None,
547 },
548 };
549
550 envmnt::set_or_remove("CARGO_MAKE_PROJECT_VERSION_MEMBER", &main_member);
551
552 match main_member {
553 Some(member) => {
554 let mut path = PathBuf::new();
555 path.push(member);
556 path.push("Cargo.toml");
557 let member_crate_info = crateinfo::load_from(path)?;
558
559 match member_crate_info.package {
560 Some(package) => package.version,
561 None => None,
562 }
563 }
564 None => None,
565 }
566 }
567 None => match crate_info.package {
568 Some(ref package) => package.version.clone(),
569 None => None,
570 },
571 };
572
573 envmnt::set_or_remove("CARGO_MAKE_PROJECT_VERSION", &project_version);
574
575 Ok(())
576}
577
578pub(crate) fn setup_env(
580 cli_args: &CliArgs,
581 config: &Config,
582 task: &str,
583 home: Option<PathBuf>,
584 time_summary_vec: &mut Vec<(String, u128)>,
585) -> Result<EnvInfo, CargoMakeError> {
586 envmnt::set_bool("CARGO_MAKE", true);
587 envmnt::set("CARGO_MAKE_TASK", &task);
588
589 envmnt::set("CARGO_MAKE_COMMAND", &cli_args.command);
590
591 let task_arguments = match cli_args.arguments.clone() {
592 Some(args) => args,
593 None => vec![],
594 };
595 envmnt::set_list("CARGO_MAKE_TASK_ARGS", &task_arguments);
596
597 let mut now = SystemTime::now();
599 setup_env_for_duckscript();
600 time_summary::add(time_summary_vec, "[Setup Env - Duckscript]", now);
601
602 now = SystemTime::now();
604 let crate_info = if config.config.skip_crate_env_info.unwrap_or(false) {
605 CrateInfo::new()
606 } else {
607 setup_env_for_crate(home.clone())?
608 };
609 time_summary::add(time_summary_vec, "[Setup Env - Crate Info]", now);
610
611 now = SystemTime::now();
613 let gitinfo = if config.config.skip_git_env_info.unwrap_or(false) {
614 GitInfo::new()
615 } else {
616 setup_env_for_git_repo()
617 };
618 time_summary::add(time_summary_vec, "[Setup Env - Git]", now);
619
620 now = SystemTime::now();
622 let rustinfo = if config.config.skip_rust_env_info.unwrap_or(false) {
623 RustInfo::new()
624 } else {
625 setup_env_for_rust(home)
626 };
627 time_summary::add(time_summary_vec, "[Setup Env - Rust]", now);
628
629 now = SystemTime::now();
631 let ci_info_struct = setup_env_for_ci();
632 time_summary::add(time_summary_vec, "[Setup Env - CI]", now);
633
634 now = SystemTime::now();
636 setup_env_for_project(config, &crate_info)?;
637 time_summary::add(time_summary_vec, "[Setup Env - Project]", now);
638
639 now = SystemTime::now();
641 initialize_env(config, &cli_args.arguments.clone().unwrap_or(vec![]))?;
642 time_summary::add(time_summary_vec, "[Setup Env - Vars]", now);
643
644 Ok(EnvInfo {
645 rust_info: rustinfo,
646 crate_info,
647 git_info: gitinfo,
648 ci_info: ci_info_struct,
649 })
650}
651
652fn set_workspace_cwd(directory_path: &Path, force: bool) {
653 if force || !envmnt::exists("CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY") {
654 let directory_path_string: String = FromPath::from_path(directory_path);
655
656 envmnt::set(
657 "CARGO_MAKE_WORKSPACE_WORKING_DIRECTORY",
658 directory_path_string,
659 );
660 }
661}
662
663pub(crate) fn search_and_set_workspace_cwd() {
664 match crateinfo::search_workspace_root() {
665 Some(root_directory) => {
666 let root_directory_path_buf = get_directory_path(Some(&root_directory));
667 let root_directory_path = root_directory_path_buf.as_path();
668 set_workspace_cwd(&root_directory_path, true);
669 }
670 None => (),
671 }
672}
673
674fn get_directory_path(path_option: Option<&str>) -> PathBuf {
675 let cwd_str = path_option.unwrap_or(".");
676 let directory = expand_value(cwd_str);
677
678 let directory_path_string = io::canonicalize_to_string(&directory);
679 PathBuf::from(directory_path_string)
680}
681
682pub(crate) fn setup_cwd(cwd: Option<&str>) -> Option<PathBuf> {
683 let directory_path_buf = get_directory_path(cwd);
684 let directory_path = directory_path_buf.as_path();
685
686 debug!(
687 "Changing working directory to: {}",
688 directory_path.display()
689 );
690
691 match env::set_current_dir(&directory_path) {
692 Err(error) => {
693 error!(
694 "Unable to set current working directory to: {} {:#?}",
695 directory_path.display(),
696 error
697 );
698 None
699 }
700 _ => {
701 envmnt::set("CARGO_MAKE_WORKING_DIRECTORY", &directory_path);
702
703 set_workspace_cwd(&directory_path, false);
704
705 debug!("Working directory changed to: {}", directory_path.display());
706
707 let home = home::cargo_home_with_cwd(directory_path).ok();
708
709 envmnt::set_optional("CARGO_MAKE_CARGO_HOME", &home);
710 home
711 }
712 }
713}
714
715pub(crate) fn load_env_file(env_file: Option<String>) -> bool {
716 load_env_file_with_base_directory(env_file, None, false)
717}
718
719fn load_env_file_with_base_directory(
720 env_file: Option<String>,
721 base_directory: Option<String>,
722 defaults_only: bool,
723) -> bool {
724 match env_file {
725 Some(file_name) => {
726 let expanded_file_name = expand_value(&file_name);
727
728 let file_path = if expanded_file_name.starts_with(".") {
729 let (base_path, check_relative_path) = match base_directory {
730 Some(file) => (file, true),
731 None => (envmnt::get_or("CARGO_MAKE_WORKING_DIRECTORY", "."), false),
732 };
733
734 if check_relative_path && base_path.starts_with(".") {
735 Path::new(&envmnt::get_or("CARGO_MAKE_WORKING_DIRECTORY", "."))
736 .join(&base_path)
737 .join(expanded_file_name)
738 } else {
739 Path::new(&base_path).join(expanded_file_name)
740 }
741 } else {
742 Path::new(&expanded_file_name).to_path_buf()
743 };
744
745 match file_path.to_str() {
746 Some(file_path_str) => {
747 let evaluate_env_var = |key: String, value: String| {
748 let skip = if defaults_only {
749 envmnt::exists(&key)
750 } else {
751 false
752 };
753
754 if skip {
755 None
756 } else {
757 Some((key, expand_value(&value)))
758 }
759 };
760
761 match envmnt::evaluate_and_load_file(file_path_str, evaluate_env_var) {
762 Err(error) => {
763 error!(
764 "Unable to load env file: {} Error: {:#?}",
765 &file_path_str, error
766 );
767 false
768 }
769 _ => {
770 debug!("Loaded env file: {}", &file_path_str);
771 true
772 }
773 }
774 }
775 None => false,
776 }
777 }
778 None => false,
779 }
780}
781
782fn current_dir_or(fallback: &PathBuf) -> PathBuf {
783 match env::current_dir() {
784 Ok(value) => value.clone(),
785 _ => fallback.clone(),
786 }
787}
788
789pub(crate) fn find_git_root(directory: &PathBuf) -> Option<String> {
790 let from_dir = if directory.to_str().unwrap_or(".") == "." {
791 current_dir_or(directory)
792 } else {
793 directory.to_path_buf()
794 };
795 debug!("Looking for git root from directory: {:?}", &from_dir);
796 let file_path = Path::new(&from_dir).join(".git");
797
798 if file_path.exists() {
799 match from_dir.to_str() {
800 Some(directory_string) => Some(directory_string.to_string()),
801 _ => None,
802 }
803 } else {
804 match from_dir.parent() {
805 Some(parent_directory) => {
806 let parent_directory_path = parent_directory.to_path_buf();
807 find_git_root(&parent_directory_path)
808 }
809 None => None,
810 }
811 }
812}
813
814pub(crate) fn get_project_root_for_path(directory: &PathBuf) -> Option<String> {
815 let from_dir = if directory.to_str().unwrap_or(".") == "." {
816 current_dir_or(directory)
817 } else {
818 directory.to_path_buf()
819 };
820 debug!("Looking for project root from directory: {:?}", &from_dir);
821 let file_path = Path::new(&from_dir).join("Cargo.toml");
822
823 if file_path.exists() {
824 match from_dir.to_str() {
825 Some(directory_string) => Some(directory_string.to_string()),
826 _ => None,
827 }
828 } else {
829 match from_dir.parent() {
830 Some(parent_directory) => {
831 let parent_directory_path = parent_directory.to_path_buf();
832 get_project_root_for_path(&parent_directory_path)
833 }
834 None => None,
835 }
836 }
837}
838
839pub(crate) fn get_project_root() -> Option<String> {
840 let directory = PathBuf::from(".");
841 get_project_root_for_path(&directory)
842}
843
844fn expand_env_for_script_runner_arguments(task: &mut Task) {
845 let updated_args = match task.script_runner_args {
846 Some(ref args) => {
847 let mut expanded_args = vec![];
848
849 for index in 0..args.len() {
850 expanded_args.push(expand_value(&args[index]));
851 }
852
853 Some(expanded_args)
854 }
855 None => None,
856 };
857
858 task.script_runner_args = updated_args;
859}
860
861fn expand_env_for_arguments(task: &mut Task) {
862 let updated_args = match task.args {
864 Some(ref args) => {
865 let mut expanded_args = vec![];
866
867 let task_args = match envmnt::get_list("CARGO_MAKE_TASK_ARGS") {
868 Some(list) => list,
869 None => vec![],
870 };
871
872 for index in 0..args.len() {
873 if args[index].contains("${@}") {
874 if task_args.len() > 0 {
875 if args[index] == "${@}" {
876 for arg_index in 0..task_args.len() {
877 expanded_args.push(task_args[arg_index].clone());
878 }
879 } else {
880 for arg_index in 0..task_args.len() {
881 let value_string =
882 str::replace(&args[index], "${@}", &task_args[arg_index]);
883 expanded_args.push(value_string);
884 }
885 }
886 }
887 } else {
888 expanded_args.push(args[index].clone());
889 }
890 }
891
892 for index in 0..expanded_args.len() {
893 expanded_args[index] = expand_value(&expanded_args[index]);
894 }
895
896 Some(expanded_args)
897 }
898 None => None,
899 };
900
901 task.args = updated_args;
902}
903
904pub(crate) fn expand_env(step: &Step) -> Step {
905 let mut config = step.config.clone();
907
908 match config.command {
910 Some(value) => {
911 config.command = Some(expand_value(&value));
912 }
913 None => {}
914 };
915
916 expand_env_for_arguments(&mut config);
918 expand_env_for_script_runner_arguments(&mut config);
919
920 Step {
921 name: step.name.clone(),
922 config,
923 }
924}
925
926pub(crate) fn expand_condition_script_runner_arguments(step: &Step) -> Step {
927 let mut modified_step = step.clone();
928
929 modified_step.config.condition_script_runner_args = step
930 .config
931 .condition_script_runner_args
932 .as_ref()
933 .map(|args| args.iter().map(|arg| expand_value(arg)).collect());
934 modified_step
935}