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 174 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 write!( 118 text, 119 "{}.{}.{}", 120 version.major, version.minor, version.patch 121 ) 122 .expect("write to a string"); 123 124 if !version.pre.is_empty() { 125 text.push('-'); 126 for (i, identifier) in version.pre.iter().enumerate() { 127 if i != 0 { 128 text.push('.'); 129 } 130 match *identifier { 131 Identifier::Numeric(ref id) => text.push_str(&id.to_string()), 132 Identifier::AlphaNumeric(ref id) => text.push_str(id), 133 } 134 } 135 } 136 if let Some(build) = version.build.as_ref() { 137 text.push('+'); 138 text.push_str(build); 139 } 140 text 141} 142 143#[test] 144fn displays_simple_version_correctly() { 145 let version = Version { 146 major: 1, 147 minor: 23, 148 patch: 4, 149 pre: vec![], 150 build: None, 151 }; 152 153 let displayed = version_to_string(&version); 154 155 assert_eq!(displayed, "1.23.4"); 156} 157 158#[test] 159fn displays_full_version_correctly() { 160 let version = Version { 161 major: 1, 162 minor: 23, 163 patch: 4, 164 pre: vec![ 165 Identifier::Numeric(123), 166 Identifier::AlphaNumeric("123abc".to_string()), 167 ], 168 build: Some("12345abc".to_string()), 169 }; 170 171 let displayed = version_to_string(&version); 172 173 assert_eq!(displayed, "1.23.4-123.123abc+12345abc"); 174}