minimize application code

Sun, 28 Jan 2024 14:02:41 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 28 Jan 2024 14:02:41 +0100
changeset 113
24f32dbd88cd
parent 112
206e91a8dd18
child 114
0fa5a6f08245

minimize application code

src/main/java/de/unixwork/uwproj/ConfigVar.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Define.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Dependency.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Feature.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/NamedDependency.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Option.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/OptionDefault.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/OptionValue.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/PkgConfigPackage.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Project.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Target.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/TargetData.java file | annotate | diff | comparison | revisions
src/main/java/de/unixwork/uwproj/Util.java file | annotate | diff | comparison | revisions
test/configure2 file | annotate | diff | comparison | revisions
--- a/src/main/java/de/unixwork/uwproj/ConfigVar.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/ConfigVar.java	Sun Jan 28 14:02:41 2024 +0100
@@ -2,34 +2,24 @@
 
 import org.w3c.dom.Element;
 
-public class ConfigVar {
-    private String varName;
-    private String value;
-    private boolean exec = false;
+public final class ConfigVar {
+    private final String varName;
+    private final String value;
+    private final boolean exec;
 
-    public static ConfigVar parse(Element e) {
-        return parse(e, false);
+    public ConfigVar(Element e) {
+        this(e, false);
     }
 
-    public static ConfigVar parse(Element e, boolean varNameIsElemName) {
-        ConfigVar var = new ConfigVar();
-
+    public ConfigVar(Element e, boolean varNameIsElemName) {
         if (varNameIsElemName) {
             // take the node name literally and don't apply shId()
-            var.varName = e.getNodeName().toUpperCase();
+            varName = e.getNodeName().toUpperCase();
         } else {
-            String name = e.getAttribute("name");
-            if (name.isBlank()) {
-                System.err.println("<var>-element: name attribute required");
-                return null;
-            }
-            var.varName = name;
+            varName = e.getAttribute("name");
         }
-
-        var.value = Util.getContent(e);
-        var.exec = Boolean.parseBoolean(e.getAttribute("exec"));
-
-        return var;
+        value = Util.getContent(e);
+        exec = Boolean.parseBoolean(e.getAttribute("exec"));
     }
 
     public String getVarName() {
--- a/src/main/java/de/unixwork/uwproj/Define.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Define.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,6 +1,6 @@
 package de.unixwork.uwproj;
 
-public class Define {
+public final class Define {
     private final String name;
     private final String value;
 
@@ -8,7 +8,17 @@
         this.name = name;
         this.value = value;
     }
-    
+
+    public String toFlags() {
+        if (name.isBlank()) {
+            return "";
+        } else if (value.isBlank()) {
+            return "-D" + name;
+        } else {
+            return "-D" + name + "=" + value;
+        }
+    }
+
     public String getName() {
         return name;
     }
@@ -16,14 +26,4 @@
     public String getValue() {
         return value;
     }
-    
-    public String toFlags() {
-        if(name == null) {
-            return "";
-        } else if(value == null) {
-            return "-D"+name;
-        } else {
-            return "-D"+name + "=" + value;
-        }
-    }
 }
--- a/src/main/java/de/unixwork/uwproj/Dependency.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Dependency.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,112 +1,81 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-import static de.unixwork.uwproj.Util.isNullOrBlank;
-
-public class Dependency {
-    private String name;
-    private String platform;
-    private String toolchain;
-    private String not;
+public final class Dependency {
+    private final String id;
+    private final String name;
+    private final String platform;
+    private final String toolchain;
+    private final String not;
 
     private final List<ConfigVar> flags = new LinkedList<>();
     private final List<PkgConfigPackage> pkgconfig = new LinkedList<>();
     private final List<String> tests = new LinkedList<>();
-    private final StringBuilder make = new StringBuilder();
+    private final List<String> make = new LinkedList<>();
 
     private final List<String> lang = new LinkedList<>();
 
-    private int num = 0;
-
-    public static Dependency parse(Element element) throws Exception {
-        Dependency d = new Dependency();
-
-        String name = element.getAttribute("name");
-        String platform = element.getAttribute("platform");
-        String toolchain = element.getAttribute("toolchain");
-        String not = element.getAttribute("not");
-        if (!name.isEmpty()) {
-            d.setName(name);
-        }
-        if (!platform.isEmpty()) {
-            d.setPlatform(platform);
-        }
-        if (!toolchain.isEmpty()) {
-            d.setToolchain(toolchain);
-        }
-        if (!not.isEmpty()) {
-            d.setNotString(not);
-        }
+    public Dependency(Element element) {
+        name = element.getAttribute("name");
+        id = Util.shId(name);
+        platform = element.getAttribute("platform");
+        toolchain = element.getAttribute("toolchain");
+        not = element.getAttribute("not");
 
-        NodeList nodes = element.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeType() == Node.ELEMENT_NODE) {
-                Element elm = (Element) node;
-                String n = elm.getNodeName();
-                if (n.equals("cflags") || n.equals("cxxflags") || n.equals("ldflags")) {
-                    Optional.ofNullable(ConfigVar.parse(elm, true)).ifPresent(d::addFlags);
-                } else if (n.equals("pkgconfig")) {
-                    PkgConfigPackage pcp = PkgConfigPackage.parse(elm);
-                    d.addPkgconfig(pcp);
-                } else if (n.equals("test")) {
-                    d.tests.add(Util.getContent(elm));
-                } else if (n.equals("make")) {
-                    d.addMake(Util.getContent(elm));
-                } else if (n.equals("lang")) {
-                    d.lang.add(Util.getContent(elm).toLowerCase());
-                }
+        Util.getChildElements(element).forEach(elm -> {
+            switch (elm.getNodeName()) {
+                case "cflags", "cxxflags", "ldflags" -> flags.add(new ConfigVar(elm, true));
+                case "pkgconfig" -> pkgconfig.add(new PkgConfigPackage(elm));
+                case "test" -> tests.add(Util.getContent(elm));
+                case "make" -> make.add(Util.getContent(elm));
+                case "lang" -> lang.add(Util.getContent(elm).toLowerCase());
             }
-        }
+        });
+    }
 
-        return d;
+    /**
+     * Returns the ID of this dependency, if it has a name.
+     * @return the ID that can be used for shell scripts - empty if dependency has not a name
+     */
+    public String getId() {
+        return id;
+    }
+
+    public boolean hasName() {
+        return !name.isEmpty();
     }
 
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public String getPlatform() {
         return platform;
     }
 
     public String getFullName() {
         String fname = name;
-        if (!isNullOrBlank(platform)) {
+        if (!platform.isBlank()) {
             fname += " platform=\"" + platform + '"';
         }
-        if (!isNullOrBlank(toolchain)) {
+        if (!toolchain.isBlank()) {
             fname += " toolchain=\"" + toolchain + '"';
         }
         return fname;
     }
 
-    public void setNotString(String not) {
-        this.not = not;
-    }
-
     public List<String> getNotList() {
-        return isNullOrBlank(not) ?
-                Collections.emptyList() :
-                Arrays.stream(not.split(",")).map(String::trim).collect(Collectors.toList());
-    }
-
-    public void setPlatform(String platform) {
-        this.platform = platform;
-    }
-
-    public void setToolchain(String toolchain) {
-        this.toolchain = toolchain;
+        return Arrays.stream(not.split(","))
+                .map(String::trim)
+                .filter(Predicate.not(String::isEmpty))
+                .collect(Collectors.toList());
     }
 
     public String getToolchain() { return toolchain; }
@@ -115,37 +84,16 @@
         return flags;
     }
 
-    public void addFlags(ConfigVar var) {
-        this.flags.add(var);
-    }
-
     public List<PkgConfigPackage> getPkgconfig() {
         return pkgconfig;
     }
 
-    public void addPkgconfig(PkgConfigPackage pkgconfig) {
-        this.pkgconfig.add(pkgconfig);
-    }
-
-    public int getNum() {
-        return num;
-    }
-
-    public void setNum(int num) {
-        this.num = num;
-    }
-
     public List<String> getTests() {
         return tests;
     }
 
-    public void addMake(String m) {
-        make.append(m.trim());
-        make.append('\n');
-    }
-
     public String getMake() {
-        return make.toString();
+        return String.join("\n", make);
     }
 
     public List<String> getLang() {
--- a/src/main/java/de/unixwork/uwproj/Feature.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Feature.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,56 +1,30 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 import java.util.List;
 
-import static de.unixwork.uwproj.Util.isNotNullOrBlank;
 import static de.unixwork.uwproj.Util.shId;
 
-public class Feature {
-    private String name;
-    private String arg;
-    private boolean auto;
-    private String desc;
-
-    private TargetData targetData;
-
-    public static Feature parse(Project project, Element e) throws Exception {
-        Feature feature = new Feature();
-        String name = e.getAttribute("name");
-        String arg = e.getAttribute("arg");
-
-        if (name.isBlank()) {
-            throw new Exception("feature element requires name attribute");
-        }
+public final class Feature {
+    private final String name;
+    private final String arg;
+    private final boolean auto;
+    private final String desc;
+    private final TargetData targetData;
 
-        feature.setName(name);
-        if (arg.isBlank()) {
-            feature.setArg(name);
-        } else {
-            feature.setArg(arg);
-        }
-
-        feature.setAuto(Boolean.parseBoolean(e.getAttribute("default")));
-        feature.setTargetData(TargetData.parse(e));
-        project.addFeature(feature);
+    public Feature(Element e) {
+        name = e.getAttribute("name");
+        arg = Util.getAttrOrDefault(e, "arg", name);
+        auto = Boolean.parseBoolean(e.getAttribute("default"));
+        targetData = new TargetData(e);
 
-        // TODO: when Option also receives this feature, we might move this to TargetData.parse()
-        NodeList nodes = e.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeType() == Node.ELEMENT_NODE) {
-                Element elm = (Element) node;
-                String n = elm.getNodeName();
-                if (n.equals("desc")) {
-                    feature.setDesc(Util.getContent(elm));
-                }
-            }
-        }
-
-        return feature;
+        // TODO: when Option also receives descriptions, we will move desc to TargetData
+        desc = Util.getChildElements(e)
+                .filter(c -> c.getNodeName().equals("desc"))
+                .map(Util::getContent)
+                .findAny()
+                .orElse("");
     }
 
     public String getVarName() {
@@ -70,49 +44,29 @@
     }
 
     public boolean hasMake() {
-        return isNotNullOrBlank(targetData.getMake());
+        return targetData.hasMake();
     }
 
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public String getArg() {
         return arg;
     }
 
-    public void setArg(String arg) {
-        this.arg = arg;
-    }
-
     public String getDesc() {
         return desc;
     }
 
-    public void setDesc(String desc) {
-        this.desc = desc;
-    }
-
     public boolean isAuto() {
         return auto;
     }
 
-    public void setAuto(boolean auto) {
-        this.auto = auto;
-    }
-
     public TargetData getTargetData() {
         return targetData;
     }
 
-    public void setTargetData(TargetData targetData) {
-        this.targetData = targetData;
-    }
-
     /**
      * Generates help text for the feature option.
      * <p>
@@ -139,7 +93,7 @@
         builder.append(opt);
 
         // Stop, if there is no description
-        if (desc == null || desc.isBlank()) return builder.toString();
+        if (desc.isBlank()) return builder.toString();
 
         // Prepare the description by replacing some unwanted spaces
         final var hdesc = desc.trim()
--- a/src/main/java/de/unixwork/uwproj/NamedDependency.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/NamedDependency.java	Sun Jan 28 14:02:41 2024 +0100
@@ -4,27 +4,24 @@
 
 import static de.unixwork.uwproj.Util.shId;
 
-public class NamedDependency {
-    private String name;
-    private List<Dependency> subdependencies;
+public final class NamedDependency {
+    private final String name;
+    private final List<Dependency> subdependencies;
 
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
+    public NamedDependency(String name, List<Dependency> subdependencies) {
         this.name = name;
+        this.subdependencies = subdependencies;
     }
 
     public String getId() {
         return shId(name);
     }
 
+    public String getName() {
+        return name;
+    }
+
     public List<Dependency> getSubdependencies() {
         return subdependencies;
     }
-
-    public void setSubdependencies(List<Dependency> subdependency) {
-        this.subdependencies = subdependency;
-    }
 }
--- a/src/main/java/de/unixwork/uwproj/Option.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Option.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,8 +1,6 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 import java.util.LinkedList;
 import java.util.List;
@@ -10,54 +8,30 @@
 
 import static de.unixwork.uwproj.Util.shId;
 
-public class Option {
-    private String arg;
+public final class Option {
+    private final String arg;
 
     private final LinkedList<OptionValue> values = new LinkedList<>();
     private final LinkedList<OptionDefault> defaults = new LinkedList<>();
 
-    public static Option parse(Element element) throws Exception {
-        var opt = new Option();
-        String arg = element.getAttribute("arg");
-        if (arg.isBlank()) {
-            throw new Exception("Option has no argument string");
-        }
-        opt.setArgument(arg);
-
-        NodeList nodes = element.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeType() == Node.ELEMENT_NODE) {
-                Element elm = (Element) node;
-                String n = elm.getNodeName();
-                if (n.equals("value")) {
-                    opt.values.add(new OptionValue(opt,
-                            elm.getAttribute("str"),
-                            TargetData.parse(elm)
-                    ));
-                } else if (n.equals("default")) {
-                    var def = new OptionDefault(opt);
-                    def.setValueName(elm.getAttribute("value"));
-                    String defPlatform = elm.getAttribute(("platform"));
-                    if (!defPlatform.isBlank()) {
-                        def.setPlatform(defPlatform);
-                    }
-                    opt.defaults.add(def);
-                }
+    public Option(Element element) {
+        arg = element.getAttribute("arg");
+        Util.getChildElements(element).forEach(elm -> {
+            switch (elm.getNodeName()) {
+                case "value" -> values.add(new OptionValue(this,
+                        elm.getAttribute("str"),
+                        new TargetData(elm)));
+                case "default" -> defaults.add(new OptionDefault(this,
+                        elm.getAttribute("value"),
+                        elm.getAttribute("platform")));
             }
-        }
-
-        return opt;
+        });
     }
 
     public String getArgument() {
         return arg;
     }
 
-    public void setArgument(String arg) {
-        this.arg = arg;
-    }
-
     public String getVarName() {
         return shId("OPT_" + arg.toUpperCase());
     }
--- a/src/main/java/de/unixwork/uwproj/OptionDefault.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/OptionDefault.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,30 +1,24 @@
 package de.unixwork.uwproj;
 
-public class OptionDefault {
+public final class OptionDefault {
     private final Option option;
-    private String valueName;
-    private String platform;
+    private final String valueName;
+    private final String platform;
 
-    public OptionDefault(Option opt) {
-        option = opt;
+    public OptionDefault(Option option, String valueName, String platform) {
+        this.option = option;
+        this.valueName = valueName;
+        this.platform = platform;
     }
 
     public String getValueName() {
         return valueName;
     }
 
-    public void setValueName(String valueName) {
-        this.valueName = valueName;
-    }
-
     public String getPlatform() {
         return platform;
     }
 
-    public void setPlatform(String platform) {
-        this.platform = platform;
-    }
-
     public String getFunc() {
         return option.getValueFunc(valueName);
     }
--- a/src/main/java/de/unixwork/uwproj/OptionValue.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/OptionValue.java	Sun Jan 28 14:02:41 2024 +0100
@@ -2,9 +2,7 @@
 
 import java.util.List;
 
-import static de.unixwork.uwproj.Util.isNotNullOrBlank;
-
-public class OptionValue {
+public final class OptionValue {
     private final Option option;
 
     private final String value;
@@ -21,7 +19,6 @@
         return value;
     }
 
-
     public List<String> getDependencies() {
         return targetData.getDependencies();
     }
@@ -39,6 +36,6 @@
     }
 
     public boolean hasMake() {
-        return isNotNullOrBlank(targetData.getMake());
+        return targetData.hasMake();
     }
 }
--- a/src/main/java/de/unixwork/uwproj/PkgConfigPackage.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/PkgConfigPackage.java	Sun Jan 28 14:02:41 2024 +0100
@@ -3,64 +3,37 @@
 import org.w3c.dom.Element;
 
 public class PkgConfigPackage {
-    private String id;
-    private String name;
-    private String atleast;
-    private String exact;
-    private String max;
+    private final String id;
+    private final String name;
+    private final String atleast;
+    private final String exact;
+    private final String max;
 
-    public static PkgConfigPackage parse(Element e) throws Exception {
-        var p = new PkgConfigPackage();
-        String name = Util.getContent(e);
-        if (name.isBlank()) {
-            throw new Exception("pkgconfig element: value required");
-        } else {
-            p.setName(name);
-            p.setId(Util.shId(name));
-        }
-        p.setAtleast(e.getAttribute("atleast"));
-        p.setExact(e.getAttribute("exact"));
-        p.setMax(e.getAttribute("max"));
-        return p;
+    public PkgConfigPackage(Element e) {
+        name = Util.getContent(e);
+        id = Util.shId(name);
+        atleast = e.getAttribute("atleast");
+        exact = e.getAttribute("exact");
+        max = e.getAttribute("max");
     }
 
     public String getId() {
         return id;
     }
 
-    public void setId(String id) {
-        this.id = id;
-    }
-
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public String getAtleast() {
         return atleast;
     }
 
-    public void setAtleast(String atleast) {
-        this.atleast = atleast;
-    }
-
     public String getMax() {
         return max;
     }
 
-    public void setMax(String max) {
-        this.max = max;
-    }
-
     public String getExact() {
         return exact;
     }
-
-    public void setExact(String exact) {
-        this.exact = exact;
-    }
 }
--- a/src/main/java/de/unixwork/uwproj/Project.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Project.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,14 +1,8 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
-import javax.xml.parsers.DocumentBuilderFactory;
-import java.io.File;
 import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 public class Project {
     private final HashMap<String, List<Dependency>> namedDependencies = new HashMap<>();
@@ -17,70 +11,50 @@
     private final List<Option> options = new LinkedList<>();
     private final List<Feature> features = new LinkedList<>();
 
-    private final HashMap<String, ConfigVar> configVars = new HashMap<>();
     private final List<ConfigVar> configVarsList = new LinkedList<>();
     
-    private final Set<String> lang;
-
-    public Project(Element root) throws Exception {
-        NodeList dependency_nodes = root.getElementsByTagName("dependency");
-        NodeList target_nodes = root.getElementsByTagName("target");
-        NodeList config_nodes = root.getElementsByTagName("config");
+    private final Set<String> lang = new HashSet<>();
 
-        for (int i = 0; i < config_nodes.getLength(); i++) {
-            NodeList cfgs = config_nodes.item(i).getChildNodes();
-            for (int c = 0; c < cfgs.getLength(); c++) {
-                Node node = cfgs.item(c);
-                if (node.getNodeType() == Node.ELEMENT_NODE) {
-                    if (node.getNodeName().equals("var")) {
-                        Optional.ofNullable(ConfigVar.parse((Element) node)).ifPresent(v -> {
-                            configVars.put(v.getVarName(), v);
-                            configVarsList.add(v);
-                        });
+    public Project(Element root) {
+        Util.getChildElements(root).forEach(element -> {
+            switch (element.getNodeName()) {
+                case "config" -> Util.getChildElements(element).forEach(v -> {
+                    if (v.getNodeName().equals("var")) {
+                        configVarsList.add(new ConfigVar(v));
+                    }
+                });
+                case "dependency" -> {
+                    final var dependency = new Dependency(element);
+                    lang.addAll(dependency.getLang());
+                    if (dependency.hasName()) {
+                        namedDependencies.computeIfAbsent(dependency.getId(), k -> new LinkedList<>()).add(dependency);
+                    } else {
+                        dependencies.add(dependency);
                     }
                 }
+                case "target" -> {
+                    final var target = new Target(element);
+                    targets.add(target);
+                    features.addAll(target.getFeatures());
+                    options.addAll(target.getOptions());
+                }
             }
+        });
+
+        // add default target, if no target was specified
+        if (targets.isEmpty()) {
+            targets.add(Target.defaultTarget());
         }
 
-        for (int i = 0; i < dependency_nodes.getLength(); i++) {
-            addDependency(Dependency.parse((Element) dependency_nodes.item(i)));
-        }
-        for (int i = 0; i < target_nodes.getLength(); i++) {
-            targets.add(Target.parse(this, (Element) target_nodes.item(i)));
-        }
-
-        if (targets.isEmpty()) {
-            createDefaultTarget();
-        }
-        
-        // create a list of all languages that are used
-        lang = Stream.concat(
-            namedDependencies.values().stream().flatMap(Collection::stream),
-            dependencies.stream()
-        ).flatMap(d -> d.getLang().stream()).collect(Collectors.toSet());
-
         // check if some targets want all named dependencies
-        targets.stream().filter(Target::isAllDependencies).forEach(t -> {
-            t.clearDependencies();
-            namedDependencies.keySet().forEach(t::addDependency);
-        });
-    }
-
-    private void createDefaultTarget() {
-        var t = new Target();
-        t.setAllDependencies(true);
-        t.setName("default");
-        addTarget(t);
+        targets.stream().filter(Target::wantsAllDependencies)
+                .forEach(t -> t.replaceAllDependencies(namedDependencies.keySet()));
     }
 
     public List<NamedDependency> getNamedDependencies() {
         var ret = new LinkedList<NamedDependency>();
-
         for (var entry : namedDependencies.entrySet()) {
-            var d = new NamedDependency();
-            d.setName(entry.getKey());
-            d.setSubdependencies(entry.getValue());
-            ret.add(d);
+            ret.add(new NamedDependency(entry.getKey(), entry.getValue()));
         }
         return ret;
     }
@@ -93,32 +67,10 @@
         return targets;
     }
 
-    public void addDependency(Dependency dependency) {
-        if(dependency.getName() != null) {
-            List<Dependency> l = namedDependencies.computeIfAbsent(dependency.getName(), k -> new LinkedList<>());
-            dependency.setNum(l.size());
-            l.add(dependency);
-        } else {
-            dependencies.add(dependency);
-        }
-    }
-
-    public void addTarget(Target target) {
-        targets.add(target);
-    }
-
-    public void addOption(Option o) {
-        options.add(o);
-    }
-
     public List<Option> getOptions() {
         return options;
     }
 
-    public void addFeature(Feature feature) {
-        features.add(feature);
-    }
-
     public List<Feature> getFeatures() {
         return features;
     }
--- a/src/main/java/de/unixwork/uwproj/Target.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Target.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,19 +1,18 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 
-import static de.unixwork.uwproj.Util.*;
+import static de.unixwork.uwproj.Util.shId;
 import static java.util.function.Predicate.not;
 
-public class Target {
-    private String name = "";
-    private String prefix;
+public final class Target {
+    private final String name;
+    private final String prefix;
 
     private final List<String> dependencies = new LinkedList<>();
     private final List<Define> defines = new LinkedList<>();
@@ -22,67 +21,51 @@
 
     private boolean allDependencies = false;
 
-    public static Target parse(Project project, Element element) throws Exception {
-        var target = new Target();
+    public static Target defaultTarget() {
+        return new Target();
+    }
 
-        String name = element.getAttribute("name");
-        if (!name.isBlank()) {
-            target.setName(name);
-        }
+    private Target() {
+        name = "default";
+        prefix = "";
+        allDependencies = true;
+    }
 
-        NodeList nodes = element.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeType() == Node.ELEMENT_NODE) {
-                Element elm = (Element) node;
-                String n = elm.getNodeName();
-                if (n.equals("feature")) {
-                    target.addFeature(Feature.parse(project, elm));
-                } else if (n.equals("define")) {
-                    target.addDefine(
-                            elm.getAttribute("name"),
-                            elm.getAttribute("value")
-                    );
-                } else if (n.equals("dependencies")) {
-                    Arrays.stream(Util.getContent(elm).split(","))
-                            .map(String::trim)
-                            .filter(not(String::isBlank))
-                            .forEach(target::addDependency);
-                } else if (n.equals("alldependencies")) {
-                    target.setAllDependencies(true);
-                } else if (n.equals("option")) {
-                    var opt = Option.parse(elm);
-                    target.addOption(opt);
-                    project.addOption(opt);
-                }
+    public Target(Element element) {
+        this.name = element.getAttribute("name").trim();
+        if (this.name.isEmpty()) {
+            prefix = "";
+        } else {
+            prefix = shId(name.toUpperCase());
+        }
+        Util.getChildElements(element).forEach(elm -> {
+            switch (elm.getNodeName()) {
+                case "feature" -> features.add(new Feature(elm));
+                case "define" -> defines.add(new Define(
+                        elm.getAttribute("name"),
+                        elm.getAttribute("value")
+                ));
+                case "dependencies" -> Arrays.stream(Util.getContent(elm).split(","))
+                        .map(String::trim)
+                        .filter(not(String::isBlank))
+                        .map(Util::shId)
+                        .forEach(dependencies::add);
+                case "alldependencies" -> this.allDependencies = true;
+                case "option" -> options.add(new Option(elm));
             }
-        }
-
-        if (isNullOrBlank(target.prefix) && isNotNullOrBlank(target.name)) {
-            target.setPrefix(name.toUpperCase());
-        }
-
-        return target;
+        });
     }
 
     public String getName() {
         return name;
     }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
     public String getPrefix() {
         return prefix;
     }
 
-    public void setPrefix(String prefix) {
-        this.prefix = prefix;
-    }
-
     private String withPrefix(String id) {
-        return prefix == null ? id : String.format("%s_%s", prefix, id);
+        return prefix.isEmpty() ? id : String.format("%s_%s", prefix, id);
     }
 
     public String getCFlags() {
@@ -97,50 +80,27 @@
         return withPrefix("CXXFLAGS");
     }
 
-    public void clearDependencies() {
-        dependencies.clear();
-    }
-
     public List<String> getDependencies() {
         return dependencies;
     }
 
-    public void addDependency(String dependency) {
-        // we have to add the sanitized identifier to the list of dependencies
-        dependencies.add(shId(dependency));
-    }
-
-    public boolean isAllDependencies() {
-        return allDependencies;
+    public void replaceAllDependencies(Collection<String> deps) {
+        dependencies.clear();
+        dependencies.addAll(deps);
     }
 
-    public void setAllDependencies(boolean allDependencies) {
-        this.allDependencies = allDependencies;
-    }
-
-    public void addDefine(String name, String value) {
-        if (name.isBlank()) {
-            throw new IllegalArgumentException("define element requires name attribute");
-        }
-        defines.add(new Define(name, value));
+    public boolean wantsAllDependencies() {
+        return allDependencies;
     }
 
     public List<Define> getDefines() {
         return defines;
     }
 
-    public void addFeature(Feature f) {
-        features.add(f);
-    }
-
     public List<Feature> getFeatures() {
         return features;
     }
 
-    public void addOption(Option o) {
-        options.add(o);
-    }
-
     public List<Option> getOptions() {
         return options;
     }
--- a/src/main/java/de/unixwork/uwproj/TargetData.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/TargetData.java	Sun Jan 28 14:02:41 2024 +0100
@@ -1,47 +1,33 @@
 package de.unixwork.uwproj;
 
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
 
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
 
-import static de.unixwork.uwproj.Util.shId;
 import static java.util.function.Predicate.not;
 
 public class TargetData {
     private final List<Define> defines = new LinkedList<>();
     private final List<String> dependencies = new LinkedList<>();
-    private final StringBuilder make = new StringBuilder();
-
-    public static TargetData parse(Element element) {
-        var target = new TargetData();
+    private final List<String> make = new LinkedList<>();
 
-        NodeList nodes = element.getChildNodes();
-        for (int i = 0; i < nodes.getLength(); i++) {
-            Node node = nodes.item(i);
-            if (node.getNodeType() == Node.ELEMENT_NODE) {
-                Element elm = (Element) node;
-                String n = elm.getNodeName();
-                if (n.equals("define")) {
-                    target.addDefine(
-                            elm.getAttribute("name"),
-                            elm.getAttribute("value")
-                    );
-                } else if (n.equals("dependencies")) {
-                    Arrays.stream(Util.getContent(elm).split(","))
-                            .map(String::trim)
-                            .filter(not(String::isBlank))
-                            .forEach(target::addDependency);
-                } else if (n.equals("make")) {
-                    target.addMake(Util.getContent(elm));
-                }
+    public TargetData(Element element) {
+        Util.getChildElements(element).forEach(elm -> {
+            switch (elm.getNodeName()) {
+                case "define" -> defines.add(new Define(
+                        elm.getAttribute("name"),
+                        elm.getAttribute("value")
+                ));
+                case "dependencies" -> Arrays.stream(Util.getContent(elm).split(","))
+                        .map(String::trim)
+                        .filter(not(String::isBlank))
+                        .map(Util::shId)
+                        .forEach(dependencies::add);
+                case "make" -> make.add(Util.getContent(elm));
             }
-        }
-
-        return target;
+        });
     }
 
     public List<Define> getDefines() {
@@ -53,23 +39,10 @@
     }
 
     public String getMake() {
-        return make.toString();
-    }
-
-    public void addDefine(String name, String value) {
-        if (name.isBlank()) {
-            throw new IllegalArgumentException("define element requires name attribute");
-        }
-        defines.add(new Define(name, value));
+        return String.join("\n", make);
     }
 
-    public void addDependency(String d) {
-        // we have to add the sanitized identifier to the list of dependencies
-        dependencies.add(shId(d));
-    }
-
-    public void addMake(String m) {
-        make.append(m.trim());
-        make.append('\n');
+    public boolean hasMake() {
+        return !make.isEmpty();
     }
 }
--- a/src/main/java/de/unixwork/uwproj/Util.java	Sun Jan 28 13:26:47 2024 +0100
+++ b/src/main/java/de/unixwork/uwproj/Util.java	Sun Jan 28 14:02:41 2024 +0100
@@ -4,9 +4,37 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
 public class Util {
 
     /**
+     * Returns a stream of all children for the specified XML node.
+     * @param node the node
+     * @return a stream of child elements of node
+     */
+    public static Stream<Element> getChildElements(Node node) {
+        final var children = node.getChildNodes();
+        return IntStream.range(0, children.getLength())
+                .mapToObj(children::item)
+                .filter(n -> n.getNodeType() == Node.ELEMENT_NODE)
+                .map(n -> (Element)n);
+    }
+
+    /**
+     * Returns the value of an attribute, or a default if the attribute is not set.
+     * @param elm the element
+     * @param attr the attribute name
+     * @param def the default value when the attribute is empty
+     * @return the attribute value or the default
+     */
+    public static String getAttrOrDefault(Element elm, String attr, String def) {
+        final var v = elm.getAttribute(attr);
+        return v.isBlank() ? def : v;
+    }
+
+    /**
      * Returns the text content of the given element with indentation automatically trimmed.
      *
      * @param elm the element
@@ -41,14 +69,6 @@
         return "";
     }
 
-    public static boolean isNullOrBlank(String s) {
-        return s == null || s.isBlank();
-    }
-
-    public static boolean isNotNullOrBlank(String s) {
-        return s != null && !s.isBlank();
-    }
-
     /**
      * Creates an identifier from the given string that can be used as an identifier in a POSIX shell script.
      * <p>
--- a/test/configure2	Sun Jan 28 13:26:47 2024 +0100
+++ b/test/configure2	Sun Jan 28 14:02:41 2024 +0100
@@ -501,7 +501,6 @@
         cat >> $TEMP_DIR/make.mk << __EOF__
 # Dependency: libxml2
 xml = libxml2
-
 __EOF__
         print_check_msg "$dep_checked_libxml2" "yes\n"
         dep_checked_libxml2=1
@@ -534,7 +533,6 @@
         cat >> "$TEMP_DIR/make.mk" << __EOF__
 MVAR = 123
 MVAR += 123
-
 __EOF__
         break
     done
@@ -569,7 +567,6 @@
         TEMP_CXXFLAGS="$TEMP_CXXFLAGS -Da=b"
     cat >> "$TEMP_DIR/make.mk" << __EOF__
 UIOBJ += graphics_cairo.o
-
 __EOF__
     return 0
 }

mercurial