@@ -72,6 +72,25 @@ struct Outputs {
7272 out : String ,
7373}
7474
75+ fn is_target_for_packaging ( src_dir : & PathBuf ) -> bool {
76+ let has_cargo = src_dir. join ( "Cargo.toml" ) . is_file ( ) ;
77+ let cargo_lock = File :: open ( src_dir. join ( "Cargo.lock" ) ) ;
78+ let has_cargo_lock = cargo_lock. is_ok ( ) ;
79+ let has_cmake = src_dir. join ( "CMakeLists.txt" ) . is_file ( ) ;
80+ let has_go = src_dir. join ( "go.mod" ) . is_file ( ) ;
81+ let has_meson = src_dir. join ( "meson.build" ) . is_file ( ) ;
82+ let pyproject_toml = src_dir. join ( "pyproject.toml" ) ;
83+ let has_pyproject = pyproject_toml. is_file ( ) ;
84+ let has_setuptools = src_dir. join ( "setup.py" ) . is_file ( ) ;
85+
86+ ( has_cargo && has_cargo_lock)
87+ || has_cmake
88+ || has_go
89+ || has_meson
90+ || has_pyproject
91+ || has_setuptools
92+ }
93+
7594#[ tokio:: main]
7695async fn main ( ) -> Result < ( ) > {
7796 run ( ) . await
@@ -394,7 +413,74 @@ async fn run() -> Result<()> {
394413 PathBuf :: from ( & src)
395414 } ;
396415
397- let mut choices = Vec :: new ( ) ;
416+ // Let's first find all subdirectories that are compatible with our supported recipes.
417+ let root_src_dir = src_dir. clone ( ) ;
418+ let mut open_subdirs = vec ! [ ( 0 , src_dir) ] ;
419+ let mut sourceroot_candidates = vec ! [ ] ;
420+ while !open_subdirs. is_empty ( ) {
421+ // If we call this, we have a non-empty vector.
422+ let ( depth, target_dir) = open_subdirs. pop ( ) . unwrap ( ) ;
423+ let subdirs = std:: fs:: read_dir ( & target_dir) . with_context ( || {
424+ format ! ( "failed to list subdirectories of {}" , target_dir. display( ) )
425+ } ) ?;
426+
427+ for maybe_subdir in subdirs {
428+ let subdir = maybe_subdir. context ( format ! (
429+ "unexpected io error while reading a subdirectory of {}" ,
430+ target_dir. to_string_lossy( )
431+ ) ) ?;
432+
433+ let subdir_path = & subdir. path ( ) ;
434+
435+ // We want only subdirectories.
436+ if !subdir_path. is_dir ( ) {
437+ continue ;
438+ }
439+
440+ if is_target_for_packaging ( subdir_path) {
441+ sourceroot_candidates. push ( subdir. file_name ( ) ) ;
442+ }
443+
444+ // Recurse into that subdir.
445+ if depth < 3 {
446+ open_subdirs. push ( ( depth + 1 , subdir_path. to_path_buf ( ) ) ) ;
447+ }
448+ }
449+ }
450+
451+ editor. set_helper ( Some ( Prompter :: List (
452+ sourceroot_candidates
453+ . iter ( )
454+ . map ( |sr| {
455+ PathBuf :: from ( sr) . strip_prefix ( & root_src_dir)
456+ . expect ( "Failed to strip the root source directory prefix" )
457+ . to_string_lossy ( )
458+ . to_string ( )
459+ } )
460+ . collect ( ) ,
461+ ) ) ) ;
462+ let choice = editor. readline ( & prompt ( "Which subdirectory should we use?" ) ) ?;
463+ let src_dir = & PathBuf :: from ( choice
464+ . parse ( )
465+ . ok ( )
466+ . and_then ( |i : usize | sourceroot_candidates. get ( i) )
467+ . unwrap_or_else ( || & sourceroot_candidates[ 0 ] ) ) ;
468+ let source_root = if src_dir != & root_src_dir {
469+ Some ( src_dir)
470+ } else {
471+ None
472+ } ;
473+ let source_root_expr = match source_root {
474+ Some ( subdir) => format ! (
475+ "\n sourceRoot = \" source/{}\" ;" ,
476+ subdir
477+ . strip_prefix( & root_src_dir)
478+ . expect( "Failed to strip the root source directory prefix" )
479+ . to_string_lossy( )
480+ ) ,
481+ None => "" . to_string ( ) ,
482+ } ;
483+
398484 let has_cargo = src_dir. join ( "Cargo.toml" ) . is_file ( ) ;
399485 let cargo_lock = File :: open ( src_dir. join ( "Cargo.lock" ) ) ;
400486 let has_cargo_lock = cargo_lock. is_ok ( ) ;
@@ -405,6 +491,7 @@ async fn run() -> Result<()> {
405491 let has_pyproject = pyproject_toml. is_file ( ) ;
406492 let has_setuptools = src_dir. join ( "setup.py" ) . is_file ( ) ;
407493
494+ let mut choices = Vec :: new ( ) ;
408495 let rust_vendors = if has_cargo {
409496 if cargo_lock. map_or ( true , |file| {
410497 BufReader :: new ( file)
@@ -454,7 +541,6 @@ async fn run() -> Result<()> {
454541 }
455542
456543 choices. push ( BuildType :: MkDerivation { rust : None } ) ;
457-
458544 editor. set_helper ( Some ( Prompter :: Build ( choices) ) ) ;
459545 let choice = editor. readline ( & prompt ( "How should this package be built?" ) ) ?;
460546 let Some ( Prompter :: Build ( choices) ) = editor. helper_mut ( ) else {
@@ -564,7 +650,7 @@ async fn run() -> Result<()> {
564650 pname = {pname:?};
565651 version = {version:?};
566652
567- src = {src_expr};
653+ src = {src_expr};{source_root_expr}
568654
569655 vendorHash = {hash};
570656
@@ -653,7 +739,7 @@ async fn run() -> Result<()> {
653739 version = {version:?};
654740 format = "{format}";
655741
656- src = {src_expr};
742+ src = {src_expr};{source_root_expr}
657743
658744 "# ,
659745 if application {
@@ -712,7 +798,7 @@ async fn run() -> Result<()> {
712798 pname = {pname:?};
713799 version = {version:?};
714800
715- src = {src_expr};
801+ src = {src_expr};{source_root_expr}
716802
717803 cargoHash = "{hash}";
718804
@@ -742,7 +828,7 @@ async fn run() -> Result<()> {
742828 pname = "{pname}";
743829 version = "{version}";
744830
745- src = {src_expr};
831+ src = {src_expr};{source_root_expr}
746832
747833 cargoLock = "# ,
748834 ) ?;
@@ -762,6 +848,7 @@ async fn run() -> Result<()> {
762848 version = {version:?};
763849
764850 src = {src_expr};
851+ {source_root_expr}
765852
766853 "# ,
767854 ) ?;
@@ -791,7 +878,7 @@ async fn run() -> Result<()> {
791878 pname = {pname:?};
792879 version = {version:?};
793880
794- src = {src_expr};
881+ src = {src_expr};{source_root_expr}
795882
796883 cargoDeps = rustPlatform.fetchCargoTarball {{
797884 inherit src;
@@ -824,7 +911,7 @@ async fn run() -> Result<()> {
824911 pname = "{pname}";
825912 version = "{version}";
826913
827- src = {src_expr};
914+ src = {src_expr};{source_root_expr}
828915
829916 cargoDeps = rustPlatform.importCargoLock "# ,
830917 ) ?;
@@ -908,7 +995,7 @@ async fn run() -> Result<()> {
908995 }
909996
910997 let mut desc = desc. trim_matches ( |c : char | !c. is_alphanumeric ( ) ) . to_owned ( ) ;
911- desc. get_mut ( 0 .. 1 ) . map ( str:: make_ascii_uppercase) ;
998+ desc. get_mut ( 0 .. 1 ) . map ( str:: make_ascii_uppercase) ;
912999 write ! ( out, " " ) ?;
9131000 writedoc ! (
9141001 out,
@@ -1022,5 +1109,5 @@ fn get_version(rev: &str) -> &str {
10221109}
10231110
10241111fn get_version_number ( rev : & str ) -> & str {
1025- & rev[ rev. find ( char:: is_numeric) . unwrap_or_default ( ) ..]
1112+ & rev[ rev. find ( char:: is_numeric) . unwrap_or_default ( ) ..]
10261113}
0 commit comments