Skip to content

Commit eecdf9a

Browse files
authored
Merge pull request #29 from rruiter87/tc-version-check
Tc version check
2 parents 57ebc7e + 8375035 commit eecdf9a

14 files changed

Lines changed: 17116 additions & 11 deletions

.pre-commit-hooks.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,11 @@
5858
entry: minimize-id-changes
5959
language: python
6060
files: .*\.plcproj$
61+
- id: check-twincat-versions
62+
name: Check if all TwinCAT versions match
63+
description: Checks if TwinCAT versions match in different tsproj files, or if it matches the targeted one.
64+
entry: check-twincat-versions
65+
# All files need to be passed at once, else not all files are compared to eachother
66+
require_serial: true
67+
language: python
68+
files: .*\.tsproj$

README.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ repos:
2525
files: \.(TcPOU|TcDUT|TcGVL)$
2626

2727
- repo: https://github.com/pcdshub/pre-commit-hooks.git
28-
rev: v1.6.0
28+
rev: v1.7.0
2929
hooks:
3030
- id: twincat-leading-tabs-remover
3131
- id: twincat-lineids-remover
@@ -36,6 +36,15 @@ repos:
3636
# Check if minimize id changes is selected in the plc project file.
3737
# See https://www.youtube.com/watch?v=KKpBtaYjfWo&t=935s why to do this.
3838
- id: minimize-id-changes
39+
# Checks if TwinCAT versions match in different tsproj files, or if it matches the targeted one.
40+
- id: check-twincat-versions
41+
# Possible optional arguments
42+
# --target-version: Set a version that you want the tsproj file to have
43+
# --fix: Fix the version numbers if a target version is set
44+
# --reason: Add a reason to the error message in case of a non-matching version.
45+
# --pinned: Require the TwinCAT version to be pinned. Apply pinning if combined with --fix.
46+
# --no-pinned: Require the TwinCAT version to not be pinned. Remove pinning if combined with --fix.
47+
args: [--target-version=3.1.4024.20, --pinned, --fix, --reason="This version has a crucial new feature"]
3948
# Optional, if you use pytmc to generate EPICS IOCs:
4049
# - id: pytmc-pragma-linter
4150
```

forTwinCatRepos/.pre-commit-config.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repos:
99
files: \.(TcPOU|TcDUT|TcGVL)$
1010

1111
- repo: https://github.com/pcdshub/pre-commit-hooks.git
12-
rev: v1.5.0
12+
rev: v1.7.0
1313
hooks:
1414
- id: twincat-leading-tabs-remover
1515
- id: twincat-lineids-remover
@@ -20,5 +20,14 @@ repos:
2020
# Check if minimize id changes is selected in the plc project file.
2121
# See https://www.youtube.com/watch?v=KKpBtaYjfWo&t=935s why to do this.
2222
- id: minimize-id-changes
23+
# Checks if TwinCAT versions match in different tsproj files, or if it matches the targeted one.
24+
- id: check-twincat-versions
25+
# Possible optional arguments
26+
# --target-version: Set a version that you want the tsproj file to have
27+
# --fix: Fix the version numbers if a target version is set
28+
# --reason: Add a reason to the error message in case of a non-matching version.
29+
# --pinned: Require the TwinCAT version to be pinned. Apply pinning if combined with --fix.
30+
# --no-pinned: Require the TwinCAT version to not be pinned. Remove pinning if combined with --fix.
31+
args: [--target-version=3.1.4024.20, --pinned, --fix, --reason="This version has a crucial new feature"]
2332
# Optional, if you use pytmc to generate EPICS IOCs:
2433
# - id: pytmc-pragma-linter

pre_commit_hooks/check_fixed_library_versions.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
from lxml import etree
66

7-
8-
class PreCommitException(Exception):
9-
pass
7+
from pre_commit_hooks.exceptions import PreCommitException
108

119

1210
def check_file(filename):
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import argparse
2+
import re
3+
import xml.etree.ElementTree as ET
4+
5+
from pre_commit_hooks.exceptions import PreCommitException
6+
7+
8+
def tc_version_pinned(xml_content: str) -> bool:
9+
root = ET.fromstring(xml_content)
10+
11+
return (
12+
"TcVersionFixed" in root.attrib and root.attrib.get("TcVersionFixed") == "true"
13+
)
14+
15+
16+
def get_tc_version(xml_content: str) -> str:
17+
root = ET.fromstring(xml_content)
18+
19+
return root.attrib.get("TcVersion")
20+
21+
22+
def fix_tc_version(xml_content: str, new_version: str) -> str:
23+
pattern = r'(TcVersion=")([^"]*)(")'
24+
new_xml_content = re.sub(pattern, r"\g<1>" + new_version + r"\g<3>", xml_content)
25+
26+
return new_xml_content
27+
28+
29+
def fix_pinned_version(xml_content: str, pin_version: bool) -> str:
30+
new_value = "true" if pin_version else "false"
31+
32+
pattern = r'(TcVersionFixed=")([^"]*)(")'
33+
34+
if re.search(pattern, xml_content):
35+
new_xml_content = re.sub(pattern, r"\g<1>" + new_value + r"\g<3>", xml_content)
36+
else:
37+
version_pattern = r'(TcVersion="[^"]*")'
38+
new_xml_content = re.sub(
39+
version_pattern, r'\g<1> TcVersionFixed="' + new_value + r'"', xml_content
40+
)
41+
42+
return new_xml_content
43+
44+
45+
def main(args=None):
46+
if args is None:
47+
parser = argparse.ArgumentParser()
48+
parser.add_argument(
49+
"filenames", nargs="+", help="List of tsproj filenames to process."
50+
)
51+
parser.add_argument(
52+
"--target-version", type=str, help="Target TwinCAT version to enforce."
53+
)
54+
parser.add_argument(
55+
"--fix",
56+
action="store_true",
57+
help="Fix the versions if they do not match the target version and fix the pinned state if combined with --pinned/no-pinned.",
58+
)
59+
parser.add_argument(
60+
"--reason", type=str, help="Reason for targeting a specific version."
61+
)
62+
parser.add_argument(
63+
"--pinned",
64+
action=argparse.BooleanOptionalAction,
65+
help="Check if the TwinCAT version should be pinned. Applies or removes pinning if combined with --fix.",
66+
)
67+
68+
args = parser.parse_args()
69+
70+
try:
71+
versions = {}
72+
pinned = {}
73+
for filename in args.filenames:
74+
with open(filename, "r") as file:
75+
xml_content = file.read()
76+
versions[filename] = get_tc_version(xml_content)
77+
pinned[filename] = tc_version_pinned(xml_content)
78+
79+
itemize = "\n -"
80+
exception_message = ""
81+
if args.target_version:
82+
mismatched_files = [
83+
fname for fname, ver in versions.items() if ver != args.target_version
84+
]
85+
if mismatched_files:
86+
reason_msg = f"\nReason: {args.reason}" if args.reason else ""
87+
if args.fix:
88+
for filename in mismatched_files:
89+
with open(filename, "r") as file:
90+
xml_content = file.read()
91+
fixed_content = fix_tc_version(xml_content, args.target_version)
92+
with open(filename, "w") as file:
93+
file.write(fixed_content)
94+
95+
print(
96+
f"Fixed TwinCAT versions for:{itemize}{itemize.join(mismatched_files)}{reason_msg}"
97+
)
98+
else:
99+
exception_message += (
100+
"The following files are not set to the targeted TwinCAT version "
101+
f"{args.target_version}:{itemize}{itemize.join(mismatched_files)}{reason_msg}"
102+
)
103+
else:
104+
unique_versions = set(versions.values())
105+
if len(unique_versions) > 1:
106+
exception_message += (
107+
"Not all files have the same TwinCAT version:"
108+
f"{itemize}"
109+
+ itemize.join(f"{fname}: {ver}" for fname, ver in versions.items())
110+
)
111+
112+
if args.pinned is not None:
113+
mismatched_files = [
114+
fname for fname, pin in pinned.items() if pin != args.pinned
115+
]
116+
if mismatched_files:
117+
if args.fix:
118+
for filename in mismatched_files:
119+
with open(filename, "r") as file:
120+
xml_content = file.read()
121+
fixed_content = fix_pinned_version(xml_content, args.pinned)
122+
with open(filename, "w") as file:
123+
file.write(fixed_content)
124+
print(
125+
f"Fixed pinned state for:{itemize}{itemize.join(mismatched_files)}"
126+
)
127+
else:
128+
should_be_pinned_message = (
129+
"The following files should have a pinned TwinCAT version"
130+
if args.pinned
131+
else "The following files should NOT have a pinned TwinCAT version"
132+
)
133+
exception_message += "\n\n" if len(exception_message) > 0 else ""
134+
exception_message += f"{should_be_pinned_message}{itemize}{itemize.join(mismatched_files)}"
135+
if len(exception_message) > 0:
136+
raise PreCommitException(exception_message)
137+
138+
return 0
139+
except Exception as exc:
140+
print(exc)
141+
return 1
142+
143+
144+
if __name__ == "__main__":
145+
exit(main())

pre_commit_hooks/exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class PreCommitException(Exception):
2+
pass

pre_commit_hooks/minimize_id_changes.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
from importlib.abc import Traversable
44
from typing import Union
55

6-
7-
class PreCommitException(Exception):
8-
pass
6+
from pre_commit_hooks.exceptions import PreCommitException
97

108

119
def minimize_id_changes_checked(filename: Union[Traversable, str]) -> None:

pre_commit_hooks/no_product_version.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
from lxml import etree
66

7-
8-
class PreCommitException(Exception):
9-
pass
7+
from pre_commit_hooks.exceptions import PreCommitException
108

119

1210
def check_file(filename):

0 commit comments

Comments
 (0)