1+ """
2+ Finds files owned by a specific user in a source directory tree,
3+ deletes them, and replaces them with symbolic links to the same
4+ relative path in a target directory tree.
5+ """
6+
17import os
2- import shutil
38import pwd
9+ import argparse
10+
11+ DEFAULT_SOURCE_ROOT = '/glade/campaign/cesm/cesmdata/cseg/inputdata/'
12+ DEFAULT_TARGET_ROOT = '/glade/campaign/collections/gdex/data/d651077/cesmdata/inputdata/'
413
514def find_and_replace_owned_files (source_dir , target_dir , username ):
615 """
@@ -25,10 +34,10 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
2534
2635 print (f"Searching for files owned by '{ username } ' (UID: { user_uid } ) in '{ source_dir } '..." )
2736
28- for dirpath , dirnames , filenames in os .walk (source_dir ):
37+ for dirpath , _ , filenames in os .walk (source_dir ):
2938 for filename in filenames :
3039 file_path = os .path .join (dirpath , filename )
31-
40+
3241 # Use os.stat().st_uid to get the file's owner UID
3342 try :
3443 if os .path .islink (file_path ):
@@ -38,14 +47,14 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
3847 file_uid = os .stat (file_path ).st_uid
3948 except FileNotFoundError :
4049 continue # Skip if file was deleted during traversal
41-
50+
4251 if file_uid == user_uid :
4352 print (f"Found owned file: { file_path } " )
4453
4554 # Determine the relative path and the new link's destination
4655 relative_path = os .path .relpath (file_path , source_dir )
4756 link_target = os .path .join (target_dir , relative_path )
48-
57+
4958 # Check if the target file actually exists
5059 if not os .path .exists (link_target ):
5160 print (f"Warning: Corresponding file not found in '{ target_dir } ' for '{ file_path } '. Skipping." )
@@ -73,14 +82,41 @@ def find_and_replace_owned_files(source_dir, target_dir, username):
7382 os .rename (link_name + ".tmp" , link_name )
7483 print (f"Error creating symlink for { link_name } : { e } . Skipping." )
7584
85+ def parse_arguments ():
86+ """
87+ Parse command-line arguments.
88+
89+ Returns:
90+ argparse.Namespace: Parsed arguments containing source_root
91+ and target_root.
92+ """
93+ parser = argparse .ArgumentParser (
94+ description = (
95+ 'Find files owned by a user and replace them with symbolic links to a target directory.'
96+ )
97+ )
98+ parser .add_argument (
99+ '--source-root' ,
100+ default = DEFAULT_SOURCE_ROOT ,
101+ help = (
102+ f'The root of the directory tree to search for files (default: { DEFAULT_SOURCE_ROOT } )'
103+ )
104+ )
105+ parser .add_argument (
106+ '--target-root' ,
107+ default = DEFAULT_TARGET_ROOT ,
108+ help = (
109+ f'The root of the directory tree where files should be moved to '
110+ f'(default: { DEFAULT_TARGET_ROOT } )'
111+ )
112+ )
113+
114+ return parser .parse_args ()
115+
76116if __name__ == '__main__' :
77117 # --- Configuration ---
78- # Replace these with your actual directories and username
79- source_root = '/glade/campaign/cesm/cesmdata/cseg/inputdata/'
80- target_root = '/glade/campaign/collections/gdex/data/d651077/cesmdata/inputdata/'
118+ args = parse_arguments ()
81119 my_username = os .environ ['USER' ]
82120
83121 # --- Execution ---
84- find_and_replace_owned_files (source_root , target_root , my_username )
85-
86-
122+ find_and_replace_owned_files (args .source_root , args .target_root , my_username )
0 commit comments