55"""
66
77import os
8+ import sys
89import pwd
910import argparse
11+ import logging
1012
1113DEFAULT_SOURCE_ROOT = '/glade/campaign/cesm/cesmdata/cseg/inputdata/'
1214DEFAULT_TARGET_ROOT = '/glade/campaign/collections/gdex/data/d651077/cesmdata/inputdata/'
1315
16+ # Set up logger
17+ logger = logging .getLogger (__name__ )
18+
1419def find_and_replace_owned_files (source_dir , target_dir , username ):
1520 """
1621 Finds files owned by a specific user in a source directory tree,
@@ -29,10 +34,15 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
2934 try :
3035 user_uid = pwd .getpwnam (username ).pw_uid
3136 except KeyError :
32- print ( f "Error: User '{ username } ' not found. Exiting." )
37+ logger . error ( "Error: User '%s ' not found. Exiting." , username )
3338 return
3439
35- print (f"Searching for files owned by '{ username } ' (UID: { user_uid } ) in '{ source_dir } '..." )
40+ logger .info (
41+ "Searching for files owned by '%s' (UID: %s) in '%s'..." ,
42+ username ,
43+ user_uid ,
44+ source_dir
45+ )
3646
3747 for dirpath , _ , filenames in os .walk (source_dir ):
3848 for filename in filenames :
@@ -41,23 +51,28 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
4151 # Use os.stat().st_uid to get the file's owner UID
4252 try :
4353 if os .path .islink (file_path ):
44- print ( f "Skipping symlink: { file_path } " )
54+ logger . info ( "Skipping symlink: %s" , file_path )
4555 continue
4656
4757 file_uid = os .stat (file_path ).st_uid
4858 except FileNotFoundError :
4959 continue # Skip if file was deleted during traversal
5060
5161 if file_uid == user_uid :
52- print ( f "Found owned file: { file_path } " )
62+ logger . info ( "Found owned file: %s" , file_path )
5363
5464 # Determine the relative path and the new link's destination
5565 relative_path = os .path .relpath (file_path , source_dir )
5666 link_target = os .path .join (target_dir , relative_path )
5767
5868 # Check if the target file actually exists
5969 if not os .path .exists (link_target ):
60- print (f"Warning: Corresponding file not found in '{ target_dir } ' for '{ file_path } '. Skipping." )
70+ logger .warning (
71+ "Warning: Corresponding file not found in '%s' "
72+ "for '%s'. Skipping." ,
73+ target_dir ,
74+ file_path
75+ )
6176 continue
6277
6378 # Get the link name
@@ -66,9 +81,9 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
6681 # Remove the original file
6782 try :
6883 os .rename (link_name , link_name + ".tmp" )
69- print ( f "Deleted original file: { link_name } " )
84+ logger . info ( "Deleted original file: %s" , link_name )
7085 except OSError as e :
71- print ( f "Error deleting file { link_name } : { e } . Skipping." )
86+ logger . error ( "Error deleting file %s: %s . Skipping." , link_name , e )
7287 continue
7388
7489 # Create the symbolic link, handling necessary parent directories
@@ -77,18 +92,18 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
7792 os .makedirs (os .path .dirname (link_name ), exist_ok = True )
7893 os .symlink (link_target , link_name )
7994 os .remove (link_name + ".tmp" )
80- print ( f "Created symbolic link: { link_name } -> { link_target } " )
95+ logger . info ( "Created symbolic link: %s -> %s" , link_name , link_target )
8196 except OSError as e :
8297 os .rename (link_name + ".tmp" , link_name )
83- print ( f "Error creating symlink for { link_name } : { e } . Skipping." )
98+ logger . error ( "Error creating symlink for %s: %s . Skipping." , link_name , e )
8499
85100def parse_arguments ():
86101 """
87102 Parse command-line arguments.
88103
89104 Returns:
90- argparse.Namespace: Parsed arguments containing source_root
91- and target_root .
105+ argparse.Namespace: Parsed arguments containing source_root,
106+ target_root, and verbosity settings .
92107 """
93108 parser = argparse .ArgumentParser (
94109 description = (
@@ -111,11 +126,39 @@ def parse_arguments():
111126 )
112127 )
113128
129+ # Verbosity options (mutually exclusive)
130+ verbosity_group = parser .add_mutually_exclusive_group ()
131+ verbosity_group .add_argument (
132+ '-v' , '--verbose' ,
133+ action = 'store_true' ,
134+ help = 'Enable verbose output'
135+ )
136+ verbosity_group .add_argument (
137+ '-q' , '--quiet' ,
138+ action = 'store_true' ,
139+ help = 'Quiet mode (show only warnings and errors)'
140+ )
141+
114142 return parser .parse_args ()
115143
116144if __name__ == '__main__' :
117- # --- Configuration ---
145+
118146 args = parse_arguments ()
147+
148+ # Configure logging based on verbosity flags
149+ if args .quiet :
150+ LOG_LEVEL = logging .WARNING
151+ elif args .verbose :
152+ LOG_LEVEL = logging .DEBUG
153+ else :
154+ LOG_LEVEL = logging .INFO
155+
156+ logging .basicConfig (
157+ level = LOG_LEVEL ,
158+ format = '%(message)s' ,
159+ stream = sys .stdout
160+ )
161+
119162 my_username = os .environ ['USER' ]
120163
121164 # --- Execution ---
0 commit comments