diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/SemanticDataRepository.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/SemanticDataRepository.kt index a9539c7e..e5fb83d6 100644 --- a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/SemanticDataRepository.kt +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/SemanticDataRepository.kt @@ -154,6 +154,7 @@ class SemanticDataRepository private constructor() { validatorMap.putAll(RlimitOptionValue.validators) // Scopes are not supported since they aren't standard unit files. validatorMap.putAll(NetworkAddressOptionValue.validators) validatorMap.putAll(InAddrPrefixesOptionValue.validators) + validatorMap.putAll(UIntOptionValues.validators) fileClassToSectionNameToKeyValuesFromDoc["unit"]?.remove(SCOPE_KEYWORD) fileClassToSectionToKeyAndValidatorMap["unit"]?.remove(SCOPE_KEYWORD) } @@ -706,7 +707,7 @@ unit types. These options are documented in setOf( - "BareUDP", "BatmanAdvanced", "Bond", "Bridge", "FooOverUDP", "GENEVE", "IPoIB", "IPVLAN", "IPVTAP", + "BareUDP", "BatmanAdvanced", "Bond", "Bridge", "FooOverUDP", "GENEVE", "HSR", "IPoIB", "IPVLAN", "IPVTAP", "L2TP", "L2TPSession", "MACsec", "MACsecReceiveAssociation", "MACsecReceiveChannel", "MACsecTransmitAssociation", "MACVLAN", "MACVTAP", "Match", "NetDev", "Peer", "Tap", "Tun", "Tunnel", "VLAN", "VRF", "VXCAN", "VXLAN", "WireGuard", "WireGuardPeer", "WLAN", "Xfrm", "NetDev" diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/UIntOptionValues.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/UIntOptionValues.kt new file mode 100644 index 00000000..be22d8d8 --- /dev/null +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/UIntOptionValues.kt @@ -0,0 +1,19 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues + +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.Validator +import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar.* + + + +class UIntOptionValues(validatorName: String, grammar: Combinator) : GrammarOptionValue(validatorName, grammar) { + + companion object { + + val validators = mapOf( + Validator("config_parse_uint32", "0") to UIntOptionValues("config_parse_uint32", SequenceCombinator(IntegerTerminal(0, 4_294_967_296 ), EOF())), + Validator("config_parse_uint16", "0") to UIntOptionValues("config_parse_uint16", SequenceCombinator(IntegerTerminal(0, 65536), EOF())), + Validator("config_parse_uint8", "0") to UIntOptionValues("config_parse_uint8", SequenceCombinator(IntegerTerminal(0, 256), EOF())), + ) + } +} + diff --git a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/IntegerTerminal.kt b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/IntegerTerminal.kt index f1107238..11864d77 100644 --- a/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/IntegerTerminal.kt +++ b/src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/IntegerTerminal.kt @@ -1,6 +1,8 @@ package net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.optionvalues.grammar -class IntegerTerminal(private val minInclusive: Int,private val maxExclusive: Int) : TerminalCombinator { +class IntegerTerminal(private val minInclusive: Long,private val maxExclusive: Long) : TerminalCombinator { + + constructor(minInclusive: Int, maxExclusive: Int) : this(minInclusive.toLong(), maxExclusive.toLong()) val intRegex = "-?[0-9]+".toRegex() @@ -14,13 +16,17 @@ class IntegerTerminal(private val minInclusive: Int,private val maxExclusive: In override fun SemanticMatch(value: String, offset: Int): MatchResult { val matchResult = intRegex.matchAt(value, offset) ?: return NoMatch - val intValue = matchResult.value.toInt() + try { + val intValue = matchResult.value.toLong() + + if (intValue < minInclusive || intValue >= maxExclusive) { + return NoMatch.copy(longestMatch = offset) + } - if (intValue < minInclusive || intValue >= maxExclusive) { + return MatchResult(listOf(matchResult.value), offset + matchResult.value.length, listOf(this), offset + matchResult.value.length) + } catch (e: NumberFormatException) { return NoMatch.copy(longestMatch = offset) } - - return MatchResult(listOf(matchResult.value), offset + matchResult.value.length, listOf(this), offset + matchResult.value.length) } override fun toString(): String { diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/annotators/InvalidSectionHeaderNameAnnotatorTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/annotators/InvalidSectionHeaderNameAnnotatorTest.kt index 52996978..8012dcd0 100644 --- a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/annotators/InvalidSectionHeaderNameAnnotatorTest.kt +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/annotators/InvalidSectionHeaderNameAnnotatorTest.kt @@ -524,9 +524,9 @@ class InvalidSectionHeaderNameAnnotatorTest : AbstractUnitFileTest() { val highlightTexts = highlights.map { it.description } - assertContainsElements(highlightTexts, "The section Unit is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") - assertContainsElements(highlightTexts, "The section Install is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") - assertContainsElements(highlightTexts, "The section Service is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") + assertContainsElements(highlightTexts, "The section Unit is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") + assertContainsElements(highlightTexts, "The section Install is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") + assertContainsElements(highlightTexts, "The section Service is not allowed in Netdev files, only the following are allowed: [BareUDP, BatmanAdvanced, Bond, Bridge, FooOverUDP, GENEVE, HSR, IPoIB, IPVLAN, IPVTAP, L2TP, L2TPSession, MACsec, MACsecReceiveAssociation, MACsecReceiveChannel, MACsecTransmitAssociation, MACVLAN, MACVTAP, Match, NetDev, Peer, Tap, Tun, Tunnel, VLAN, VRF, VXCAN, VXLAN, WireGuard, WireGuardPeer, WLAN, Xfrm]") } fun testServiceSectionsInNetworkFileHasWarnings() { diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForUIntOptionValue.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForUIntOptionValue.kt new file mode 100644 index 00000000..00cec0ec --- /dev/null +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/inspections/InvalidValueInspectionForUIntOptionValue.kt @@ -0,0 +1,121 @@ +package net.sjrx.intellij.plugins.systemdunitfiles.inspections + +import junit.framework.TestCase +import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest + +class InvalidValueInspectionForUIntOptionValue : AbstractUnitFileTest() { + + fun testWeakWarningWhenNegativeIntegerSpecified() { + // Fixture Setup + // language="unit file (systemd)" + val file = """ + [VXLAN] + # uint32 + VNI=-1 + + [Bridge] + # uint16 + Priority=-2 + + [HSR] + # uint8 + Supervision=-3 + """.trimIndent() + + + // Execute SUT + setupFileInEditor("file.netdev", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + // Verification + assertSize(3, highlights) + var info = highlights[0] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("-1", info.text) + + info = highlights[1] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("-2", info.text) + + info = highlights[2] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("-3", info.text) + } + + fun testWeakWarningWhenTooBigAnIntegerSpecified() { + // Fixture Setup + // language="unit file (systemd)" + val file = """ + [VXLAN] + # uint32 + VNI=9999999999 + + [Bridge] + # uint16 + Priority=65536 + + [HSR] + # uint8 + Supervision=256 + """.trimIndent() + + + // Execute SUT + setupFileInEditor("file.netdev", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + // Verification + assertSize(3, highlights) + var info = highlights[0] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("9999999999", info.text) + + info = highlights[1] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("65536", info.text) + + info = highlights[2] + assertStringContains("is correctly formatted but seems invalid", info!!.description) + TestCase.assertEquals("256", info.text) + } + + fun testNoWeakWarningOnBoundaryConditions() { + // Fixture Setup + // language="unit file (systemd)" + val file = """ + [VXLAN] + # uint32 + VNI=0 + VNI=1 + VNI=4294967295 + VNI=4294967294 + VNI=2294967294 + VNI=2094967294 + VNI=65536 + VNI=65534 + + [Bridge] + # uint16 + Priority=0 + Priority=1 + Priority=65535 + + [HSR] + # uint8 + Supervision=0 + Supervision=1 + Supervision=255 + """.trimIndent() + + // Execute SUT + setupFileInEditor("file.netdev", file) + enableInspection(InvalidValueInspection::class.java) + val highlights = myFixture.doHighlighting() + + // Verification + assertSize(0, highlights) + } + +} diff --git a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/OptionValueTest.kt b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/OptionValueTest.kt index fbf54967..28bc3ae8 100644 --- a/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/OptionValueTest.kt +++ b/src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/OptionValueTest.kt @@ -4,6 +4,8 @@ import net.sjrx.intellij.plugins.systemdunitfiles.AbstractUnitFileTest import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.FileClass import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.SemanticDataRepository import net.sjrx.intellij.plugins.systemdunitfiles.semanticdata.Validator +import java.time.LocalDate +import java.time.temporal.ChronoUnit class OptionValueTest : AbstractUnitFileTest() { @@ -35,7 +37,14 @@ class OptionValueTest : AbstractUnitFileTest() { println("Missing:$totalMissingValidators") println("Found:$totalFoundValidators") - val allowed = 1183 + + val startDate = LocalDate.of(2025, 7, 12) // Today's date + val startingCount = 1183 // Your current undocumented options count + val currentDate = LocalDate.now() + val daysSinceStart = ChronoUnit.DAYS.between(startDate, currentDate) + val reductionPerDay = 4 + val allowed = maxOf(0, startingCount - (daysSinceStart * reductionPerDay)) + if (totalMissingValidators >= allowed) { assertEquals("Number of missing validators is too high at ${totalMissingValidators} > $allowed vs. found ${totalFoundValidators}", sortedList, "") } diff --git a/systemd-build/Systemd-Builder.Dockerfile b/systemd-build/Systemd-Builder.Dockerfile index 4910af9e..aa4edd3e 100644 --- a/systemd-build/Systemd-Builder.Dockerfile +++ b/systemd-build/Systemd-Builder.Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && apt-get -y install git build-essential tzdata meson pkg-co RUN mkdir /opt/systemd-source -RUN git clone https://github.com/systemd/systemd.git /opt/systemd-source/systemd +RUN git clone https://github.com/systemd/systemd.git /opt/systemd-source/systemd --single-branch --depth=1 WORKDIR /opt/systemd-source/systemd diff --git a/systemd-build/systemd-build.sh b/systemd-build/systemd-build.sh index 8a3d6bad..e812801f 100755 --- a/systemd-build/systemd-build.sh +++ b/systemd-build/systemd-build.sh @@ -21,7 +21,7 @@ echo "Git Pull" && \ cp ./src/network/networkd-network-gperf.gperf /mount/ && \ cp ./src/network/networkd-gperf.gperf /mount/ && \ cp -R ./man /mount/ && \ - /usr/bin/meson --internal exe --capture /mount/man/ethtool-link-mode.xml -- /usr/bin/python3 ./src/shared/ethtool-link-mode.py --xml 'cc -E' ./src/basic/include/linux/ethtool.h && \ + /usr/bin/meson --internal exe --capture /mount/man/ethtool-link-mode.xml -- /usr/bin/python3 ./src/shared/ethtool-link-mode.py --xml 'cc -E' ./src/include/uapi/linux/ethtool.h && \ git log --format="%at" | sort | tail -n 1 | xargs -I{} date -d @{} +%Y-%m-%d > last_commit_date && \ git rev-parse --short=10 HEAD > last_commit_hash && \ cp last_commit_date last_commit_hash /mount/ && \