Fixed problem with multiple class-path attributes. Hopefully Sun will update their spec sometime. PR: 4683 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269921 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -24,6 +24,82 @@ | |||
| <jar file="mftest5.jar" manifest="manifests/test5.mf"/> | |||
| </target> | |||
| <target name="test6"> | |||
| <jar file="mftest6.jar" manifest="manifests/test6.mf"/> | |||
| </target> | |||
| <target name="test7"> | |||
| <jar file="mftest7.jar" manifest="manifests/test7.mf"/> | |||
| </target> | |||
| <target name="test8"> | |||
| <jar file="mftest8.jar"> | |||
| <manifest> | |||
| <attribute name="Class-Path" value="fubar"/> | |||
| <section name="Test"> | |||
| <attribute name="TestAttr" value="Test"/> | |||
| </section> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test9"> | |||
| <jar file="mftest9.jar"> | |||
| <manifest> | |||
| <attribute name="Class-Path" value="fubar"/> | |||
| <section name="Test"> | |||
| <attribute name="Name" value="Test"/> | |||
| </section> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test10"> | |||
| <jar file="mftest10.jar"> | |||
| <manifest> | |||
| <attribute value="fubar"/> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test11"> | |||
| <jar file="mftest11.jar"> | |||
| <manifest> | |||
| <attribute name="Test"/> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test12"> | |||
| <jar file="mftest12.jar"> | |||
| <manifest> | |||
| <section> | |||
| <attribute name="TestAttr" value="Test"/> | |||
| </section> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test13"> | |||
| <jar file="mftest13.jar"> | |||
| <manifest> | |||
| <attribute name="Test" value="Test1"/> | |||
| <attribute name="Test" value="Test2"/> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="test14"> | |||
| <jar file="mftest14.jar"> | |||
| <manifest> | |||
| <attribute name="Class-path" value="Test1"/> | |||
| <attribute name="Class-path" value="Test2"/> | |||
| <attribute name="Class-Path" value="Test3"/> | |||
| <attribute name="class-Path" value="Test4"/> | |||
| </manifest> | |||
| </jar> | |||
| </target> | |||
| <target name="clean"> | |||
| <delete> | |||
| <fileset dir="." includes="mftest*.jar"/> | |||
| @@ -0,0 +1,5 @@ | |||
| Manifest-Version: 1.0 | |||
| Test: test6 | |||
| Class-Path: fubar | |||
| @@ -0,0 +1,4 @@ | |||
| Manifest-Version: 1.0 | |||
| Class-Path: fubar | |||
| From: Jack | |||
| @@ -81,9 +81,12 @@ public class Manifest { | |||
| /** The Name Attribute is the first in a named section */ | |||
| public final static String ATTRIBUTE_NAME = "Name"; | |||
| /** THe From Header is disallowed in a Manifest */ | |||
| /** The From Header is disallowed in a Manifest */ | |||
| public final static String ATTRIBUTE_FROM = "From"; | |||
| /** The Class-Path Header is special - it can be duplicated */ | |||
| public final static String ATTRIBUTE_CLASSPATH = "class-path"; | |||
| /** Default Manifest version if one is not specified */ | |||
| public final static String DEFAULT_MANIFEST_VERSION = "1.0"; | |||
| @@ -321,8 +324,19 @@ public class Manifest { | |||
| for (Enumeration e = section.attributes.keys(); e.hasMoreElements();) { | |||
| String attributeName = (String)e.nextElement(); | |||
| // the merge file always wins | |||
| attributes.put(attributeName, section.attributes.get(attributeName)); | |||
| if (attributeName.equals(ATTRIBUTE_CLASSPATH) && | |||
| attributes.containsKey(attributeName)) { | |||
| // classpath entries are vetors which are merged | |||
| Vector classpathAttrs = (Vector)section.attributes.get(attributeName); | |||
| Vector ourClasspathAttrs = (Vector)attributes.get(attributeName); | |||
| for (Enumeration e2 = classpathAttrs.elements(); e2.hasMoreElements();) { | |||
| ourClasspathAttrs.addElement(e2.nextElement()); | |||
| } | |||
| } | |||
| else { | |||
| // the merge file always wins | |||
| attributes.put(attributeName, section.attributes.get(attributeName)); | |||
| } | |||
| } | |||
| // add in the warnings | |||
| @@ -344,8 +358,18 @@ public class Manifest { | |||
| nameAttr.write(writer); | |||
| } | |||
| for (Enumeration e = attributes.elements(); e.hasMoreElements();) { | |||
| Attribute attribute = (Attribute)e.nextElement(); | |||
| attribute.write(writer); | |||
| Object object = e.nextElement(); | |||
| if (object instanceof Attribute) { | |||
| Attribute attribute = (Attribute)object; | |||
| attribute.write(writer); | |||
| } | |||
| else { | |||
| Vector attrList = (Vector)object; | |||
| for (Enumeration e2 = attrList.elements(); e2.hasMoreElements();) { | |||
| Attribute attribute = (Attribute)e2.nextElement(); | |||
| attribute.write(writer); | |||
| } | |||
| } | |||
| } | |||
| writer.println(); | |||
| } | |||
| @@ -359,11 +383,21 @@ public class Manifest { | |||
| * in the section | |||
| */ | |||
| public String getAttributeValue(String attributeName) { | |||
| Attribute attribute = (Attribute)attributes.get(attributeName.toLowerCase()); | |||
| Object attribute = attributes.get(attributeName.toLowerCase()); | |||
| if (attribute == null) { | |||
| return null; | |||
| } | |||
| return attribute.getValue(); | |||
| if (attribute instanceof Attribute) { | |||
| return ((Attribute)attribute).getValue(); | |||
| } | |||
| else { | |||
| String value = ""; | |||
| for (Enumeration e = ((Vector)attribute).elements(); e.hasMoreElements();) { | |||
| Attribute classpathAttribute = (Attribute)e.nextElement(); | |||
| value += classpathAttribute.getValue() + " "; | |||
| } | |||
| return value.trim(); | |||
| } | |||
| } | |||
| /** | |||
| @@ -407,12 +441,24 @@ public class Manifest { | |||
| warnings.addElement("Manifest attributes should not start with \"" + | |||
| ATTRIBUTE_FROM + "\" in \"" +attribute.getName() + ": " + attribute.getValue() + "\""); | |||
| } | |||
| else if (attributes.containsKey(attribute.getName().toLowerCase())) { | |||
| throw new ManifestException("The attribute \"" + attribute.getName() + "\" may not " + | |||
| "occur more than once in the same section"); | |||
| } | |||
| else { | |||
| attributes.put(attribute.getName().toLowerCase(), attribute); | |||
| // classpath attributes go into a vector | |||
| String attributeName = attribute.getName().toLowerCase(); | |||
| if (attributeName.equals(ATTRIBUTE_CLASSPATH)) { | |||
| Vector classpathAttrs = (Vector)attributes.get(attributeName); | |||
| if (classpathAttrs == null) { | |||
| classpathAttrs = new Vector(); | |||
| attributes.put(attributeName, classpathAttrs); | |||
| } | |||
| classpathAttrs.addElement(attribute); | |||
| } | |||
| else if (attributes.containsKey(attributeName)) { | |||
| throw new ManifestException("The attribute \"" + attribute.getName() + "\" may not " + | |||
| "occur more than once in the same section"); | |||
| } | |||
| else { | |||
| attributes.put(attributeName, attribute); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| @@ -213,7 +213,7 @@ public abstract class BuildFileTest extends TestCase { | |||
| executeTarget(target); | |||
| } catch (org.apache.tools.ant.BuildException ex) { | |||
| if ((null != contains) && (ex.getMessage().indexOf(contains) == -1)) { | |||
| fail("Should throw BuildException because '" + cause + "' with message containing'" + contains + "' (actual message '" + ex.getMessage() + "' instead)"); | |||
| fail("Should throw BuildException because '" + cause + "' with message containing '" + contains + "' (actual message '" + ex.getMessage() + "' instead)"); | |||
| } | |||
| return; | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 2000 The Apache Software Foundation. All rights | |||
| * Copyright (c) 2001 The Apache Software Foundation. All rights | |||
| * reserved. | |||
| * | |||
| * Redistribution and use in source and binary forms, with or without | |||
| @@ -105,7 +105,7 @@ public class ManifestTest extends BuildFileTest { | |||
| public void test4() { | |||
| expectBuildExceptionContaining("test4", "Manifest is invalid - section starts with continuation line", | |||
| "Invalid Manifest"); | |||
| } | |||
| } | |||
| /** | |||
| * Malformed manifest - Name attribute in main section | |||
| @@ -116,4 +116,81 @@ public class ManifestTest extends BuildFileTest { | |||
| boolean hasWarning = output.indexOf("Manifest warning: \"Name\" attributes should not occur in the main section") != -1; | |||
| assertEquals("Expected warning about Name in main section", true, hasWarning); | |||
| } | |||
| /** | |||
| * New Section not starting with Name attribute. | |||
| */ | |||
| public void test6() { | |||
| expectBuildExceptionContaining("test6", "Manifest is invalid - section starts with incorrect attribute", | |||
| "Invalid Manifest"); | |||
| String output = getLog(); | |||
| boolean hasWarning = output.indexOf("Manifest sections should start with a \"Name\" attribute") != -1; | |||
| assertEquals("Expected warning about section not starting with Name: attribute", true, hasWarning); | |||
| } | |||
| /** | |||
| * From attribute is illegal | |||
| */ | |||
| public void test7() { | |||
| executeTarget("test7"); | |||
| boolean hasWarning = getLog().indexOf("Manifest attributes should not start with \"From\"") != -1; | |||
| assertEquals("Expected warning about From: attribute", true, hasWarning); | |||
| } | |||
| /** | |||
| * Inline manifest - OK | |||
| */ | |||
| public void test8() { | |||
| executeTarget("test8"); | |||
| } | |||
| /** | |||
| * Inline manifest - Invalid since has a Name attribute in the section element | |||
| */ | |||
| public void test9() { | |||
| expectBuildExceptionContaining("test9", "Construction is invalid - Name attribute should not be used", | |||
| "Specify the section name using the \"name\" attribute of the <section> element"); | |||
| } | |||
| /** | |||
| * Inline manifest - Invalid attribute without name | |||
| */ | |||
| public void test10() { | |||
| expectBuildExceptionContaining("test10", "Attribute has no name", | |||
| "Attributes must have name and value"); | |||
| } | |||
| /** | |||
| * Inline manifest - Invalid attribute without value | |||
| */ | |||
| public void test11() { | |||
| expectBuildExceptionContaining("test11", "Attribute has no value", | |||
| "Attributes must have name and value"); | |||
| } | |||
| /** | |||
| * Inline manifest - Invalid attribute without value | |||
| */ | |||
| public void test12() { | |||
| expectBuildExceptionContaining("test12", "Section with no name", | |||
| "Sections must have a name"); | |||
| } | |||
| /** | |||
| * Inline manifest - Duplicate attribute | |||
| */ | |||
| public void test13() { | |||
| expectBuildExceptionContaining("test13", "Duplicate Attribute", | |||
| "The attribute \"Test\" may not occur more than once in the same section"); | |||
| } | |||
| /** | |||
| * Inline manifest - OK since classpath entries can be duplicated. | |||
| */ | |||
| public void test14() { | |||
| executeTarget("test14"); | |||
| } | |||
| } | |||