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