@@ -7,13 +7,15 @@ extern crate ssh2;
77
88use bzip2:: read:: BzDecoder ;
99use clap:: { Arg , Command as App } ;
10+ use env_logger:: Env ;
11+ use log:: { debug, error, info, warn} ;
1012use regex:: Regex ;
1113use serde:: { Deserialize , Serialize } ;
1214use ssh2:: Session ;
1315use std:: collections:: HashMap ;
1416use std:: error:: Error ;
1517use std:: fs:: { self , File } ;
16- use std:: io:: { copy, BufReader , BufWriter , Read } ;
18+ use std:: io:: { copy, BufReader , BufWriter , Read , Write } ;
1719use std:: net:: TcpStream ;
1820use std:: path:: Path ;
1921use std:: process;
@@ -44,13 +46,12 @@ impl Config {
4446 let ssh_host = cap
4547 . get ( 2 )
4648 . unwrap_or_else ( || {
47- eprintln ! ( "Failed to parse ssh host" ) ;
49+ error ! ( "Failed to parse ssh host" ) ;
4850 process:: exit ( 1 ) ;
4951 } )
5052 . as_str ( ) ;
5153
5254 let mut config: Config = match config_file. exists ( ) {
53- // let config_path = ;
5455 true => Config :: parse ( config_file. to_str ( ) . unwrap ( ) , ssh_host) ,
5556 false => Config {
5657 ssh_host : ssh_host. to_string ( ) ,
@@ -62,7 +63,7 @@ impl Config {
6263 match cap. get ( 1 ) {
6364 Some ( val) => config. ssh_user = val. as_str ( ) . to_string ( ) ,
6465 None => {
65- eprintln ! ( "SSH username cannot be empty" ) ;
66+ error ! ( "SSH username cannot be empty" ) ;
6667 process:: exit ( 1 ) ;
6768 }
6869 }
@@ -78,7 +79,7 @@ impl Config {
7879 match Config :: parse_config_file ( path, host) {
7980 Ok ( config) => config,
8081 Err ( err) => {
81- eprintln ! ( "Failed to parse config file - {}" , err) ;
82+ error ! ( "Failed to parse config file - {}" , err) ;
8283 Config {
8384 ssh_host : host. to_string ( ) ,
8485 ..Default :: default ( )
@@ -100,6 +101,11 @@ impl Config {
100101}
101102
102103fn main ( ) -> Result < ( ) , Box < dyn Error > > {
104+ // Initialize the logger with the default environment variable "RUST_LOG"
105+ env_logger:: Builder :: from_env ( Env :: default ( ) . default_filter_or ( "info" ) )
106+ . format ( |buf, record| writeln ! ( buf, "[{}] {}" , record. level( ) , record. args( ) ) )
107+ . init ( ) ;
108+
103109 let matches = App :: new ( "Database Importer" )
104110 . about ( "Import database from remote server" )
105111 . arg (
@@ -156,7 +162,7 @@ fn main() -> Result<(), Box<dyn Error>> {
156162 let host = match matches. value_of ( "host" ) {
157163 Some ( n) => n,
158164 None => {
159- eprintln ! ( "Target host cannot be empty" ) ;
165+ error ! ( "Target host cannot be empty" ) ;
160166 process:: exit ( 1 ) ;
161167 }
162168 } ;
@@ -166,7 +172,7 @@ fn main() -> Result<(), Box<dyn Error>> {
166172 let tables = match matches. values_of ( "table" ) {
167173 Some ( n) => n,
168174 None => {
169- eprintln ! ( "Target tables cannot be empty" ) ;
175+ error ! ( "Target tables cannot be empty" ) ;
170176 process:: exit ( 1 ) ;
171177 }
172178 } ;
@@ -182,7 +188,7 @@ fn main() -> Result<(), Box<dyn Error>> {
182188 None => {
183189 // User option was not specified.
184190 // Use ssh username, if available
185- eprintln ! ( "Using SSH username as database username" ) ;
191+ info ! ( "Using SSH username as database username" ) ;
186192 config. ssh_user . to_owned ( )
187193 }
188194 } ,
@@ -195,18 +201,18 @@ fn main() -> Result<(), Box<dyn Error>> {
195201 None => {
196202 // User option was not specified.
197203 // Use ssh username, if available
198- eprintln ! ( "Inferring database name as {}_db" , db_user) ;
204+ info ! ( "Inferring database name as {}_db" , db_user) ;
199205 format ! ( "{}_db" , db_user)
200206 }
201207 } ,
202208 } ;
203209
204- let db_pass = match matches. value_of ( "db_pass " ) {
210+ let db_pass = match matches. value_of ( "dbpass " ) {
205211 Some ( val) => val. to_owned ( ) ,
206212 None => match config. db_pass {
207213 Some ( val) => val,
208214 None => {
209- eprintln ! ( "Database password cannot be empty" ) ;
215+ error ! ( "Database password cannot be empty" ) ;
210216 process:: exit ( 2 ) ;
211217 }
212218 } ,
@@ -217,7 +223,7 @@ fn main() -> Result<(), Box<dyn Error>> {
217223 // Connect to the remote server
218224 let ssh_host_port = format ! ( "{}:{}" , config. ssh_host, config. ssh_port) ;
219225 let tcp = TcpStream :: connect ( & ssh_host_port) . unwrap_or_else ( |err| {
220- eprintln ! ( "{}" , err) ;
226+ error ! ( "{}" , err) ;
221227 process:: exit ( 1 ) ;
222228 } ) ;
223229
@@ -226,24 +232,21 @@ fn main() -> Result<(), Box<dyn Error>> {
226232 sess. handshake ( ) . expect ( "SSH handshake failed" ) ;
227233
228234 // Try to authenticate with the first identity in the agent.
229- eprint ! ( "Attept to authenticate with ssh-agent..." ) ;
235+ info ! ( "Attempt to authenticate with ssh-agent..." ) ;
230236 let _ = sess. userauth_agent ( & config. ssh_user ) ;
231237
232238 // Make sure we succeeded
233239 if !sess. authenticated ( ) {
234- eprintln ! ( "FAILED" ) ;
235-
236- eprintln ! ( "Falling back to password login" ) ;
237- eprint ! ( "Enter password: " ) ;
238-
240+ warn ! ( "SSH-agent authentication failed. Falling back to password login." ) ;
241+ info ! ( "Enter password: " ) ;
239242 let ssh_pass = rpassword:: read_password ( ) . unwrap ( ) ;
240243 sess. userauth_password ( & config. ssh_user , & ssh_pass)
241244 . unwrap_or_else ( |_| {
242- eprintln ! ( "Failed to authenticate to remote server" ) ;
245+ error ! ( "Failed to authenticate to remote server" ) ;
243246 process:: exit ( 1 ) ;
244247 } ) ;
245248 } else {
246- eprintln ! ( "OK " ) ;
249+ info ! ( "SSH-agent authentication succeeded. " ) ;
247250 }
248251
249252 let mut remote_temp_file = String :: new ( ) ;
@@ -254,13 +257,6 @@ fn main() -> Result<(), Box<dyn Error>> {
254257 channel. read_to_string ( & mut remote_temp_file) . unwrap ( ) ;
255258 let remote_temp_file = remote_temp_file. trim ( ) ;
256259
257- // ctrlc::set_handler(move || {
258- // // Handle early termination
259- // let status = sess.sftp().and_then(|sftp| {
260- // sftp.unlink(Path::new(remote_temp_file))
261- // });
262- // }).expect("Error setting Ctrl-C handler");
263-
264260 let pass_arg = format ! ( "-p{}" , & db_pass) ;
265261 let mut v = vec ! [ "mysqldump" , "-u" , & db_user, & pass_arg, & db_name] ;
266262
@@ -279,33 +275,29 @@ fn main() -> Result<(), Box<dyn Error>> {
279275 remote_temp_file
280276 ) ;
281277
282- eprint ! ( "Exporting database on target server..." ) ;
278+ info ! ( "Exporting database on target server..." ) ;
283279 let mut channel = sess. channel_session ( ) . ok ( ) . unwrap ( ) ;
284280 let exit_status = channel
285281 . exec ( & arg)
286282 . and_then ( |_| channel. close ( ) )
287- // .and_then(|_| channel.wait_close())
288283 . and_then ( |_| channel. exit_status ( ) ) ;
289284
290285 match exit_status {
291- Ok ( 0 ) => ( ) ,
286+ Ok ( 0 ) => info ! ( "Database export succeeded." ) ,
292287 _ => {
293- eprintln ! ( "ERR" ) ;
294- eprintln ! ( "Failed to export database" ) ;
288+ error ! ( "Failed to export database" ) ;
295289 process:: exit ( 4 ) ;
296290 }
297291 }
298292
299- eprintln ! ( "OK" ) ;
300-
301293 let ( remote_file, stat) = sess
302294 . scp_recv ( Path :: new ( & remote_temp_file) )
303295 . unwrap_or_else ( |err| {
304- eprintln ! ( "Failed to download file - {}" , err) ;
296+ error ! ( "Failed to download file - {}" , err) ;
305297 process:: exit ( 2 ) ;
306298 } ) ;
307299
308- eprintln ! ( "Exported file size: {}" , stat. size( ) ) ;
300+ info ! ( "Exported file size: {}" , stat. size( ) ) ;
309301
310302 let temp_file = Builder :: new ( )
311303 . suffix ( ".sql.bz2" )
@@ -325,13 +317,13 @@ fn main() -> Result<(), Box<dyn Error>> {
325317 match copy ( & mut remote_file, & mut target) {
326318 Ok ( _) => ( ) ,
327319 Err ( err) => {
328- eprintln ! ( "Failed to download exported database dump - {}" , err) ;
320+ error ! ( "Failed to download exported database dump - {}" , err) ;
329321 process:: exit ( 3 ) ;
330322 }
331323 }
324+ debug ! ( "Database dump downloaded to {:?}" , path) ;
332325
333326 progressbar. finish_and_clear ( ) ;
334- println ! ( "Downloading database dump...OK" ) ;
335327
336328 let mut channel = sess. channel_session ( ) . ok ( ) . unwrap ( ) ;
337329 let arg = format ! ( "rm -f {}" , remote_temp_file) ;
@@ -341,8 +333,8 @@ fn main() -> Result<(), Box<dyn Error>> {
341333 . and_then ( |_| channel. exit_status ( ) ) ;
342334
343335 match exit_status {
344- Ok ( 0 ) => eprintln ! ( "Removed temporary file from remote filesystem...OK " ) ,
345- _ => eprintln ! ( "Failed to delete temporary file from remote filesystem" ) ,
336+ Ok ( 0 ) => info ! ( "Removed temporary file from remote filesystem." ) ,
337+ _ => warn ! ( "Failed to delete temporary file from remote filesystem. " ) ,
346338 }
347339
348340 // TODO: Delete temporary file from remote filesystem
@@ -356,35 +348,38 @@ fn main() -> Result<(), Box<dyn Error>> {
356348 . spawn ( )
357349 . expect ( "Failed to spawn mysql client" ) ;
358350
351+ debug ! ( "Spawning mysql client" ) ;
359352 if let Some ( stdin) = & mut cmd. stdin {
360353 let mut writer = BufWriter :: new ( stdin) ;
361354
355+ debug ! ( "Copying uncompressed dump to mysql client stdin" ) ;
362356 // Decompress and import to local mysql database
363357 match copy ( & mut Box :: new ( BzDecoder :: new ( f) ) , & mut writer) {
364- Ok ( _) => {
365- eprintln ! ( "Import completed successfully" )
366- }
358+ Ok ( _) => info ! ( "Database import completed successfully." ) ,
367359 Err ( err) => {
368- eprintln ! ( "Failed to import database dump - {}" , err) ;
360+ error ! ( "Failed to import database dump - {}" , err) ;
369361 process:: exit ( 5 ) ;
370362 }
371363 } ;
372364 }
373365
366+ debug ! ( "Waiting for import to complete" ) ;
367+
374368 let result = match cmd. try_wait ( ) {
375369 Ok ( Some ( status) ) => status. code ( ) ,
376370 Ok ( None ) => cmd. wait ( ) . unwrap ( ) . code ( ) ,
377371 Err ( e) => {
378- eprintln ! ( "error attempting to wait: {}" , e) ;
372+ error ! ( "Error attempting to wait: {}" , e) ;
379373 process:: exit ( 5 ) ;
380374 }
381375 } ;
382376
377+ debug ! ( "Removing temporary file {:?}" , path) ;
383378 fs:: remove_file ( path) ?;
384379
385380 match result {
386381 Some ( 0 ) => ( ) ,
387- n => eprintln ! ( "Import failed with exit code {:?}" , n) ,
382+ n => error ! ( "Import failed with exit code {:?}" , n) ,
388383 } ;
389384
390385 Ok ( ( ) )
0 commit comments