Skip to content

Commit 5e48a5c

Browse files
authored
feat: auto-detect package manager (#486)
* feat: auto-detect package manager * fmt
1 parent 724ff2b commit 5e48a5c

8 files changed

Lines changed: 73 additions & 22 deletions

File tree

.changes/detect-package-manager.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"create-tauri-app": "minor"
3+
"create-tauri-app-js": "minor"
4+
---
5+
6+
Auto-detect package manager used to run `create-tauri-app` and promote the most relevant category for it and select it and also make the package manager selected by default in the managers selection list.
7+

.github/workflows/fmt.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525

2626
- run: cargo fmt --all -- --check
2727

28-
prttier-fmt-check:
28+
prettier-fmt-check:
2929
runs-on: ubuntu-latest
3030

3131
steps:

packages/cli/node/create-tauri-app.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,10 @@ if (binStem.match(/(nodejs|node|bun)-*([1-9]*)*$/g)) {
4949
args.unshift(bin);
5050
}
5151

52-
cli.run(args, binName);
52+
// adapted from https://github.com/vitejs/vite/blob/34826aae015ed16dc9b9096c0f778154ca6981a6/packages/create-vite/src/index.ts#L513
53+
function pkgManagerFromUserAgent(userAgent) {
54+
if (!userAgent) return undefined;
55+
return userAgent.split(" ")[0]?.split("/")[0];
56+
}
57+
const pkgManager = pkgManagerFromUserAgent(process.env.npm_config_user_agent);
58+
cli.run(args, binName, pkgManager);

packages/cli/node/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
export function run(
1111
args: Array<string>,
1212
binName?: string | undefined | null,
13+
pkgManager?: string | undefined | null,
1314
): void;

packages/cli/node/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
const { existsSync, readFileSync } = require("fs");
1+
/* tslint:disable */
2+
/* eslint-disable */
3+
/* prettier-ignore */
4+
5+
/* auto-generated by NAPI-RS */
6+
7+
const { existsSync, readFileSync } = require('fs')
28
const { join } = require("path");
39

410
const { platform, arch } = process;

packages/cli/node/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
#[allow(unused)]
66
#[napi_derive::napi]
7-
fn run(args: Vec<String>, bin_name: Option<String>) {
8-
create_tauri_app::run(args, bin_name);
7+
fn run(args: Vec<String>, bin_name: Option<String>, pkg_manager: Option<String>) {
8+
create_tauri_app::run(args, bin_name, pkg_manager);
99
}

packages/cli/src/lib.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,29 +35,36 @@ pub mod internal {
3535
}
3636
}
3737

38-
pub fn run<I, A>(args: I, bin_name: Option<String>)
38+
pub fn run<I, A>(args: I, bin_name: Option<String>, detected_manager: Option<String>)
3939
where
4040
I: IntoIterator<Item = A>,
4141
A: Into<OsString> + Clone,
4242
{
43-
if let Err(e) = try_run(args, bin_name) {
43+
if let Err(e) = try_run(args, bin_name, detected_manager) {
4444
eprintln!("{BOLD}{RED}error{RESET}: {e:#}");
4545
exit(1);
4646
}
4747
}
4848

49-
fn try_run<I, A>(args: I, bin_name: Option<String>) -> anyhow::Result<()>
49+
fn try_run<I, A>(
50+
args: I,
51+
bin_name: Option<String>,
52+
detected_manager: Option<String>,
53+
) -> anyhow::Result<()>
5054
where
5155
I: IntoIterator<Item = A>,
5256
A: Into<OsString> + Clone,
5357
{
58+
let detected_manager = detected_manager.and_then(|p| p.parse::<PackageManager>().ok());
5459
let args = cli::parse(args.into_iter().map(Into::into).collect(), bin_name)?;
5560
let defaults = cli::Args::default();
5661
let cli::Args {
5762
skip,
5863
mobile,
5964
alpha,
60-
..
65+
manager,
66+
project_name,
67+
template,
6168
} = args;
6269
let cwd = std::env::current_dir()?;
6370

@@ -74,7 +81,7 @@ where
7481

7582
// Project name used for the project directory name
7683
// and if valid, it will also be used in Cargo.toml, Package.json ...etc
77-
let project_name = args.project_name.unwrap_or_else(|| {
84+
let project_name = project_name.unwrap_or_else(|| {
7885
if skip {
7986
defaults.project_name.unwrap()
8087
} else {
@@ -142,7 +149,7 @@ where
142149
};
143150

144151
// Prompt for category if a package manger is not passed on the command line
145-
let category = if args.manager.is_none() && !skip {
152+
let category = if manager.is_none() && !skip {
146153
// Filter managers if a template is passed on the command line
147154
let managers = PackageManager::ALL.to_vec();
148155
let managers = args
@@ -158,11 +165,24 @@ where
158165

159166
// Filter categories based on the detected package mangers
160167
let categories = Category::ALL.to_vec();
161-
let categories = categories
168+
let mut categories = categories
162169
.into_iter()
163170
.filter(|c| c.package_managers().iter().any(|p| managers.contains(p)))
164171
.collect::<Vec<_>>();
165172

173+
// sort categories so the most relevant category
174+
// based on the auto-detected package manager is selected first
175+
categories.sort_by(|a, b| {
176+
detected_manager
177+
.map(|p| b.package_managers().contains(&p))
178+
.unwrap_or(false)
179+
.cmp(
180+
&detected_manager
181+
.map(|p| a.package_managers().contains(&p))
182+
.unwrap_or(false),
183+
)
184+
});
185+
166186
// If only one category is detected, skip prompt
167187
if categories.len() == 1 {
168188
Some(categories[0])
@@ -181,20 +201,28 @@ where
181201

182202
// Package manager which will be used for rendering the template
183203
// and the after-render instructions
184-
let pkg_manager = args.manager.unwrap_or_else(|| {
204+
let pkg_manager = manager.unwrap_or_else(|| {
185205
if skip {
186206
defaults.manager.unwrap()
187207
} else {
188208
let category = category.unwrap();
189-
let managers = category.package_managers();
209+
210+
let mut managers = category.package_managers().to_owned();
211+
// sort managers so the auto-detected package manager is selected first
212+
managers.sort_by(|a, b| {
213+
detected_manager
214+
.map(|p| p == *b)
215+
.unwrap_or(false)
216+
.cmp(&detected_manager.map(|p| p == *a).unwrap_or(false))
217+
});
190218

191219
// If only one package manager is detected, skip prompt
192220
if managers.len() == 1 {
193221
managers[0]
194222
} else {
195223
let index = Select::with_theme(&ColorfulTheme::default())
196224
.with_prompt("Choose your package manager")
197-
.items(managers)
225+
.items(&managers)
198226
.default(0)
199227
.interact()
200228
.unwrap();
@@ -206,7 +234,7 @@ where
206234
let templates_no_flavors = pkg_manager.templates_no_flavors();
207235

208236
// Template to render
209-
let template = args.template.unwrap_or_else(|| {
237+
let template = template.unwrap_or_else(|| {
210238
if skip {
211239
defaults.template.unwrap()
212240
} else {

packages/cli/src/main.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5-
use std::{env::args_os, ffi::OsStr, path::Path, process::exit};
5+
use std::{env::args_os, ffi::OsStr, path::Path};
66

77
fn main() {
88
let mut args = args_os().peekable();
9+
let mut is_cargo = false;
910
let bin_name = match args
1011
.next()
1112
.as_deref()
@@ -14,6 +15,7 @@ fn main() {
1415
.and_then(OsStr::to_str)
1516
{
1617
Some("cargo-create-tauri-app") => {
18+
is_cargo = true;
1719
if args.peek().and_then(|s| s.to_str()) == Some("create-tauri-app") {
1820
// remove the extra cargo subcommand
1921
args.next();
@@ -23,11 +25,12 @@ fn main() {
2325
}
2426
}
2527
Some(stem) => Some(stem.to_string()),
26-
None => {
27-
eprintln!("cargo-tauri wrapper unable to read first argument");
28-
exit(1);
29-
}
28+
None => None,
3029
};
3130

32-
create_tauri_app::run(args, bin_name);
31+
create_tauri_app::run(
32+
args,
33+
bin_name,
34+
if is_cargo { Some("cargo".into()) } else { None },
35+
);
3336
}

0 commit comments

Comments
 (0)