1use std::rc::Rc;
2
3use gleam_core::{
4 Error, Result, Warning,
5 analyse::TargetSupport,
6 build::{Codegen, Compile, Mode, Options},
7 error::{FileIoAction, FileKind},
8 paths::ProjectPaths,
9 type_,
10 warning::VectorWarningEmitterIO,
11};
12use hexpm::version::Version;
13
14use crate::{build, cli};
15
16pub fn run(paths: &ProjectPaths) -> Result<()> {
17 // When running gleam fix we want all the compilation warnings to be hidden,
18 // at the same time we need to access those to apply the fixes: so we
19 // accumulate those into a vector.
20 let warnings = Rc::new(VectorWarningEmitterIO::new());
21 let _built = build::main_with_warnings(
22 paths,
23 Options {
24 root_target_support: TargetSupport::Enforced,
25 warnings_as_errors: false,
26 codegen: Codegen::DepsOnly,
27 compile: Compile::All,
28 mode: Mode::Dev,
29 target: None,
30 no_print_progress: false,
31 },
32 build::download_dependencies(paths, cli::Reporter::new())?,
33 warnings.clone(),
34 )?;
35 let warnings = warnings.take();
36
37 fix_minimum_required_version(paths, warnings)?;
38
39 println!("Done!");
40 Ok(())
41}
42
43fn fix_minimum_required_version(paths: &ProjectPaths, warnings: Vec<Warning>) -> Result<()> {
44 let Some(minimum_required_version) = minimum_required_version_from_warnings(warnings) else {
45 return Ok(());
46 };
47
48 // Set the version requirement in gleam.toml
49 let root_config = paths.root_config();
50 let mut toml = crate::fs::read(&root_config)?
51 .parse::<toml_edit::DocumentMut>()
52 .map_err(|e| Error::FileIo {
53 kind: FileKind::File,
54 action: FileIoAction::Parse,
55 path: root_config.to_path_buf(),
56 err: Some(e.to_string()),
57 })?;
58
59 #[allow(clippy::indexing_slicing)]
60 {
61 toml["gleam"] = toml_edit::value(format!(">= {minimum_required_version}"));
62 }
63
64 // Write the updated config
65 crate::fs::write(root_config.as_path(), &toml.to_string())?;
66
67 println!("- Set required Gleam version to \">= {minimum_required_version}\"");
68 Ok(())
69}
70
71/// Returns the highest minimum required version among all warnings requiring a
72/// specific Gleam version that is not allowed by the `gleam` version contraint
73/// in the `gleam.toml`.
74fn minimum_required_version_from_warnings(warnings: Vec<Warning>) -> Option<Version> {
75 warnings
76 .iter()
77 .filter_map(|warning| match warning {
78 Warning::Type {
79 warning:
80 type_::Warning::FeatureRequiresHigherGleamVersion {
81 minimum_required_version,
82 ..
83 },
84 ..
85 } => Some(minimum_required_version),
86 _ => None,
87 })
88 .reduce(std::cmp::max)
89 .cloned()
90}