浏览代码

cli: Add optional `package-manager` flag in `init` command to set package manager field in Anchor.toml (#3328)

Co-authored-by: acheron <98934430+acheroncrypto@users.noreply.github.com>
Arihant Bansal 11 月之前
父节点
当前提交
d34c04a98a
共有 5 个文件被更改,包括 86 次插入22 次删除
  1. 2 1
      CHANGELOG.md
  2. 11 2
      cli/src/checks.rs
  3. 25 0
      cli/src/config.rs
  4. 32 9
      cli/src/lib.rs
  5. 16 10
      cli/src/rust_template.rs

+ 2 - 1
CHANGELOG.md

@@ -56,8 +56,9 @@ The minor version will be incremented upon a breaking change and the patch versi
 - cli: Add `--program-id` option to `idl convert` command ([#3309](https://github.com/coral-xyz/anchor/pull/3309)).
 - lang: Generate documentation of constants in `declare_program!` ([#3311](https://github.com/coral-xyz/anchor/pull/3311)).
 - cli: Add support for fetching legacy IDLs ([#3324](https://github.com/coral-xyz/anchor/pull/3324)).
-- avm: Add short alias for `install` and `list` command ([#3326])(https://github.com/coral-xyz/anchor/pull/3326).
+- avm: Add short alias for `install` and `list` commands ([#3326](https://github.com/coral-xyz/anchor/pull/3326)).
 - avm: Add Windows support for renaming anchor binary ([#3325](https://github.com/coral-xyz/anchor/pull/3325)).
+- cli: Add optional `package-manager` flag in `init` command to set package manager field in Anchor.toml ([#3328](https://github.com/coral-xyz/anchor/pull/3328)).
 
 ### Fixes
 

+ 11 - 2
cli/src/checks.rs

@@ -4,7 +4,7 @@ use anyhow::{anyhow, Result};
 use semver::{Version, VersionReq};
 
 use crate::{
-    config::{Config, Manifest, WithPath},
+    config::{Config, Manifest, PackageManager, WithPath},
     VERSION,
 };
 
@@ -69,12 +69,21 @@ pub fn check_anchor_version(cfg: &WithPath<Config>) -> Result<()> {
         .and_then(|ver| VersionReq::parse(ver).ok())
         .filter(|ver| !ver.matches(&cli_version));
 
+    let update_cmd = match &cfg.toolchain.package_manager {
+        Some(pkg_manager) => match pkg_manager {
+            PackageManager::NPM => "npm update",
+            PackageManager::Yarn => "yarn upgrade",
+            PackageManager::PNPM => "pnpm update",
+        },
+        None => "npm update",
+    };
+
     if let Some(ver) = mismatched_ts_version {
         eprintln!(
             "WARNING: `@coral-xyz/anchor` version({ver}) and the current CLI version\
                 ({cli_version}) don't match.\n\n\t\
                 This can lead to unwanted behavior. To fix, upgrade the package by running:\n\n\t\
-                yarn upgrade @coral-xyz/anchor@{cli_version}\n"
+                {update_cmd} @coral-xyz/anchor@{cli_version}\n"
         );
     }
 

+ 25 - 0
cli/src/config.rs

@@ -380,6 +380,31 @@ pub struct Config {
 pub struct ToolchainConfig {
     pub anchor_version: Option<String>,
     pub solana_version: Option<String>,
+    pub package_manager: Option<PackageManager>,
+}
+
+/// Package manager to use for the project.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum, Serialize, Deserialize)]
+pub enum PackageManager {
+    /// Use npm as the package manager.
+    NPM,
+    /// Use yarn as the package manager.
+    #[default]
+    Yarn,
+    /// Use pnpm as the package manager.
+    PNPM,
+}
+
+impl std::fmt::Display for PackageManager {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        let pkg_manager_str = match self {
+            PackageManager::NPM => "npm",
+            PackageManager::Yarn => "yarn",
+            PackageManager::PNPM => "pnpm",
+        };
+
+        write!(f, "{pkg_manager_str}")
+    }
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize)]

+ 32 - 9
cli/src/lib.rs

@@ -1,7 +1,7 @@
 use crate::config::{
     get_default_ledger_path, AnchorPackage, BootstrapMode, BuildConfig, Config, ConfigOverride,
-    Manifest, ProgramArch, ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator,
-    WithPath, SHUTDOWN_WAIT, STARTUP_WAIT,
+    Manifest, PackageManager, ProgramArch, ProgramDeployment, ProgramWorkspace, ScriptsConfig,
+    TestValidator, WithPath, SHUTDOWN_WAIT, STARTUP_WAIT,
 };
 use anchor_client::Cluster;
 use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY};
@@ -82,6 +82,9 @@ pub enum Command {
         /// Don't install JavaScript dependencies
         #[clap(long)]
         no_install: bool,
+        /// Package Manager to use
+        #[clap(value_enum, long, default_value = "yarn")]
+        package_manager: PackageManager,
         /// Don't initialize git
         #[clap(long)]
         no_git: bool,
@@ -756,6 +759,7 @@ fn process_command(opts: Opts) -> Result<()> {
             javascript,
             solidity,
             no_install,
+            package_manager,
             no_git,
             template,
             test_template,
@@ -766,6 +770,7 @@ fn process_command(opts: Opts) -> Result<()> {
             javascript,
             solidity,
             no_install,
+            package_manager,
             no_git,
             template,
             test_template,
@@ -952,6 +957,7 @@ fn init(
     javascript: bool,
     solidity: bool,
     no_install: bool,
+    package_manager: PackageManager,
     no_git: bool,
     template: ProgramTemplate,
     test_template: TestTemplate,
@@ -990,9 +996,12 @@ fn init(
     fs::create_dir_all("app")?;
 
     let mut cfg = Config::default();
-    let test_script = test_template.get_test_script(javascript);
-    cfg.scripts
-        .insert("test".to_owned(), test_script.to_owned());
+
+    let test_script = test_template.get_test_script(javascript, &package_manager);
+    cfg.scripts.insert("test".to_owned(), test_script);
+
+    let package_manager_cmd = package_manager.to_string();
+    cfg.toolchain.package_manager = Some(package_manager);
 
     let mut localnet = BTreeMap::new();
     let program_id = rust_template::get_or_create_program_id(&rust_name);
@@ -1064,10 +1073,16 @@ fn init(
     )?;
 
     if !no_install {
-        let yarn_result = install_node_modules("yarn")?;
-        if !yarn_result.status.success() {
-            println!("Failed yarn install will attempt to npm install");
+        let package_manager_result = install_node_modules(&package_manager_cmd)?;
+
+        if !package_manager_result.status.success() && package_manager_cmd != "npm" {
+            println!(
+                "Failed {} install will attempt to npm install",
+                package_manager_cmd
+            );
             install_node_modules("npm")?;
+        } else {
+            eprintln!("Failed to install node modules");
         }
     }
 
@@ -4124,7 +4139,12 @@ fn migrate(cfg_override: &ConfigOverride) -> Result<()> {
                 rust_template::deploy_ts_script_host(&url, &module_path.display().to_string());
             fs::write(deploy_ts, deploy_script_host_str)?;
 
-            std::process::Command::new("yarn")
+            let pkg_manager_cmd = match &cfg.toolchain.package_manager {
+                Some(pkg_manager) => pkg_manager.to_string(),
+                None => PackageManager::default().to_string(),
+            };
+
+            std::process::Command::new(pkg_manager_cmd)
                 .args([
                     "run",
                     "ts-node",
@@ -4812,6 +4832,7 @@ mod tests {
             true,
             false,
             true,
+            PackageManager::default(),
             false,
             ProgramTemplate::default(),
             TestTemplate::default(),
@@ -4832,6 +4853,7 @@ mod tests {
             true,
             false,
             true,
+            PackageManager::default(),
             false,
             ProgramTemplate::default(),
             TestTemplate::default(),
@@ -4852,6 +4874,7 @@ mod tests {
             true,
             false,
             true,
+            PackageManager::default(),
             false,
             ProgramTemplate::default(),
             TestTemplate::default(),

+ 16 - 10
cli/src/rust_template.rs

@@ -1,6 +1,6 @@
 use crate::{
     config::ProgramWorkspace, create_files, override_or_create_files, solidity_template, Files,
-    VERSION,
+    PackageManager, VERSION,
 };
 use anyhow::Result;
 use clap::{Parser, ValueEnum};
@@ -401,7 +401,7 @@ pub fn ts_package_json(jest: bool, license: String) -> String {
     if jest {
         format!(
             r#"{{
-  "license": "{license}",              
+  "license": "{license}",
   "scripts": {{
     "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
     "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
@@ -423,7 +423,7 @@ pub fn ts_package_json(jest: bool, license: String) -> String {
     } else {
         format!(
             r#"{{
-  "license": "{license}",  
+  "license": "{license}",
   "scripts": {{
     "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w",
     "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check"
@@ -607,30 +607,36 @@ pub enum TestTemplate {
     /// Generate template for Mocha unit-test
     #[default]
     Mocha,
-    /// Generate template for Jest unit-test    
+    /// Generate template for Jest unit-test
     Jest,
     /// Generate template for Rust unit-test
     Rust,
 }
 
 impl TestTemplate {
-    pub fn get_test_script(&self, js: bool) -> &str {
+    pub fn get_test_script(&self, js: bool, pkg_manager: &PackageManager) -> String {
+        let pkg_manager_exec_cmd = match pkg_manager {
+            PackageManager::Yarn => "yarn run",
+            PackageManager::NPM => "npx",
+            PackageManager::PNPM => "pnpm exec",
+        };
+
         match &self {
             Self::Mocha => {
                 if js {
-                    "yarn run mocha -t 1000000 tests/"
+                    format!("{pkg_manager_exec_cmd} mocha -t 1000000 tests/")
                 } else {
-                    "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+                    format!("{pkg_manager_exec_cmd} ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts")
                 }
             }
             Self::Jest => {
                 if js {
-                    "yarn run jest"
+                    format!("{pkg_manager_exec_cmd} jest")
                 } else {
-                    "yarn run jest --preset ts-jest"
+                    format!("{pkg_manager_exec_cmd} jest --preset ts-jest")
                 }
             }
-            Self::Rust => "cargo test",
+            Self::Rust => "cargo test".to_owned(),
         }
     }