1414 * limitations under the License.
1515 */
1616
17+ use std:: { env, fs, future, io, process} ;
1718use std:: collections:: { BTreeMap , HashMap } ;
1819use std:: ffi:: OsStr ;
1920use std:: future:: Future ;
@@ -24,28 +25,28 @@ use std::os::unix::process::CommandExt;
2425use std:: os:: windows:: process:: CommandExt ;
2526use std:: path:: PathBuf ;
2627use std:: process:: Stdio ;
27- use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
2828use std:: sync:: Arc ;
29+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
2930use std:: time:: { Duration , Instant } ;
30- use std:: { env, fs, future, io, process} ;
3131
3232use anyhow:: { anyhow, Context , Error , Result } ;
3333use clap:: ValueEnum ;
3434use futures:: future:: { BoxFuture , FutureExt } ;
3535use log:: { error, info, warn} ;
3636use notify:: { ErrorKind , Event , PollWatcher , RecommendedWatcher , RecursiveMode , Watcher } ;
37- use serde:: { de, ser , Deserialize , Serialize } ;
37+ use serde:: { de, Deserialize , ser , Serialize } ;
3838use tokio:: io:: { AsyncReadExt , AsyncWriteExt } ;
3939use tokio:: process:: { Child , ChildStdin , ChildStdout , Command } ;
40+ use tokio:: sync:: { mpsc, Mutex , oneshot} ;
4041use tokio:: sync:: oneshot:: { Receiver , Sender } ;
41- use tokio:: sync:: { mpsc, oneshot, Mutex } ;
4242use tokio:: time:: timeout;
4343
4444use crate :: cs:: { ClientArgs , ServerArgs } ;
4545
4646#[ derive( Debug ) ]
4747pub struct ManagerArgs {
4848 pub config : Option < PathBuf > ,
49+ pub depth : Option < u8 > ,
4950 pub server_args : Option < ServerArgs > ,
5051 pub client_args : Option < ClientArgs > ,
5152}
@@ -87,6 +88,46 @@ impl Manager {
8788 }
8889 }
8990
91+ fn collect_files ( & self , path : PathBuf , depth : u8 ) -> io:: Result < Vec < ProcessConfigEnum > > {
92+ let mut files = vec ! [ ] ;
93+ if path. is_dir ( ) {
94+ for entry in fs:: read_dir ( path) ? {
95+ let entry = entry?;
96+ let path = entry. path ( ) ;
97+ if path. is_dir ( ) {
98+ let max = self . args . depth . unwrap_or ( 3 ) ;
99+ if max != 0 && depth + 1 > max {
100+ info ! ( "{} is too deep" , path. display( ) ) ;
101+ continue ;
102+ }
103+ files. append ( self . collect_files ( path, depth + 1 ) ?. as_mut ( ) ) ;
104+ } else {
105+ match path. extension ( ) . and_then ( OsStr :: to_str) {
106+ Some ( "yaml" ) | Some ( "yml" ) => { }
107+ None | Some ( _) => {
108+ info ! (
109+ "ignored file {} is not end with yml or yaml" ,
110+ path. display( )
111+ ) ;
112+ continue ;
113+ }
114+ }
115+ let fm = entry. metadata ( ) ?. len ( ) ;
116+ if fm > 10 * 1024 * 1024 {
117+ info ! ( "ignored file {} is too large" , path. display( ) ) ;
118+ continue ;
119+ }
120+ info ! ( "collected file {}" , path. display( ) ) ;
121+ files. push ( ProcessConfigEnum :: Config ( path) ) ;
122+ }
123+ }
124+ } else {
125+ info ! ( "collected file {}" , path. display( ) ) ;
126+ files. push ( ProcessConfigEnum :: Config ( path) ) ;
127+ }
128+ Ok ( files)
129+ }
130+
90131 async fn collect_configs (
91132 & self ,
92133 ) -> Result < ( Vec < ProcessConfigEnum > , Option < Vec < ProcessConfigEnum > > ) > {
@@ -100,7 +141,7 @@ impl Manager {
100141 None => env:: current_dir ( ) ?,
101142 Some ( path) => path. into ( ) ,
102143 } ;
103- configs = collect_files ( config. clone ( ) ) ?;
144+ configs = self . collect_files ( config. clone ( ) , 1 ) ?;
104145 }
105146 if configs. is_empty ( ) {
106147 return Err ( anyhow ! ( "no target found" ) ) ;
@@ -324,9 +365,7 @@ impl Manager {
324365 let reconnect = async {
325366 let cmds = cmd_map. clone ( ) ;
326367 let config = config. clone ( ) ;
327- if let Err ( e) =
328- Self :: sync_run ( cmds, vec ! [ config. clone( ) ] , sub_cmd) . await
329- {
368+ if let Err ( e) = Self :: sync_run ( cmds, vec ! [ config. clone( ) ] , sub_cmd) . await {
330369 error ! ( "{sub_cmd} ({config:?}) reconnect sync_run failed: {:?}" , e) ;
331370 }
332371 } ;
@@ -427,23 +466,15 @@ impl Manager {
427466 }
428467 }
429468 if !server_config. is_empty ( ) {
430- Self :: run (
431- self . cmds . clone ( ) ,
432- server_config,
433- "sub-server" ,
434- )
435- . await
436- . context ( "run_server failed" ) ?;
469+ Self :: run ( self . cmds . clone ( ) , server_config, "sub-server" )
470+ . await
471+ . context ( "run_server failed" ) ?;
437472 }
438473
439474 if !client_config. is_empty ( ) {
440- Self :: run (
441- self . cmds . clone ( ) ,
442- client_config,
443- "sub-client" ,
444- )
445- . await
446- . context ( "run_client failed" ) ?;
475+ Self :: run ( self . cmds . clone ( ) , client_config, "sub-client" )
476+ . await
477+ . context ( "run_client failed" ) ?;
447478 }
448479 Ok ( ( ) )
449480 }
@@ -759,41 +790,6 @@ pub fn send_signal(signal: Signal) -> Result<()> {
759790 Ok ( ( ) )
760791}
761792
762- fn collect_files ( path : PathBuf ) -> io:: Result < Vec < ProcessConfigEnum > > {
763- let mut files = vec ! [ ] ;
764- if path. is_dir ( ) {
765- for entry in fs:: read_dir ( path) ? {
766- let entry = entry?;
767- let path = entry. path ( ) ;
768- if path. is_dir ( ) {
769- collect_files ( path) ?;
770- } else {
771- let fm = entry. metadata ( ) ?. len ( ) ;
772- if fm > 10 * 1024 * 1024 {
773- info ! ( "ignored file {} is too large" , path. display( ) ) ;
774- continue ;
775- }
776- match path. extension ( ) . and_then ( OsStr :: to_str) {
777- Some ( "yaml" ) | Some ( "yml" ) => { }
778- None | Some ( _) => {
779- info ! (
780- "ignored file {} is not end with yml or yaml" ,
781- path. display( )
782- ) ;
783- continue ;
784- }
785- }
786- info ! ( "collected file {}" , path. display( ) ) ;
787- files. push ( ProcessConfigEnum :: Config ( path) ) ;
788- }
789- }
790- } else {
791- info ! ( "collected file {}" , path. display( ) ) ;
792- files. push ( ProcessConfigEnum :: Config ( path) ) ;
793- }
794- Ok ( files)
795- }
796-
797793#[ derive( Serialize , Deserialize , Debug ) ]
798794struct Config {
799795 #[ serde( rename = "type" ) ]
0 commit comments