9
9
import importlib .util
10
10
import logging
11
11
import os
12
- import os .path
13
12
import re
14
13
import shutil
15
14
import subprocess
16
15
import sys
17
16
17
+ from pathlib import Path
18
18
from collections import OrderedDict
19
19
from typing import Dict
20
20
from typing import List
@@ -89,7 +89,7 @@ class Environment:
89
89
90
90
def __init__ (
91
91
self ,
92
- env : Union [str , List [str ], Dict [str , str ], None ],
92
+ env : Union [str , List [Path ], Dict [str , str ], None ],
93
93
preserve : List [str ] = None ,
94
94
source_file : bool = True ,
95
95
):
@@ -121,17 +121,17 @@ def _init_shell_env(self, base: Mapping[str, str]) -> None:
121
121
if regex .match (key ):
122
122
self ._shell_env [key ] = base [key ]
123
123
124
- def init_from_file (self , filepath : str ) -> None :
124
+ def init_from_file (self , filepath : Path ) -> None :
125
125
"""Init variables from a file containing KEY=VALUE pairs."""
126
- with open (filepath ) as file :
126
+ with filepath . open () as file :
127
127
data = file .read ()
128
128
self .init_from_str (data )
129
129
130
130
def init_from_dict (self , env : Dict [str , str ]) -> None :
131
131
"""Init variables from a dictionary."""
132
132
self ._data = env
133
133
134
- def init_from_shell (self , filepath : str , shell : str = None ) -> None :
134
+ def init_from_shell (self , filepath : Path , shell : str = None ) -> None :
135
135
"""Init variables from a shell sourcing a file."""
136
136
if shell is None :
137
137
shell = self ._shell_path
@@ -197,31 +197,31 @@ def __str__(self) -> str:
197
197
buf += "}"
198
198
return buf
199
199
200
- def path_append (self , key : str , value : str ) -> None :
200
+ def path_append (self , key : str , value : Union [ Path , str ] ) -> None :
201
201
"""
202
202
Append the value to the path-like variable key.
203
203
204
204
This uses ":" as the separator between multiple values in the path.
205
205
"""
206
206
if key in self ._data :
207
- self ._data [key ] += self ._sep + value
207
+ self ._data [key ] += self ._sep + str ( value )
208
208
else :
209
- self ._data [key ] = value
209
+ self ._data [key ] = str ( value )
210
210
211
- def path_prepend (self , key : str , value : str ) -> None :
211
+ def path_prepend (self , key : str , value : Union [ Path , str ] ) -> None :
212
212
"""
213
213
Prepend the value to the path-like variable key.
214
214
215
215
This uses ":" as the separator between multiple values in the path.
216
216
"""
217
217
if key in self ._data :
218
- self ._data [key ] = self ._sep + value + self ._data [key ]
218
+ self ._data [key ] = self ._sep + str ( value ) + self ._data [key ]
219
219
else :
220
- self ._data [key ] = value
220
+ self ._data [key ] = str ( value )
221
221
222
- def path_set (self , key : str , values : List [str ]) -> None :
222
+ def path_set (self , key : str , values : List [Union [ Path , str ] ]) -> None :
223
223
"""Set the key to a :-separated list."""
224
- self ._data [key ] = self ._sep .join (values )
224
+ self ._data [key ] = self ._sep .join ([ str ( v ) for v in values ] )
225
225
226
226
def deduplicate_list (self , key : str ) -> None :
227
227
"""Remove duplicates from the specified key."""
@@ -241,9 +241,9 @@ def get_list(self, key: str, default: List[str] = None) -> Optional[List[str]]:
241
241
return self ._data [key ].split (self ._sep )
242
242
return default
243
243
244
- def set (self , key : str , value : str ) -> None :
244
+ def set (self , key : str , value : Union [ Path , str ] ) -> None :
245
245
"""Set the value."""
246
- self ._data [key ] = value
246
+ self ._data [key ] = str ( value )
247
247
248
248
def set_default (self , key : str , value : str ) -> None :
249
249
"""Set the value if it has not already been set."""
@@ -322,7 +322,7 @@ def teardown(self) -> None:
322
322
"""Perform plugin teardown after simulation."""
323
323
324
324
325
- def _find_plugin_setups (file : str ) -> List [Type [PluginSetup ]]:
325
+ def _find_plugin_setups (file : Path ) -> List [Type [PluginSetup ]]:
326
326
"""Open a Python module and find all PluginSetups."""
327
327
name = os .path .splitext (file )[0 ]
328
328
spec = importlib .util .spec_from_file_location (name , file )
@@ -342,14 +342,14 @@ class Engine:
342
342
343
343
def __init__ (self , conf , conanfile = None ):
344
344
# Set options:
345
- self .conan_path = conf ._conf ["conan_path" ]
346
- self .shell_path = conf ._conf ["shell_path" ]
345
+ self .conan_path = Path ( conf ._conf ["conan_path" ])
346
+ self .shell_path = Path ( conf ._conf ["shell_path" ])
347
347
self .relay_anonymous_files = conf ._conf ["relay_anonymous_files" ]
348
348
if conanfile is None :
349
349
self ._read_conf_profile (conf )
350
350
else :
351
351
self ._read_anonymous_profile (conanfile )
352
- self .runtime_dir = conf .profile_runtime (self .profile )
352
+ self .runtime_dir = Path ( conf .profile_runtime (self .profile ) )
353
353
self .engine_pre_args = conf ._conf ["engine" ]["pre_arguments" ]
354
354
self .engine_post_args = conf ._conf ["engine" ]["post_arguments" ]
355
355
self .preserve_env = False
@@ -379,79 +379,80 @@ def _read_anonymous_profile(self, conanfile) -> None:
379
379
hasher .update (self .profile_data .encode ())
380
380
self .profile = hasher .hexdigest ()
381
381
382
- def runtime_env_path (self ) -> str :
383
- return os . path . join ( self .runtime_dir , "launcher_env.sh" )
382
+ def runtime_env_path (self ) -> Path :
383
+ return self .runtime_dir / "launcher_env.sh"
384
384
385
385
def _prepare_runtime_dir (self ) -> None :
386
386
# Clean and create runtime directory
387
387
self .clean ()
388
388
logging .debug (f"Create: { self .runtime_dir } " )
389
- os . makedirs ( self .runtime_dir )
389
+ self .runtime_dir . mkdir ( parents = True )
390
390
391
391
def _prepare_virtualenv (self ) -> None :
392
392
# Get conan to create a virtualenv AND virtualrunenv for us:
393
393
# One gives us the LD_LIBRARY_PATH and the other gives us env_info
394
394
# variables set in packages.
395
- for generator in ["virtualenv" , "virtualrunenv" ]:
396
- conan_cmd = [
397
- self .conan_path ,
398
- "install" ,
399
- "--install-folder" ,
400
- self .runtime_dir ,
401
- "-g" ,
402
- generator ,
403
- ]
404
- for arg in self .conan_args :
405
- conan_cmd .append (arg )
406
- for option in self .conan_options :
407
- conan_cmd .append ("-o" )
408
- conan_cmd .append (option )
409
- for setting in self .conan_settings :
410
- conan_cmd .append ("-s" )
411
- conan_cmd .append (setting )
412
- conan_cmd .append (self .profile_path )
413
- self ._run_cmd (conan_cmd , must_succeed = True )
395
+ conan_cmd = [
396
+ str (self .conan_path ),
397
+ "install" ,
398
+ "--install-folder" ,
399
+ str (self .runtime_dir ),
400
+ "-g" ,
401
+ "virtualenv" ,
402
+ "-g" ,
403
+ "virtualrunenv" ,
404
+ ]
405
+ for arg in self .conan_args :
406
+ conan_cmd .append (arg )
407
+ for option in self .conan_options :
408
+ conan_cmd .append ("-o" )
409
+ conan_cmd .append (option )
410
+ for setting in self .conan_settings :
411
+ conan_cmd .append ("-s" )
412
+ conan_cmd .append (setting )
413
+ conan_cmd .append (self .profile_path )
414
+ self ._run_cmd (conan_cmd , must_succeed = True )
414
415
415
416
def _read_conan_env (self ) -> Environment :
416
417
# The order of the items in env_paths is important because variables
417
418
# will be overwritten.
418
419
# TODO: Should be replaced by merging in the future.
419
420
env_paths = [
420
- os . path . join ( self .runtime_dir , "activate_run.sh" ) ,
421
- os . path . join ( self .runtime_dir , "activate.sh" ) ,
421
+ self .runtime_dir / "activate_run.sh" ,
422
+ self .runtime_dir / "activate.sh" ,
422
423
]
423
424
preserve = None if not self .preserve_env else list (os .environ .keys ())
424
425
return Environment (env_paths , preserve = preserve )
425
426
426
- def _extract_engine_path (self , env ) -> str :
427
+ def _extract_engine_path (self , env ) -> Path :
427
428
"""Return the first cloe-engine we find in the PATH."""
428
429
for bindir in env .get_list ("PATH" , default = []):
429
- pp = os . path . join (bindir , "cloe-engine" )
430
- if os . path . exists (pp ):
430
+ pp = Path (bindir ) / "cloe-engine"
431
+ if pp . exists ():
431
432
return pp
432
433
raise RuntimeError ("cannot locate cloe-engine executable" )
433
434
434
- def _extract_plugin_paths (self , env ) -> List [str ]:
435
+ def _extract_plugin_paths (self , env ) -> List [Path ]:
435
436
"""Return all Cloe plugin paths we find in LD_LIBRARY_PATH."""
436
437
plugin_paths = []
437
438
for libdir in env .get_list ("LD_LIBRARY_PATH" , default = []):
438
- pp = os . path . join (libdir , "cloe" )
439
- if os . path . exists (pp ):
439
+ pp = Path (libdir ) / "cloe"
440
+ if pp . exists ():
440
441
plugin_paths .append (pp )
441
442
return plugin_paths
442
443
443
- def _extract_plugin_setups (self , lib_paths : List [str ]) -> List [Type [PluginSetup ]]:
444
+ def _extract_plugin_setups (self , lib_paths : List [Path ]) -> List [Type [PluginSetup ]]:
444
445
for lib_dir in lib_paths :
445
- for file in os . listdir ( lib_dir ):
446
- if not file .endswith ( ".py" ) :
446
+ for file in lib_dir . iterdir ( ):
447
+ if not file .suffix == ".py" :
447
448
continue
448
- path = os . path . join ( lib_dir , file )
449
+ path = lib_dir / file
449
450
logging .info (f"Loading plugin setup: { path } " )
450
451
_find_plugin_setups (path )
451
452
return PluginSetup .__subclasses__ ()
452
453
453
454
def _prepare_runtime_env (self , use_cache : bool = False ) -> Environment :
454
- if os . path . exists ( self .runtime_env_path ()) and use_cache :
455
+ if self .runtime_env_path (). exists ( ) and use_cache :
455
456
logging .debug ("Re-using existing runtime directory." )
456
457
else :
457
458
logging .debug ("Initializing runtime directory ..." )
@@ -480,7 +481,7 @@ def _process_arg(self, src_path) -> str:
480
481
return src_path
481
482
482
483
dst_file = src_path .replace ("/" , "_" )
483
- dst_path = os . path . join ( self .runtime_dir , dst_file )
484
+ dst_path = self .runtime_dir / dst_file
484
485
logging .info (f"Relay anonymous file { src_path } into { dst_path } " )
485
486
with open (src_path ) as src :
486
487
with open (dst_path , "w" ) as dst :
@@ -519,7 +520,7 @@ def _prepare_plugin_setups(self, env: Environment) -> List[PluginSetup]:
519
520
520
521
def clean (self ) -> None :
521
522
"""Clean the runtime directory."""
522
- if os . path .exists (self . runtime_dir ):
523
+ if self . runtime_dir .exists ():
523
524
logging .debug (f"Remove: { self .runtime_dir } " )
524
525
shutil .rmtree (self .runtime_dir , ignore_errors = True )
525
526
@@ -586,8 +587,8 @@ def activate(
586
587
587
588
print ("# Please see `cloe-launch activate --help` before activating this." )
588
589
print ()
589
- print (f"source { os . path . join ( self .runtime_dir , 'activate.sh' ) } " )
590
- print (f"source { os . path . join ( self .runtime_dir , 'activate_run.sh' ) } " )
590
+ print (f"source { self .runtime_dir / 'activate.sh' } " )
591
+ print (f"source { self .runtime_dir / 'activate_run.sh' } " )
591
592
for var in ["CLOE_PROFILE_HASH" , "CLOE_ENGINE" , "CLOE_PLUGIN_PATH" ]:
592
593
print (f'export { var } ="{ env [var ]} "' )
593
594
print (f'export CLOE_SHELL="{ self .runtime_env_path ()} "' )
0 commit comments