Skip to content

Commit b75e56b

Browse files
author
Robert Roos
committed
Prevents adding duplicate filenames
1 parent 2e42810 commit b75e56b

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

src/tctools/patch_plc/patch_plc_class.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ class FileItems:
1818
files: set[Path] = field(default_factory=set)
1919

2020
def add(self, other: "FileItems"):
21+
"""Merge in another set of files/folders."""
2122
self.folders |= other.folders
2223
self.files |= other.files
2324

2425
def subtract(self, other: "FileItems"):
26+
"""Remove files/folders that occur in another set."""
2527
self.folders = self.folders.difference(other.folders)
2628
self.files = self.files.difference(other.files)
2729

@@ -178,6 +180,8 @@ def operation_merge(
178180
"""See help info for `merge`."""
179181
new_sources = FileItems.merge(new_sources.values())
180182

183+
self.skip_file_duplicates(new_sources, current_sources)
184+
181185
sizes_all = (len(new_sources.folders), len(new_sources.files))
182186

183187
new_sources.subtract(current_sources)
@@ -251,6 +255,8 @@ def operation_reset(self, current_sources: FileItems, new_sources: FileItemsGrou
251255
to_remove.subtract(to_add) # Don't remove sources that are real
252256
to_add.subtract(current_sources) # Don't add sources that are already known
253257

258+
self.skip_file_duplicates(to_add, current_sources)
259+
254260
# Empty folders will also be removed, make sure to keep them:
255261
to_remove.folders = set(
256262
f for f in to_remove.folders if not (self._project_file.parent / f).exists()
@@ -268,7 +274,7 @@ def operation_reset(self, current_sources: FileItems, new_sources: FileItemsGrou
268274
)
269275

270276
# Decide what to do next:
271-
if not to_remove.is_empty() and to_add.is_empty():
277+
if to_remove.is_empty() and to_add.is_empty():
272278
self.logger.info("No files or folders to change, stopping")
273279
return 0
274280

@@ -312,6 +318,25 @@ def determine_source_folders(self, source_files: Iterable[Path]) -> FileItems:
312318

313319
return sources
314320

321+
def skip_file_duplicates(
322+
self,
323+
new_sources: FileItems,
324+
current_sources: FileItems,
325+
):
326+
"""Avoid duplicate file names (regardless of full path).
327+
328+
``current_sources`` is modified in-place.
329+
"""
330+
filenames = set(f.name for f in current_sources.files) # Reduce to just names
331+
to_pop = set()
332+
for file in new_sources.files:
333+
if file.name in filenames:
334+
to_pop.add(file)
335+
self.logger.warning(f"Refusing to add existing file name: {file}")
336+
337+
if to_pop:
338+
new_sources.files -= to_pop
339+
315340
def get_project_sources(self, tree) -> FileItems:
316341
"""Get all files and folders currently in a PLC project."""
317342

tests/test_patch_plc.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import shutil
23
import subprocess
34
import sys
@@ -214,7 +215,7 @@ def test_reset(plc_code):
214215
assert item not in content_before
215216

216217
# Reset to the entire local directory:
217-
code = PatchPlc(str(project), "reset", "-r", str(project.parent)).run()
218+
code = PatchPlc(str(project), "reset", "-r", str(plc_dir)).run()
218219
assert code == 0
219220

220221
content_after = project.read_text()
@@ -226,3 +227,28 @@ def test_reset(plc_code):
226227
lines_after = content_after.count("\n")
227228
assert lines_before - (2 * 1) - (3 * 3) + (2 * 1) + (4 * 3) == lines_after
228229
# Remove 2 folders and 3 files, add 2 folders and 4 files
230+
231+
232+
def test_reset_duplicate(plc_code, caplog):
233+
plc_dir = plc_code / "TwinCAT Project1" / "MyPlc"
234+
project = plc_dir / "MyPlc.plcproj"
235+
236+
# Create a new file, with a name that's already known:
237+
module_folder = plc_dir / "POUs" / "Module"
238+
new_file = module_folder / "DUTs" / "MAIN.TcPOU"
239+
new_file.write_text("\n") # Create the file
240+
241+
content_before = project.read_text()
242+
243+
with caplog.at_level(logging.WARNING):
244+
code = PatchPlc(str(project), "reset", str(module_folder), "-r").run()
245+
246+
assert code == 0
247+
248+
assert len(caplog.records) == 1
249+
assert (
250+
caplog.records[0].message
251+
== "Refusing to add existing file name: POUs\Module\DUTs\MAIN.TcPOU"
252+
)
253+
254+
assert content_before == project.read_text() # The project should not be changed

0 commit comments

Comments
 (0)