@@ -1149,6 +1149,47 @@ def flat_deps(services, with_extends=False):
1149
1149
for name , srv in services .items ():
1150
1150
rec_deps (services , name )
1151
1151
1152
+ ###################
1153
+ # Override and reset tags
1154
+ ###################
1155
+
1156
+ class OverrideTag (yaml .YAMLObject ):
1157
+ yaml_dumper = yaml .Dumper
1158
+ yaml_loader = yaml .SafeLoader
1159
+ yaml_tag = u'!override'
1160
+
1161
+ def __init__ (self , value ):
1162
+ values = list ()
1163
+
1164
+ for item in value :
1165
+ values .append (item .value )
1166
+
1167
+ self .value = values
1168
+
1169
+ @classmethod
1170
+ def from_yaml (cls , loader , node ):
1171
+ return OverrideTag (node .value )
1172
+
1173
+ @classmethod
1174
+ def to_yaml (cls , dumper , data ):
1175
+ return dumper .represent_scalar (cls .yaml_tag , data .value )
1176
+
1177
+ class ResetTag (yaml .YAMLObject ):
1178
+ yaml_dumper = yaml .Dumper
1179
+ yaml_loader = yaml .SafeLoader
1180
+ yaml_tag = u'!reset'
1181
+
1182
+ @classmethod
1183
+ def toJSON (self ):
1184
+ return self .yaml_tag
1185
+
1186
+ @classmethod
1187
+ def from_yaml (cls , loader , node ):
1188
+ return ResetTag ()
1189
+
1190
+ @classmethod
1191
+ def to_yaml (cls , dumper , data ):
1192
+ return dumper .represent_scalar (cls .yaml_tag , '' )
1152
1193
1153
1194
###################
1154
1195
# podman and compose classes
@@ -1245,6 +1286,14 @@ def volume_ls(self, proj=None):
1245
1286
1246
1287
1247
1288
def normalize_service (service , sub_dir = "" ):
1289
+ if isinstance (service , ResetTag ):
1290
+ return service
1291
+
1292
+ if isinstance (service , OverrideTag ):
1293
+ tagObj = service
1294
+ service = tagObj .value
1295
+ print (subdir )
1296
+
1248
1297
if "build" in service :
1249
1298
build = service ["build" ]
1250
1299
if is_str (build ):
@@ -1284,7 +1333,12 @@ def normalize_service(service, sub_dir=""):
1284
1333
if is_str (extends ):
1285
1334
extends = {"service" : extends }
1286
1335
service ["extends" ] = extends
1287
- return service
1336
+
1337
+ try :
1338
+ tagObj .value = serivce
1339
+ return tagObj
1340
+ except NameError :
1341
+ return service
1288
1342
1289
1343
1290
1344
def normalize (compose ):
@@ -1330,6 +1384,8 @@ def rec_merge_one(target, source):
1330
1384
update target from source recursively
1331
1385
"""
1332
1386
done = set ()
1387
+ remove = set ()
1388
+
1333
1389
for key , value in source .items ():
1334
1390
if key in target :
1335
1391
continue
@@ -1339,17 +1395,37 @@ def rec_merge_one(target, source):
1339
1395
if key in done :
1340
1396
continue
1341
1397
if key not in source :
1398
+ if isinstance (value , ResetTag ):
1399
+ log ("INFO: Unneeded !reset found for [{key}]" )
1400
+ remove .add (key )
1401
+
1402
+ if isinstance (value , OverrideTag ):
1403
+ log ("INFO: Unneeded !override found for [{key}] with value '{value}'" )
1404
+ target [key ] = clone (value .value )
1405
+
1342
1406
continue
1407
+
1343
1408
value2 = source [key ]
1409
+
1410
+ if isinstance (value , ResetTag ) or isinstance (value2 , ResetTag ):
1411
+ remove .add (key )
1412
+ continue
1413
+
1414
+ if isinstance (value , OverrideTag ) or isinstance (value2 , OverrideTag ):
1415
+ target [key ] = clone (value .value ) if isinstance (value , OverrideTag ) else clone (value2 .value )
1416
+ continue
1417
+
1344
1418
if key in ("command" , "entrypoint" ):
1345
1419
target [key ] = clone (value2 )
1346
1420
continue
1421
+
1347
1422
if not isinstance (value2 , type (value )):
1348
1423
value_type = type (value )
1349
1424
value2_type = type (value2 )
1350
1425
raise ValueError (
1351
1426
f"can't merge value of [{ key } ] of type { value_type } and { value2_type } "
1352
1427
)
1428
+
1353
1429
if is_list (value2 ):
1354
1430
if key == "volumes" :
1355
1431
# clean duplicate mount targets
@@ -1368,6 +1444,10 @@ def rec_merge_one(target, source):
1368
1444
rec_merge_one (value , value2 )
1369
1445
else :
1370
1446
target [key ] = value2
1447
+
1448
+ for key in remove :
1449
+ del target [key ]
1450
+
1371
1451
return target
1372
1452
1373
1453
@@ -1629,7 +1709,7 @@ def _parse_compose_file(self):
1629
1709
compose ["services" ] = resolved_services
1630
1710
if not getattr (args , "no_normalize" , None ):
1631
1711
compose = normalize_final (compose , self .dirname )
1632
- self .merged_yaml = yaml .safe_dump (compose )
1712
+ self .merged_yaml = yaml .dump (compose )
1633
1713
merged_json_b = json .dumps (compose , separators = ("," , ":" )).encode ("utf-8" )
1634
1714
self .yaml_hash = hashlib .sha256 (merged_json_b ).hexdigest ()
1635
1715
compose ["_dirname" ] = dirname
0 commit comments