@@ -51,6 +51,7 @@ impl<'de> de::Deserialize<'de> for VersionControl {
51
51
pub struct NewOptions {
52
52
pub version_control : Option < VersionControl > ,
53
53
pub kind : NewProjectKind ,
54
+ pub auto_detect_kind : bool ,
54
55
/// Absolute path to the directory for the new package
55
56
pub path : PathBuf ,
56
57
pub name : Option < String > ,
@@ -106,16 +107,18 @@ impl NewOptions {
106
107
edition : Option < String > ,
107
108
registry : Option < String > ,
108
109
) -> CargoResult < NewOptions > {
110
+ let auto_detect_kind = !bin && !lib;
111
+
109
112
let kind = match ( bin, lib) {
110
113
( true , true ) => anyhow:: bail!( "can't specify both lib and binary outputs" ) ,
111
114
( false , true ) => NewProjectKind :: Lib ,
112
- // default to bin
113
115
( _, false ) => NewProjectKind :: Bin ,
114
116
} ;
115
117
116
118
let opts = NewOptions {
117
119
version_control,
118
120
kind,
121
+ auto_detect_kind,
119
122
path,
120
123
name,
121
124
edition,
@@ -389,6 +392,26 @@ fn plan_new_source_file(bin: bool, package_name: String) -> SourceFileInformatio
389
392
}
390
393
}
391
394
395
+ fn calculate_new_project_kind (
396
+ requested_kind : NewProjectKind ,
397
+ auto_detect_kind : bool ,
398
+ found_files : & Vec < SourceFileInformation > ,
399
+ ) -> NewProjectKind {
400
+ let bin_file = found_files. iter ( ) . find ( |x| x. bin ) ;
401
+
402
+ let kind_from_files = if !found_files. is_empty ( ) && bin_file. is_none ( ) {
403
+ NewProjectKind :: Lib
404
+ } else {
405
+ NewProjectKind :: Bin
406
+ } ;
407
+
408
+ if auto_detect_kind {
409
+ return kind_from_files;
410
+ }
411
+
412
+ requested_kind
413
+ }
414
+
392
415
pub fn new ( opts : & NewOptions , config : & Config ) -> CargoResult < ( ) > {
393
416
let path = & opts. path ;
394
417
if path. exists ( ) {
@@ -399,20 +422,17 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
399
422
)
400
423
}
401
424
425
+ let is_bin = opts. kind . is_bin ( ) ;
426
+
402
427
let name = get_name ( path, opts) ?;
403
- check_name (
404
- name,
405
- opts. name . is_none ( ) ,
406
- opts. kind . is_bin ( ) ,
407
- & mut config. shell ( ) ,
408
- ) ?;
428
+ check_name ( name, opts. name . is_none ( ) , is_bin, & mut config. shell ( ) ) ?;
409
429
410
430
let mkopts = MkOptions {
411
431
version_control : opts. version_control ,
412
432
path,
413
433
name,
414
434
source_files : vec ! [ plan_new_source_file( opts. kind. is_bin( ) , name. to_string( ) ) ] ,
415
- bin : opts . kind . is_bin ( ) ,
435
+ bin : is_bin,
416
436
edition : opts. edition . as_deref ( ) ,
417
437
registry : opts. registry . as_deref ( ) ,
418
438
} ;
@@ -427,7 +447,7 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
427
447
Ok ( ( ) )
428
448
}
429
449
430
- pub fn init ( opts : & NewOptions , config : & Config ) -> CargoResult < ( ) > {
450
+ pub fn init ( opts : & NewOptions , config : & Config ) -> CargoResult < NewProjectKind > {
431
451
// This is here just as a random location to exercise the internal error handling.
432
452
if std:: env:: var_os ( "__CARGO_TEST_INTERNAL_ERROR" ) . is_some ( ) {
433
453
return Err ( crate :: util:: internal ( "internal error test" ) ) ;
@@ -445,14 +465,34 @@ pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
445
465
446
466
detect_source_paths_and_types ( path, name, & mut src_paths_types) ?;
447
467
468
+ let kind = calculate_new_project_kind ( opts. kind , opts. auto_detect_kind , & src_paths_types) ;
469
+ let has_bin = kind. is_bin ( ) ;
470
+
448
471
if src_paths_types. is_empty ( ) {
449
- src_paths_types. push ( plan_new_source_file ( opts. kind . is_bin ( ) , name. to_string ( ) ) ) ;
450
- } else {
451
- // --bin option may be ignored if lib.rs or src/lib.rs present
452
- // Maybe when doing `cargo init --bin` inside a library package stub,
453
- // user may mean "initialize for library, but also add binary target"
472
+ src_paths_types. push ( plan_new_source_file ( has_bin, name. to_string ( ) ) ) ;
473
+ } else if src_paths_types. len ( ) == 1 && !src_paths_types. iter ( ) . any ( |x| x. bin == has_bin) {
474
+ // we've found the only file and it's not the type user wants. Change the type and warn
475
+ let file_type = if src_paths_types[ 0 ] . bin {
476
+ NewProjectKind :: Bin
477
+ } else {
478
+ NewProjectKind :: Lib
479
+ } ;
480
+ config. shell ( ) . warn ( format ! (
481
+ "file `{}` seems to be a {} file" ,
482
+ src_paths_types[ 0 ] . relative_path, file_type
483
+ ) ) ?;
484
+ src_paths_types[ 0 ] . bin = has_bin
485
+ } else if src_paths_types. len ( ) > 1 && !has_bin {
486
+ // We have found both lib and bin files and the user would like us to treat both as libs
487
+ anyhow:: bail!(
488
+ "cannot have a package with \
489
+ multiple libraries, \
490
+ found both `{}` and `{}`",
491
+ src_paths_types[ 0 ] . relative_path,
492
+ src_paths_types[ 1 ] . relative_path
493
+ )
454
494
}
455
- let has_bin = src_paths_types . iter ( ) . any ( |x| x . bin ) ;
495
+
456
496
check_name ( name, opts. name . is_none ( ) , has_bin, & mut config. shell ( ) ) ?;
457
497
458
498
let mut version_control = opts. version_control ;
@@ -508,7 +548,7 @@ pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
508
548
path. display( )
509
549
)
510
550
} ) ?;
511
- Ok ( ( ) )
551
+ Ok ( kind )
512
552
}
513
553
514
554
/// IgnoreList
0 commit comments