@@ -69,13 +69,17 @@ def build_parser() -> argparse.ArgumentParser:
6969 # Mutually exclusive: -file or -list (one required)
7070 group = parser .add_mutually_exclusive_group (required = True )
7171 group .add_argument ("-file" , dest = "file" , metavar = "filename" , help = argparse .SUPPRESS )
72- group .add_argument ("-list" , dest = "filelist" , metavar = "filelist" , help = argparse .SUPPRESS )
72+ group .add_argument (
73+ "-list" , dest = "filelist" , metavar = "filelist" , help = argparse .SUPPRESS
74+ )
7375
7476 parser .add_argument (
7577 "-inputdata" ,
7678 dest = "inputdata" ,
7779 metavar = "inputdata_dir" ,
78- default = os .path .join ("/glade" ,"campaign" ,"cesm" ,"cesmdata" ,"cseg" ,"inputdata" ),
80+ default = os .path .join (
81+ "/glade" , "campaign" , "cesm" , "cesmdata" , "cseg" , "inputdata"
82+ ),
7983 help = argparse .SUPPRESS ,
8084 )
8185
@@ -100,10 +104,15 @@ def read_filelist(list_path: Path) -> List[str]:
100104def resolve_paths (root : Path , relnames : Iterable [str ]) -> List [Path ]:
101105 paths : List [Path ] = []
102106 for name in relnames :
103- p = (root / name ).resolve () if not Path (name ).is_absolute () else Path (name ).resolve ()
107+ p = (
108+ (root / name ).resolve ()
109+ if not Path (name ).is_absolute ()
110+ else Path (name ).resolve ()
111+ )
104112 paths .append (p )
105113 return paths
106114
115+
107116def stage_data (src : Path , inputdata_root : Path , staging_root : Path ) -> None :
108117 """Stage a file by mirroring its path under `staging_root`.
109118 Destination path is computed by replacing the `args.inputdata` prefix of `src`
@@ -129,32 +138,42 @@ def stage_data(src: Path, inputdata_root: Path, staging_root: Path) -> None:
129138 if "d651077" in str (src ):
130139 raise RuntimeError (f"Source file { src .name } is already published." )
131140 else :
132- raise RuntimeError (f"source not under inputdata root: { src } not in { inputdata_root } " )
141+ raise RuntimeError (
142+ f"source not under inputdata root: { src } not in { inputdata_root } "
143+ )
133144
134145 dst = staging_root / rel
135146 dst .parent .mkdir (parents = True , exist_ok = True )
136147 shutil .copy2 (src , dst )
137148 print (f"[rimport] staged { src } -> { dst } " )
138149
150+
139151def ensure_running_as (target_user : str , argv : list [str ]) -> None :
140152 """If not running as `target_user`, re-exec via sudo -u target_user (handles 2FA via PAM)."""
141153 try :
142154 target_uid = pwd .getpwnam (target_user ).pw_uid
143155 except KeyError :
144156 # TODO: Raise Python error instead of SystemExit
145- print (f"rimport: target user '{ target_user } ' not found on this system" , file = sys .stderr )
157+ print (
158+ f"rimport: target user '{ target_user } ' not found on this system" ,
159+ file = sys .stderr ,
160+ )
146161 raise SystemExit (2 )
147162
148163 if os .geteuid () != target_uid :
149164 if not sys .stdin .isatty ():
150165 # TODO: Do not hard-code "cesmdata" here
151- print ("rimport: need interactive TTY to authenticate as 'cesmdata' (2FA).\n "
152- " Try: sudo -u cesmdata rimport …" , file = sys .stderr )
166+ print (
167+ "rimport: need interactive TTY to authenticate as 'cesmdata' (2FA).\n "
168+ " Try: sudo -u cesmdata rimport …" ,
169+ file = sys .stderr ,
170+ )
153171 # TODO: Raise Python error instead of SystemExit
154172 raise SystemExit (2 )
155173 # Re-exec under target user; this invokes sudo’s normal password/2FA flow.
156174 os .execvp ("sudo" , ["sudo" , "-u" , target_user , "--" ] + argv )
157175
176+
158177# TODO: Unused; delete.
159178def safe_mvandlink (src : Path , dst : Path ) -> None :
160179 dst .parent .mkdir (parents = True , exist_ok = True )
@@ -165,6 +184,7 @@ def safe_mvandlink(src: Path, dst: Path) -> None:
165184 link_target = str (moved_to )
166185 os .symlink (link_target , src )
167186
187+
168188def get_staging_root () -> Path :
169189 """Return the staging root. Uses $RIMPORT_STAGING if set, otherwise
170190 creates a sibling directory named '<inputdata_root>.staging'."""
@@ -174,7 +194,7 @@ def get_staging_root() -> Path:
174194 # TODO: This should be a module-level variable.
175195 return Path ("/glade/campaign/collections/gdex/data/d651077/cesmdata/inputdata" )
176196
177-
197+
178198def main (argv : List [str ] | None = None ) -> int :
179199 parser = build_parser ()
180200 args = parser .parse_args (argv )
0 commit comments