@@ -935,6 +935,19 @@ def _validate_path(path):
935935 raise OperationTypeError ('`path` must be a string or `os.PathLike` object' )
936936
937937
938+ def _raise_or_remove_invalid_path (fs_type , path , force , force_backup , force_backup_dir ):
939+ if force :
940+ if force_backup :
941+ backup_path = '{0}.{1}' .format (path , get_timestamp ())
942+ if force_backup_dir :
943+ backup_path = '{0}/{1}' .format (force_backup_dir , backup_path )
944+ yield 'mv {0} {1}' .format (path , backup_path )
945+ else :
946+ yield 'rm -rf {0}' .format (path )
947+ else :
948+ raise OperationError ('{0} exists and is not a {1}' .format (path , fs_type ))
949+
950+
938951@operation (pipeline_facts = {
939952 'link' : 'path' ,
940953})
@@ -943,6 +956,7 @@ def link(
943956 target = None , present = True , assume_present = False ,
944957 user = None , group = None , symbolic = True ,
945958 create_remote_dir = True ,
959+ force = False , force_backup = True , force_backup_dir = None ,
946960 state = None , host = None ,
947961):
948962 '''
@@ -956,6 +970,9 @@ def link(
956970 + group: group to own the link
957971 + symbolic: whether to make a symbolic link (vs hard link)
958972 + create_remote_dir: create the remote directory if it doesn't exist
973+ + force: if the target exists and is not a file, move or remove it and continue
974+ + force_backup: set to ``False`` to remove any existing non-file when ``force=True``
975+ + force_backup_dir: directory to move any backup to when ``force=True``
959976
960977 ``create_remote_dir``:
961978 If the remote directory does not exist it will be created using the same
@@ -1003,7 +1020,10 @@ def link(
10031020
10041021 # Not a link?
10051022 if info is False :
1006- raise OperationError ('{0} exists and is not a link' .format (path ))
1023+ yield _raise_or_remove_invalid_path (
1024+ 'link' , path , force , force_backup , force_backup_dir ,
1025+ )
1026+ info = None
10071027
10081028 add_args = ['ln' ]
10091029 if symbolic :
@@ -1086,6 +1106,7 @@ def file(
10861106 present = True , assume_present = False ,
10871107 user = None , group = None , mode = None , touch = False ,
10881108 create_remote_dir = True ,
1109+ force = False , force_backup = True , force_backup_dir = None ,
10891110 state = None , host = None ,
10901111):
10911112 '''
@@ -1099,6 +1120,9 @@ def file(
10991120 + mode: permissions of the files as an integer, eg: 755
11001121 + touch: whether to touch the file
11011122 + create_remote_dir: create the remote directory if it doesn't exist
1123+ + force: if the target exists and is not a file, move or remove it and continue
1124+ + force_backup: set to ``False`` to remove any existing non-file when ``force=True``
1125+ + force_backup_dir: directory to move any backup to when ``force=True``
11021126
11031127 ``create_remote_dir``:
11041128 If the remote directory does not exist it will be created using the same
@@ -1128,7 +1152,10 @@ def file(
11281152
11291153 # Not a file?!
11301154 if info is False :
1131- raise OperationError ('{0} exists and is not a file' .format (path ))
1155+ yield _raise_or_remove_invalid_path (
1156+ 'file' , path , force , force_backup , force_backup_dir ,
1157+ )
1158+ info = None
11321159
11331160 # Doesn't exist & we want it
11341161 if not assume_present and info is None and present :
@@ -1195,6 +1222,7 @@ def directory(
11951222 path ,
11961223 present = True , assume_present = False ,
11971224 user = None , group = None , mode = None , recursive = False ,
1225+ force = False , force_backup = True , force_backup_dir = None ,
11981226 _no_check_owner_mode = False ,
11991227 _no_fail_on_link = False ,
12001228 state = None , host = None ,
@@ -1209,6 +1237,9 @@ def directory(
12091237 + group: group to own the folder
12101238 + mode: permissions of the folder
12111239 + recursive: recursively apply user/group/mode
1240+ + force: if the target exists and is not a file, move or remove it and continue
1241+ + force_backup: set to ``False`` to remove any existing non-file when ``force=True``
1242+ + force_backup_dir: directory to move any backup to when ``force=True``
12121243
12131244 Examples:
12141245
@@ -1246,7 +1277,10 @@ def directory(
12461277 if _no_fail_on_link and host .get_fact (Link , path = path ):
12471278 host .noop ('directory {0} already exists (as a link)' .format (path ))
12481279 return
1249- raise OperationError ('{0} exists and is not a directory' .format (path ))
1280+ yield _raise_or_remove_invalid_path (
1281+ 'directory' , path , force , force_backup , force_backup_dir ,
1282+ )
1283+ info = None
12501284
12511285 # Doesn't exist & we want it
12521286 if not assume_present and info is None and present :
0 commit comments