|
1 | 1 | use crate::core::{Edition, Shell, Workspace};
|
2 | 2 | use crate::util::errors::CargoResult;
|
| 3 | +use crate::util::important_paths::find_root_manifest_for_wd; |
3 | 4 | use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
|
4 | 5 | use crate::util::{restricted_names, Config};
|
5 | 6 | use anyhow::{anyhow, Context as _};
|
@@ -759,69 +760,72 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> {
|
759 | 760 | init_vcs(path, vcs, config)?;
|
760 | 761 | write_ignore_file(path, &ignore, vcs)?;
|
761 | 762 |
|
762 |
| - let mut cargotoml_path_specifier = String::new(); |
| 763 | + // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. |
| 764 | + let mut manifest = toml_edit::Document::new(); |
| 765 | + manifest["package"] = toml_edit::Item::Table(toml_edit::Table::new()); |
| 766 | + manifest["package"]["name"] = toml_edit::value(name); |
| 767 | + manifest["package"]["version"] = toml_edit::value("0.1.0"); |
| 768 | + let edition = match opts.edition { |
| 769 | + Some(edition) => edition.to_string(), |
| 770 | + None => Edition::LATEST_STABLE.to_string(), |
| 771 | + }; |
| 772 | + manifest["package"]["edition"] = toml_edit::value(edition); |
| 773 | + if let Some(registry) = opts.registry { |
| 774 | + let mut array = toml_edit::Array::default(); |
| 775 | + array.push(registry); |
| 776 | + manifest["package"]["publish"] = toml_edit::value(array); |
| 777 | + } |
| 778 | + let mut dep_table = toml_edit::Table::default(); |
| 779 | + dep_table.decor_mut().set_prefix("\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n"); |
| 780 | + manifest["dependencies"] = toml_edit::Item::Table(dep_table); |
763 | 781 |
|
764 | 782 | // Calculate what `[lib]` and `[[bin]]`s we need to append to `Cargo.toml`.
|
765 |
| - |
766 | 783 | for i in &opts.source_files {
|
767 | 784 | if i.bin {
|
768 | 785 | if i.relative_path != "src/main.rs" {
|
769 |
| - cargotoml_path_specifier.push_str(&format!( |
770 |
| - r#" |
771 |
| -[[bin]] |
772 |
| -name = "{}" |
773 |
| -path = {} |
774 |
| -"#, |
775 |
| - i.target_name, |
776 |
| - toml::Value::String(i.relative_path.clone()) |
777 |
| - )); |
| 786 | + let mut bin = toml_edit::Table::new(); |
| 787 | + bin["name"] = toml_edit::value(i.target_name.clone()); |
| 788 | + bin["path"] = toml_edit::value(i.relative_path.clone()); |
| 789 | + manifest["bin"] |
| 790 | + .or_insert(toml_edit::Item::ArrayOfTables( |
| 791 | + toml_edit::ArrayOfTables::new(), |
| 792 | + )) |
| 793 | + .as_array_of_tables_mut() |
| 794 | + .expect("bin is an array of tables") |
| 795 | + .push(bin); |
778 | 796 | }
|
779 | 797 | } else if i.relative_path != "src/lib.rs" {
|
780 |
| - cargotoml_path_specifier.push_str(&format!( |
781 |
| - r#" |
782 |
| -[lib] |
783 |
| -name = "{}" |
784 |
| -path = {} |
785 |
| -"#, |
786 |
| - i.target_name, |
787 |
| - toml::Value::String(i.relative_path.clone()) |
788 |
| - )); |
| 798 | + let mut lib = toml_edit::Table::new(); |
| 799 | + lib["name"] = toml_edit::value(i.target_name.clone()); |
| 800 | + lib["path"] = toml_edit::value(i.relative_path.clone()); |
| 801 | + manifest["lib"] = toml_edit::Item::Table(lib); |
789 | 802 | }
|
790 | 803 | }
|
791 | 804 |
|
792 |
| - // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. |
| 805 | + let manifest_path = path.join("Cargo.toml"); |
| 806 | + if let Ok(root_manifest_path) = find_root_manifest_for_wd(&manifest_path) { |
| 807 | + let root_manifest = paths::read(&root_manifest_path)?; |
| 808 | + // Sometimes the root manifest is not a valid manifest, so we only try to parse it if it is. |
| 809 | + // This should not block the creation of the new project. It is only a best effort to |
| 810 | + // inherit the workspace package keys. |
| 811 | + if let Ok(workspace_document) = root_manifest.parse::<toml_edit::Document>() { |
| 812 | + if let Some(workspace_package_keys) = workspace_document |
| 813 | + .get("workspace") |
| 814 | + .and_then(|workspace| workspace.get("package")) |
| 815 | + .and_then(|package| package.as_table()) |
| 816 | + { |
| 817 | + update_manifest_with_inherited_workspace_package_keys( |
| 818 | + opts, |
| 819 | + &mut manifest, |
| 820 | + workspace_package_keys, |
| 821 | + ) |
| 822 | + } |
| 823 | + } |
| 824 | + } |
793 | 825 |
|
794 |
| - paths::write( |
795 |
| - &path.join("Cargo.toml"), |
796 |
| - format!( |
797 |
| - r#"[package] |
798 |
| -name = "{}" |
799 |
| -version = "0.1.0" |
800 |
| -edition = {} |
801 |
| -{} |
802 |
| -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
803 |
| -
|
804 |
| -[dependencies] |
805 |
| -{}"#, |
806 |
| - name, |
807 |
| - match opts.edition { |
808 |
| - Some(edition) => toml::Value::String(edition.to_string()), |
809 |
| - None => toml::Value::String(Edition::LATEST_STABLE.to_string()), |
810 |
| - }, |
811 |
| - match opts.registry { |
812 |
| - Some(registry) => format!( |
813 |
| - "publish = {}\n", |
814 |
| - toml::Value::Array(vec!(toml::Value::String(registry.to_string()))) |
815 |
| - ), |
816 |
| - None => "".to_string(), |
817 |
| - }, |
818 |
| - cargotoml_path_specifier |
819 |
| - ) |
820 |
| - .as_bytes(), |
821 |
| - )?; |
| 826 | + paths::write(&manifest_path, manifest.to_string())?; |
822 | 827 |
|
823 | 828 | // Create all specified source files (with respective parent directories) if they don't exist.
|
824 |
| - |
825 | 829 | for i in &opts.source_files {
|
826 | 830 | let path_of_source_file = path.join(i.relative_path.clone());
|
827 | 831 |
|
@@ -878,3 +882,40 @@ mod tests {
|
878 | 882 |
|
879 | 883 | Ok(())
|
880 | 884 | }
|
| 885 | + |
| 886 | +// Update the manifest with the inherited workspace package keys. |
| 887 | +// If the option is not set, the key is removed from the manifest. |
| 888 | +// If the option is set, keep the value from the manifest. |
| 889 | +fn update_manifest_with_inherited_workspace_package_keys( |
| 890 | + opts: &MkOptions<'_>, |
| 891 | + manifest: &mut toml_edit::Document, |
| 892 | + workspace_package_keys: &toml_edit::Table, |
| 893 | +) { |
| 894 | + if workspace_package_keys.is_empty() { |
| 895 | + return; |
| 896 | + } |
| 897 | + |
| 898 | + let try_remove_and_inherit_package_key = |key: &str, manifest: &mut toml_edit::Document| { |
| 899 | + let package = manifest["package"] |
| 900 | + .as_table_mut() |
| 901 | + .expect("package is a table"); |
| 902 | + package.remove(key); |
| 903 | + let mut table = toml_edit::Table::new(); |
| 904 | + table.set_dotted(true); |
| 905 | + table["workspace"] = toml_edit::value(true); |
| 906 | + package.insert(key, toml_edit::Item::Table(table)); |
| 907 | + }; |
| 908 | + |
| 909 | + // Inherit keys from the workspace. |
| 910 | + // Only keep the value from the manifest if the option is set. |
| 911 | + for (key, _) in workspace_package_keys { |
| 912 | + if key == "edition" && opts.edition.is_some() { |
| 913 | + continue; |
| 914 | + } |
| 915 | + if key == "publish" && opts.registry.is_some() { |
| 916 | + continue; |
| 917 | + } |
| 918 | + |
| 919 | + try_remove_and_inherit_package_key(key, manifest); |
| 920 | + } |
| 921 | +} |
0 commit comments