Sat, 02 Nov 2024 14:22:05 +0100
add compatibility check - resolves #477
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/unixwork/uwproj/CompatibilityCheck.java Sat Nov 02 14:22:05 2024 +0100 @@ -0,0 +1,35 @@ +package de.unixwork.uwproj; + +public class CompatibilityCheck { + + private CompatibilityCheck() {} + + private static int[] versionParts(String ver) { + if (ver.isBlank()) return new int[]{0,0,0}; + final var partStrings = ver.split("\\."); + try { + return new int[]{ + partStrings.length > 0 ? Integer.parseInt(partStrings[0]) : 0, + partStrings.length > 1 ? Integer.parseInt(partStrings[1]) : 0, + partStrings.length > 2 ? Integer.parseInt(partStrings[2]) : 0 + }; + } catch (NumberFormatException e) { + return new int[]{0,0,0}; + } + } + + public static void check(String expected, String actual) throws CompatibilityException { + final var expectedVer = versionParts(expected); + final var actualVer = versionParts(actual); + if (expectedVer[0] > actualVer[0] || expectedVer[1] > actualVer[1]) { + if (actual.isBlank()) actual = "unspecified"; + throw new CompatibilityException("Expected project file version '" + expected + "' but got '" + actual + "'."); + } + } + + public static class CompatibilityException extends Exception { + public CompatibilityException(String message) { + super(message); + } + } +}
--- a/src/main/java/de/unixwork/uwproj/Main.java Sun Oct 06 14:02:50 2024 +0200 +++ b/src/main/java/de/unixwork/uwproj/Main.java Sat Nov 02 14:22:05 2024 +0100 @@ -18,13 +18,27 @@ import java.util.Objects; public class Main { + public static final String PROGRAM_VERSION = "0.3"; public final static String IN_FILE_DEFAULT = "make/project.xml"; public final static String TPL_FILE_DEFAULT = "make/configure.vm"; public final static String OUT_FILE_DEFAULT = "configure"; - static Project loadProjectFile(String fileName) { + static Project loadProjectFile(String fileName) throws CompatibilityCheck.CompatibilityException { try (final var xsdResource = Objects.requireNonNull(Main.class.getClassLoader().getResourceAsStream("make/uwproj.xsd"))) { + // Load the DOM from the input file + final var dom = DocumentBuilderFactory. + newDefaultNSInstance(). + newDocumentBuilder(). + parse(fileName). + getDocumentElement(); + + // Check the version, first + CompatibilityCheck.check(PROGRAM_VERSION, dom.getAttribute("version")); + + // Parse the XML + final var proj = new Project(dom); + // Create the XSD validator final var factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); final var schema = factory.newSchema(new StreamSource(xsdResource)); @@ -33,21 +47,15 @@ // Validate the XML as stream (DOM validation cannot output line numbers in error message) validator.validate(new StreamSource(new File(fileName))); - // Load the DOM from the input file - final var dom = DocumentBuilderFactory. - newDefaultNSInstance(). - newDocumentBuilder(). - parse(fileName). - getDocumentElement(); - - // Parse the XML - return new Project(dom); + return proj; } catch (SAXParseException saxerror) { System.err.printf("Parse error in line %d, column %d: %s", saxerror.getLineNumber(), saxerror.getColumnNumber(), saxerror.getMessage()); throw new RuntimeException("XML validation failed."); + } catch (CompatibilityCheck.CompatibilityException e) { + throw e; } catch (Exception e) { throw new RuntimeException(e); } @@ -207,8 +215,11 @@ writeConfigureScript(out, tplFileName, loadProjectFile(inFileName)); } Files.copy(tmp.toPath(), outFilePath, StandardCopyOption.REPLACE_EXISTING); + } catch (CompatibilityCheck.CompatibilityException e) { + System.err.println("Compatibility problem: " + e.getMessage()); + abort(); } catch (Throwable t) { - System.err.printf("Unexpected error: %s\n", t.getMessage()); + System.err.println("Unexpected error: " + t.getMessage()); abort(); } @@ -216,7 +227,7 @@ try { Files.setPosixFilePermissions(outFilePath, PosixFilePermissions.fromString("rwxr-xr-x")); } catch (Throwable t) { - System.err.printf("WARN: Setting file permissions failed: %s\n", t.getMessage()); + System.err.println("WARN: Setting file permissions failed: " + t.getMessage()); } } }
--- a/src/main/resources/make/project.xml Sun Oct 06 14:02:50 2024 +0200 +++ b/src/main/resources/make/project.xml Sat Nov 02 14:22:05 2024 +0100 @@ -1,4 +1,3 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://unixwork.de/uwproj"> +<project version="0.3" xmlns="http://unixwork.de/uwproj"> </project> -
--- a/src/main/resources/make/uwproj.xsd Sun Oct 06 14:02:50 2024 +0200 +++ b/src/main/resources/make/uwproj.xsd Sat Nov 02 14:22:05 2024 +0100 @@ -3,7 +3,7 @@ xmlns="http://unixwork.de/uwproj" targetNamespace="http://unixwork.de/uwproj" elementFormDefault="qualified" - version="0.2" + version="0.3" > <xs:element name="project" type="ProjectType"/> @@ -21,6 +21,7 @@ <xs:element name="dependency" type="DependencyType" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="target" type="TargetType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> + <xs:attribute name="version" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="ConfigType">
--- a/test/make/project.xml Sun Oct 06 14:02:50 2024 +0200 +++ b/test/make/project.xml Sat Nov 02 14:22:05 2024 +0100 @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://unixwork.de/uwproj"> +<project version="0.3" xmlns="http://unixwork.de/uwproj"> <!-- makefile config --> <config not="mingw"> <var name="prefix">`pwd`/work</var>
--- a/test/make/project2.xml Sun Oct 06 14:02:50 2024 +0200 +++ b/test/make/project2.xml Sat Nov 02 14:22:05 2024 +0100 @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://unixwork.de/uwproj"> +<project version="0.3" xmlns="http://unixwork.de/uwproj"> <dependency name="curl" platform="windows"> <cflags>-I/mingw/include</cflags> <ldflags>-lcurl</ldflags>
--- a/test/make/uwproj.xsd Sun Oct 06 14:02:50 2024 +0200 +++ b/test/make/uwproj.xsd Sat Nov 02 14:22:05 2024 +0100 @@ -3,7 +3,7 @@ xmlns="http://unixwork.de/uwproj" targetNamespace="http://unixwork.de/uwproj" elementFormDefault="qualified" - version="0.2" + version="0.3" > <xs:element name="project" type="ProjectType"/> @@ -21,6 +21,7 @@ <xs:element name="dependency" type="DependencyType" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="target" type="TargetType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> + <xs:attribute name="version" type="xs:string" use="required" /> </xs:complexType> <xs:complexType name="ConfigType">