@@ -62,19 +62,25 @@ pub struct NewOptions {
62
62
pub enum NewProjectKind {
63
63
Bin ,
64
64
Lib ,
65
+ Auto ,
65
66
}
66
67
67
68
impl NewProjectKind {
68
69
fn is_bin ( self ) -> bool {
69
70
self == NewProjectKind :: Bin
70
71
}
72
+
73
+ fn is_auto ( self ) -> bool {
74
+ self == NewProjectKind :: Auto
75
+ }
71
76
}
72
77
73
78
impl fmt:: Display for NewProjectKind {
74
79
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
75
80
match * self {
76
81
NewProjectKind :: Bin => "binary (application)" ,
77
82
NewProjectKind :: Lib => "library" ,
83
+ NewProjectKind :: Auto => "auto-select type" ,
78
84
}
79
85
. fmt ( f)
80
86
}
@@ -109,8 +115,8 @@ impl NewOptions {
109
115
let kind = match ( bin, lib) {
110
116
( true , true ) => anyhow:: bail!( "can't specify both lib and binary outputs" ) ,
111
117
( false , true ) => NewProjectKind :: Lib ,
112
- // default to bin
113
- ( _ , false ) => NewProjectKind :: Bin ,
118
+ ( true , false ) => NewProjectKind :: Bin ,
119
+ ( false , false ) => NewProjectKind :: Auto ,
114
120
} ;
115
121
116
122
let opts = NewOptions {
@@ -389,7 +395,26 @@ fn plan_new_source_file(bin: bool, package_name: String) -> SourceFileInformatio
389
395
}
390
396
}
391
397
392
- pub fn new ( opts : & NewOptions , config : & Config ) -> CargoResult < ( ) > {
398
+ fn calculate_new_project_kind (
399
+ requested_kind : NewProjectKind ,
400
+ found_files : & Vec < SourceFileInformation > ,
401
+ ) -> NewProjectKind {
402
+ let bin_file = found_files. iter ( ) . find ( |x| x. bin ) ;
403
+
404
+ let kind_from_files = if !found_files. is_empty ( ) && bin_file. is_none ( ) {
405
+ NewProjectKind :: Lib
406
+ } else {
407
+ NewProjectKind :: Bin
408
+ } ;
409
+
410
+ if requested_kind. is_auto ( ) {
411
+ return kind_from_files;
412
+ }
413
+
414
+ requested_kind
415
+ }
416
+
417
+ pub fn new ( opts : & NewOptions , config : & Config ) -> CargoResult < NewProjectKind > {
393
418
let path = & opts. path ;
394
419
if path. exists ( ) {
395
420
anyhow:: bail!(
@@ -399,20 +424,22 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
399
424
)
400
425
}
401
426
427
+ let kind = match opts. kind {
428
+ NewProjectKind :: Bin => NewProjectKind :: Bin ,
429
+ NewProjectKind :: Auto => NewProjectKind :: Bin ,
430
+ _ => NewProjectKind :: Lib ,
431
+ } ;
432
+ let is_bin = kind. is_bin ( ) ;
433
+
402
434
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
- ) ?;
435
+ check_name ( name, opts. name . is_none ( ) , is_bin, & mut config. shell ( ) ) ?;
409
436
410
437
let mkopts = MkOptions {
411
438
version_control : opts. version_control ,
412
439
path,
413
440
name,
414
441
source_files : vec ! [ plan_new_source_file( opts. kind. is_bin( ) , name. to_string( ) ) ] ,
415
- bin : opts . kind . is_bin ( ) ,
442
+ bin : is_bin,
416
443
edition : opts. edition . as_deref ( ) ,
417
444
registry : opts. registry . as_deref ( ) ,
418
445
} ;
@@ -424,10 +451,10 @@ pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
424
451
path. display( )
425
452
)
426
453
} ) ?;
427
- Ok ( ( ) )
454
+ Ok ( kind )
428
455
}
429
456
430
- pub fn init ( opts : & NewOptions , config : & Config ) -> CargoResult < ( ) > {
457
+ pub fn init ( opts : & NewOptions , config : & Config ) -> CargoResult < NewProjectKind > {
431
458
// This is here just as a random location to exercise the internal error handling.
432
459
if std:: env:: var_os ( "__CARGO_TEST_INTERNAL_ERROR" ) . is_some ( ) {
433
460
return Err ( crate :: util:: internal ( "internal error test" ) ) ;
@@ -445,14 +472,34 @@ pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
445
472
446
473
detect_source_paths_and_types ( path, name, & mut src_paths_types) ?;
447
474
475
+ let kind = calculate_new_project_kind ( opts. kind , & src_paths_types) ;
476
+ let has_bin = kind. is_bin ( ) ;
477
+
448
478
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"
479
+ src_paths_types. push ( plan_new_source_file ( has_bin, name. to_string ( ) ) ) ;
480
+ } else if src_paths_types. len ( ) == 1 && !src_paths_types. iter ( ) . any ( |x| x. bin == has_bin) {
481
+ // we've found the only file and it's not the type user wants. Change the type and warn
482
+ let file_type = if src_paths_types[ 0 ] . bin {
483
+ NewProjectKind :: Bin . to_string ( )
484
+ } else {
485
+ NewProjectKind :: Lib . to_string ( )
486
+ } ;
487
+ config. shell ( ) . warn ( format ! (
488
+ "file '{}' seems to be a {} file" ,
489
+ src_paths_types[ 0 ] . relative_path, file_type
490
+ ) ) ?;
491
+ src_paths_types[ 0 ] . bin = has_bin
492
+ } else if src_paths_types. len ( ) > 1 && !has_bin {
493
+ // We have found both lib and bin files and the user would like us to treat both as libs
494
+ anyhow:: bail!(
495
+ "cannot have a package with \
496
+ multiple libraries, \
497
+ found both `{}` and `{}`",
498
+ src_paths_types[ 0 ] . relative_path,
499
+ src_paths_types[ 1 ] . relative_path
500
+ )
454
501
}
455
- let has_bin = src_paths_types . iter ( ) . any ( |x| x . bin ) ;
502
+
456
503
check_name ( name, opts. name . is_none ( ) , has_bin, & mut config. shell ( ) ) ?;
457
504
458
505
let mut version_control = opts. version_control ;
@@ -508,7 +555,7 @@ pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
508
555
path. display( )
509
556
)
510
557
} ) ?;
511
- Ok ( ( ) )
558
+ Ok ( kind )
512
559
}
513
560
514
561
/// IgnoreList
0 commit comments