@ -1,19 +1,23 @@
from dataclasses import asdict , dataclass , field
from pathlib import Path
from typing import Any
# from typing import Self
import datetime
import json
from . import version as transpose_version
from .exceptions import TransposeError
from .utils import move , remove , symlink
from .utils import move , symlink
@dataclass
class TransposeEntry :
name : str
path : str
created : str # Should be datetime.datetime but not really necessary here
enabled : bool = True
@dataclass
@ -21,13 +25,14 @@ class TransposeConfig:
entries : dict = field ( default_factory = dict )
version : str = field ( default = transpose_version )
def add ( self , name : str , path : str ) - > None :
def add ( self , name : str , path : str , created : str = None ) - > None :
"""
Add a new entry to the entries
Args :
name : The name of the entry ( must not exist )
path : The path where the entry originally exists
created : The date in datetime . now ( ) . __str__ ( ) format
Returns :
None
@ -35,7 +40,44 @@ class TransposeConfig:
if self . entries . get ( name ) :
raise TransposeError ( f " ' {name} ' already exists " )
self . entries [ name ] = TransposeEntry ( name = name , path = str ( path ) )
if not created :
created = str ( datetime . datetime . now ( ) )
self . entries [ name ] = TransposeEntry (
name = name ,
path = str ( path ) ,
created = created ,
)
def disable ( self , name : str ) - > None :
"""
Disable an entry by name . This ensures actions are not run against this entry , such as apply and restore
Args :
name : The name of the entry ( must exist )
Returns :
None
"""
try :
self . entries [ name ] . enabled = False
except KeyError :
raise TransposeError ( f " ' {name} ' does not exist in Transpose config entries " )
def enable ( self , name : str ) - > None :
"""
Enable an entry by name
Args :
name : The name of the entry ( must exist )
Returns :
None
"""
try :
self . entries [ name ] . enabled = True
except KeyError :
raise TransposeError ( f " ' {name} ' does not exist in Transpose config entries " )
def get ( self , name : str ) - > TransposeEntry :
"""
@ -67,33 +109,46 @@ class TransposeConfig:
except KeyError :
raise TransposeError ( f " ' {name} ' does not exist in Transpose config entries " )
def update ( self , name : str , path : str ) - > None :
def update ( self , name : str , field_key : str , field_value : Any ) - > None :
"""
Update an entry by nam e
Update an entry ' s field (attribute) valu e
Args :
name : The name of the entry ( must exist )
path : The path where the entry originally exists
field_key : The key to update
field_value : The value to update
Returns :
None
"""
try :
self . entries [ name ] . path = path
if not hasattr ( self . entries [ name ] , field_key ) :
raise TransposeError ( f " Unknown TransposeEntry field: {field_key} " )
except KeyError :
raise TransposeError ( f " ' {name} ' does not exist in Transpose config entries " )
setattr ( self . entries [ name ] , field_key , field_value )
@staticmethod
def load ( config_path : str ) : # -> Self:
try :
in_config = json . load ( open ( config_path , " r " ) )
except json . decoder . JSONDecodeError as e :
raise TransposeError ( f " Invalid JSON format for ' {config_path} ' : {e} " )
except FileNotFoundError :
in_config = { " entries " : { } }
config = TransposeConfig ( )
try :
for name in in_config [ " entries " ] :
config . add ( name , in_config [ " entries " ] [ name ] [ " path " ] )
entry = in_config [ " entries " ] [ name ]
config . add (
name ,
entry [ " path " ] ,
created = entry [ " created " ] ,
)
if not entry [ " enabled " ] :
config . disable ( name )
except ( KeyError , TypeError ) as e :
raise TransposeError ( f " Unrecognized Transpose config file format: {e} " )
@ -113,7 +168,7 @@ class TransposeConfig:
config_path . parent . mkdir ( parents = True , exist_ok = True )
with open ( str ( config_path ) , " w " ) as f :
json . dump ( self . to_dict ( ) , f )
json . dump ( self . to_dict ( ) , f , default = str )
def to_dict ( self ) - > dict :
return asdict ( self )
@ -138,7 +193,7 @@ class Transpose:
Args :
name : The name of the entry ( must exist )
force : If enabled and path already exists , move the path to ' {path}-bak '
force : If enabled and path already exists , move the path to ' {path}.backup ' first
Returns :
None
@ -146,11 +201,13 @@ class Transpose:
if not self . config . entries . get ( name ) :
raise TransposeError ( f " Entry does not exist: ' {name} ' " )
entry_path = Path ( self . config . entries [ name ] . path )
entry = self . config . entries [ name ]
if not entry . enabled and not force :
raise TransposeError ( f " Entry ' {name} ' is not enabled in the config " )
entry_path = Path ( entry . path )
if entry_path . exists ( ) :
if entry_path . is_symlink ( ) :
remove ( entry_path )
elif force : # Backup the existing path
if force : # Backup the existing path
move ( entry_path , entry_path . with_suffix ( " .backup " ) )
else :
raise TransposeError (
@ -168,7 +225,7 @@ class Transpose:
Args :
name : The name of the entry ( must exist )
force : If enabled and path already exists , move the path to ' {path}-bak '
force : If enabled and path already exists , move the path to ' {path}.backup ' first
Returns :
None
@ -176,11 +233,13 @@ class Transpose:
if not self . config . entries . get ( name ) :
raise TransposeError ( f " Could not locate entry by name: ' {name} ' " )
entry_path = Path ( self . config . entries [ name ] . path )
entry = self . config . entries [ name ]
if not entry . enabled and not force :
raise TransposeError ( f " Entry ' {name} ' is not enabled in the config " )
entry_path = Path ( entry . path )
if entry_path . exists ( ) :
if entry_path . is_symlink ( ) :
remove ( entry_path )
elif force : # Backup the existing path
if force : # Backup the existing path
move ( entry_path , entry_path . with_suffix ( " .backup " ) )
else :
raise TransposeError (