Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-cli / src / add.rs
5.6 kB 172 lines
1// SPDX-License-Identifier: Apache-2.0 2// SPDX-FileCopyrightText: 2021 The Gleam contributors 3 4use camino::{Utf8Path, Utf8PathBuf}; 5use std::fmt::Write as _; 6 7use gleam_core::{ 8 Error, Result, 9 error::{FileIoAction, FileKind}, 10 paths::ProjectPaths, 11}; 12use hexpm::version::{Identifier, Version}; 13 14use crate::{ 15 cli, 16 dependencies::{self, parse_gleam_add_specifier}, 17 fs, 18}; 19 20pub fn command(paths: &ProjectPaths, packages_to_add: Vec<String>, dev: bool) -> Result<()> { 21 let config = crate::config::root_config(paths)?; 22 if packages_to_add.iter().any(|name| name == &config.name) { 23 return Err(Error::CannotAddSelfAsDependency { name: config.name }); 24 } 25 26 let mut new_package_requirements = Vec::with_capacity(packages_to_add.len()); 27 for specifier in packages_to_add { 28 new_package_requirements.push(parse_gleam_add_specifier(&specifier)?); 29 } 30 31 // Insert the new packages into the manifest and perform dependency 32 // resolution to determine suitable versions 33 let manifest = dependencies::resolve_and_download( 34 paths, 35 cli::Reporter::new(), 36 Some((new_package_requirements.clone(), dev)), 37 Vec::new(), 38 dependencies::DependencyManagerConfig { 39 use_manifest: dependencies::UseManifest::Yes, 40 check_major_versions: dependencies::CheckMajorVersions::No, 41 }, 42 )?; 43 44 // Read gleam.toml and manifest.toml so we can insert new deps into it 45 let mut gleam_toml = read_toml_edit(&paths.root_config())?; 46 let mut manifest_toml = read_toml_edit(&paths.manifest())?; 47 48 // Insert the new deps 49 for (added_package, _) in new_package_requirements { 50 let added_package = added_package.to_string(); 51 52 // Pull the selected version out of the new manifest so we know what it is 53 let version = &manifest 54 .packages 55 .iter() 56 .find(|package| package.name == *added_package) 57 .expect("Added package not found in resolved manifest") 58 .version; 59 60 tracing::info!(version=%version, "new_package_version_resolved"); 61 62 // Produce a version requirement locked to the major version. 63 // i.e. if 1.2.3 is selected we want >= 1.2.3 and < 2.0.0 64 let range = format!( 65 ">= {} and < {}.0.0", 66 version_to_string(version), 67 version.major + 1 68 ); 69 70 // False positive. This package doesn't use the indexing API correctly. 71 #[allow(clippy::indexing_slicing)] 72 { 73 if dev { 74 let canonical_name = "dev_dependencies"; 75 let deprecated_name = "dev-dependencies"; 76 let has_canonical = gleam_toml.as_table().contains_key(canonical_name); 77 let has_deprecated = gleam_toml.as_table().contains_key(deprecated_name); 78 if !has_canonical && !has_deprecated { 79 gleam_toml["dev_dependencies"] = toml_edit::table(); 80 } 81 let name = if has_deprecated { 82 deprecated_name 83 } else { 84 canonical_name 85 }; 86 gleam_toml[name][&added_package] = toml_edit::value(range.clone()); 87 } else { 88 if !gleam_toml.as_table().contains_key("dependencies") { 89 gleam_toml["dependencies"] = toml_edit::table(); 90 } 91 gleam_toml["dependencies"][&added_package] = toml_edit::value(range.clone()); 92 } 93 manifest_toml["requirements"][&added_package]["version"] = range.into(); 94 } 95 } 96 97 // Write the updated config 98 fs::write(&paths.root_config(), &gleam_toml.to_string())?; 99 fs::write(&paths.manifest(), &manifest_toml.to_string())?; 100 101 Ok(()) 102} 103 104fn read_toml_edit(name: &Utf8Path) -> Result<toml_edit::DocumentMut, Error> { 105 fs::read(name)? 106 .parse::<toml_edit::DocumentMut>() 107 .map_err(|e| Error::FileIo { 108 kind: FileKind::File, 109 action: FileIoAction::Parse, 110 path: Utf8PathBuf::from("gleam.toml"), 111 err: Some(e.to_string()), 112 }) 113} 114 115fn version_to_string(version: &Version) -> String { 116 let mut text = String::new(); 117 let _ = write!( 118 text, 119 "{}.{}.{}", 120 version.major, version.minor, version.patch 121 ); 122 123 if !version.pre.is_empty() { 124 text.push('-'); 125 for (i, identifier) in version.pre.iter().enumerate() { 126 if i != 0 { 127 text.push('.'); 128 } 129 match *identifier { 130 Identifier::Numeric(ref id) => text.push_str(&id.to_string()), 131 Identifier::AlphaNumeric(ref id) => text.push_str(id), 132 } 133 } 134 } 135 if let Some(build) = version.build.as_ref() { 136 let _ = write!(text, "+{build}"); 137 } 138 text 139} 140 141#[test] 142fn displays_simple_version_correctly() { 143 let version = Version { 144 major: 1, 145 minor: 23, 146 patch: 4, 147 pre: vec![], 148 build: None, 149 }; 150 151 let displayed = version_to_string(&version); 152 153 assert_eq!(displayed, "1.23.4"); 154} 155 156#[test] 157fn displays_full_version_correctly() { 158 let version = Version { 159 major: 1, 160 minor: 23, 161 patch: 4, 162 pre: vec![ 163 Identifier::Numeric(123), 164 Identifier::AlphaNumeric("123abc".to_string()), 165 ], 166 build: Some("12345abc".to_string()), 167 }; 168 169 let displayed = version_to_string(&version); 170 171 assert_eq!(displayed, "1.23.4-123.123abc+12345abc"); 172}