commit: 813018bb1e76ab055fdfb492f847446bf09600d5 Author: Andrei Horodniceanu <a.horodniceanu <AT> proton <DOT> me> AuthorDate: Fri Mar 28 07:21:03 2025 +0000 Commit: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> CommitDate: Sun Mar 30 16:21:56 2025 +0000 URL: https://gitweb.gentoo.org/proj/javatoolkit.git/commit/?id=813018bb
cvv.py: Don't fail when MANIFEST.MF isn't utf-8 encoded Use the UTF-8 replacement character rather then raising and exception when encountering invalid unicode in MANIFEST.MF, which is against the standard yet some programs like the maven-jar-plugin embed the author's name literally without properly encoding it first. Closes: https://bugs.gentoo.org/952052 Signed-off-by: Andrei Horodniceanu <a.horodniceanu <AT> proton.me> Closes: https://github.com/gentoo/javatoolkit/pull/4 Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org> NEWS | 3 + src/javatoolkit/cvv.py | 7 +- src/test/res/maven-generated-manifest.mf | 169 +++++++++++++++++++++++++++++++ src/test/test_cvv.py | 24 +++++ 4 files changed, 202 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 983670a..bef013a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +0.6.9 (??) +- Prevent failure when MANIFEST.MF isn't UTF-8 encoded (bug #952052) + 0.6.8 (08 Mar 2025) - Change output format - Add tests diff --git a/src/javatoolkit/cvv.py b/src/javatoolkit/cvv.py index 0ca8023..cba3d0f 100644 --- a/src/javatoolkit/cvv.py +++ b/src/javatoolkit/cvv.py @@ -100,7 +100,12 @@ class CVVMagic: pass else: with manifest: - lines = [line.decode('utf-8').rstrip() for line in manifest.readlines()] + def decode_line(line: bytes) -> str: + # The Manifest spec requires that the file is utf-8 encoded. + # Unfortunately, stuff like the maven-jar-plugin can generate + # an invalid manifest when it blindly copies the author name + return line.decode('utf-8', 'replace').rstrip('\r\n') + lines = [decode_line(line) for line in manifest.readlines()] is_multirelease = 'Multi-Release: true' in lines invalid_version_dirs: set[str] = set() diff --git a/src/test/res/maven-generated-manifest.mf b/src/test/res/maven-generated-manifest.mf new file mode 100644 index 0000000..09bd061 --- /dev/null +++ b/src/test/res/maven-generated-manifest.mf @@ -0,0 +1,169 @@ +Manifest-Version: 1.0 +Created-By: Maven JAR Plugin 3.4.0 +Multi-Release: true +Build-Jdk-Spec: 21 +Specification-Title: Maven Artifact Resolver API +Specification-Version: 1.9 +Specification-Vendor: The Apache Software Foundation +Implementation-Title: Maven Artifact Resolver API +Implementation-Version: 1.9.22 +Implementation-Vendor: The Apache Software Foundation +Automatic-Module-Name: org.apache.maven.resolver +Bundle-Description: The application programming interface for the reposi + tory system. +Bundle-Developers: khmarbaise;email="[email protected]";name="Karl H + einz Marbaise";roles="PMC Chair";timezone="+1",aheritier;email="aheriti + [email protected]";name="Arnaud Héritier";roles="PMC Member";timezone="+1" + ,andham;email="[email protected]";name="Anders Hammar";roles="PMC Membe + r";timezone="+1",baerrach;email="[email protected]";name="Barrie Trel + oar";roles="PMC Member";timezone="Australia/Adelaide",bimargulies;email + ="[email protected]";name="Benson Margulies";roles="PMC Member";ti + mezone="America/New_York",bmarwell;email="[email protected]";name="Be + njamin Marwell";organization=ASF;roles="PMC Member";timezone="Europe/Be + rlin",brianf;email="[email protected]";name="Brian Fox";organization=So + natype;roles="PMC Member";timezone=-5,cstamas;email="[email protected] + ";name="Tamas Cservenak";roles="PMC Member";timezone="+1",dennisl;email + ="[email protected]";name="Dennis Lundberg";organization=ASF;roles="PM + C Member";timezone="+1",dkulp;email="[email protected]";name="Daniel Kul + p";organization=ASF;roles="PMC Member";timezone=-5,evenisse;email="even + [email protected]";name="Emmanuel Venisse";organization=ASF;roles="PMC Me + mber";timezone="+1",gboue;email="[email protected]";name="Guillaume Bou� + �";roles="PMC Member";timezone="Europe/Paris",gnodet;email="gnodet@apac + he.org";name="Guillaume Nodet";organization="Red Hat";roles="PMC Member + ";timezone="Europe/Paris",henning;email="[email protected]";name="Henn + ing Schmiedehausen";organization=ASF;roles="PMC Member";timezone="Ameri + ca/Los_Angeles",hboutemy;email="[email protected]";name="Hervé Boute + my";organization=ASF;roles="PMC Member";timezone="Europe/Paris",ifedore + nko;email="[email protected]";name="Igor Fedorenko";organization=Sona + type;roles="PMC Member";timezone=-5,jvanzyl;email="[email protected]";nam + e="Jason van Zyl";roles="PMC Member";timezone=-5,krosenvold;email="kros + [email protected]";name="Kristian Rosenvold";roles="PMC Member";timezon + e="+1",kwin;email="[email protected]";name="Konrad Windszus";organization + ="Cognizant Netcentric";roles="PMC Member";timezone="Europe/Berlin",mkl + eint;name="Milos Kleint";roles="PMC Member",mthmulders;email="mthmulder + [email protected]";name="Maarten Mulders";organization="Info Support";roles= + "PMC Member";timezone="Europe/Amsterdam",olamy;email="[email protected]" + ;name="Olivier Lamy";roles="PMC Member";timezone="Australia/Brisbane",m + ichaelo;email="[email protected]";name="Michael Osipov";roles="PMC Me + mber";timezone="Europe/Berlin",rfscholte;email="[email protected]";n + ame="Robert Scholte";roles="PMC Member";timezone="Europe/Amsterdam",rgo + ers;email="[email protected]";name="Ralph Goers";organization=Intuit;ro + les="PMC Member";timezone=-8,sjaranowski;email="[email protected]" + ;name="Slawomir Jaranowski";roles="PMC Member";timezone="Europe/Warsaw" + ,stephenc;email="[email protected]";name="Stephen Connolly";roles="PM + C Member";timezone=0,slachiewicz;email="[email protected]";name="S + ylwester Lachiewicz";roles="PMC Member";timezone="Europe/Warsaw",strube + rg;email="[email protected]";name="Mark Struberg";roles="PMC Member", + tibordigana;email="[email protected]";name="Tibor Digaňa";roles=" + PMC Member";timezone="Europe/Bratislava",vsiveton;email="vsiveton@apach + e.org";name="Vincent Siveton";organization=ASF;roles="PMC Member";timez + one=-5,wfay;email="[email protected]";name="Wayne Fay";organization=ASF;r + oles="PMC Member";timezone=-6,adangel;email="[email protected]";name=" + Andreas Dangel";roles=Committer;timezone="Europe/Berlin",bdemers;email= + "[email protected]";name="Brian Demers";organization=Sonatype;roles=Co + mmitter;timezone=-5,bellingard;name="Fabrice Bellingard";roles=Committe + r,bentmann;email="[email protected]";name="Benjamin Bentmann";organiz + ation=Sonatype;roles=Committer;timezone="+1",chrisgwarp;email="chrisgwa + [email protected]";name="Chris Graham";roles=Committer;timezone="Australia/ + Melbourne",dantran;email="[email protected]";name="Dan Tran";roles=Com + mitter;timezone=-8,dbradicich;email="[email protected]";name="Damia + n Bradicich";organization=Sonatype;roles=Committer;timezone=-5,brett;em + ail="[email protected]";name="Brett Porter";organization=ASF;roles=Commi + tter;timezone="+10",dfabulich;email="[email protected]";name="Daniel + Fabulich";roles=Committer;timezone=-8,eolivelli;email="eolivelli@apach + e.org";name="Enrico Olivelli";organization=Diennea;roles=Committer;time + zone="Europe/Rome",fgiust;email="[email protected]";name="Fabrizio Gius + tina";organization=openmind;roles=Committer;timezone="+1",godin;email=" + [email protected]";name="Evgeny Mandrikov";organization=SonarSource;role + s=Committer;timezone="+3",handyande;email="[email protected]";name=" + Andrew Williams";roles=Committer;timezone=0,imod;email="[email protected] + ";name="Dominik Bartholdi";roles=Committer;timezone="Europe/Zurich",jje + nsen;name="Jeff Jensen";roles=Committer,ltheussl;email="ltheussl@apache + .org";name="Lukas Theussl";roles=Committer;timezone="+1",markh;email="m + [email protected]";name="Mark Hobson";roles=Committer;timezone=0,martinka + nters;email="[email protected]";name="Martin Kanters";organizati + on=JPoint;roles=Committer;timezone="Europe/Amsterdam",mauro;name="Mauro + Talevi";roles=Committer,mfriedenhagen;email="[email protected]" + ;name="Mirko Friedenhagen";roles=Committer;timezone="+1",mmoser;email=" + [email protected]";name="Manfred Moser";roles=Committer;timezone=-8,nic + olas;name="Nicolas de Loof";roles=Committer,oching;name="Maria Odea B. + Ching";roles=Committer,pgier;email="[email protected]";name="Paul Gier"; + organization="Red Hat";roles=Committer;timezone=-6,ptahchiev;email="pta + [email protected]";name="Petar Tahchiev";roles=Committer;timezone="+2", + rafale;email="[email protected]";name="Raphaël Piéroni";organization= + Dexem;roles=Committer;timezone="+1",schulte;email="[email protected]"; + name="Christian Schulte";roles=Committer;timezone="Europe/Berlin",snico + ll;email="[email protected]";name="Stephane Nicoll";roles=Committer;ti + mezone="+1",simonetripodi;email="[email protected]";name="Simone + Tripodi";roles=Committer;timezone="+1",sor;email="[email protected]";name + ="Christian Stein";roles=Committer;timezone="Europe/Berlin",tchemit;ema + il="[email protected]";name="Tony Chemit";organization=CodeLutin;roles + =Committer;timezone="Europe/Paris",vmassol;email="[email protected]";n + ame="Vincent Massol";organization=ASF;roles=Committer;timezone="+1",elh + aro;email="[email protected]";name="Elliotte Rusty Harold";roles=Commit + ter;timezone="America/New_York",agudian;email="[email protected]";name + ="Andreas Gudian";roles=Emeritus;timezone="Europe/Berlin",aramirez;name + ="Allan Q. Ramirez";roles=Emeritus,bayard;name="Henri Yandell";roles=Em + eritus,carlos;email="[email protected]";name="Carlos Sanchez";organizat + ion=ASF;roles=Emeritus;timezone="+1",chrisjs;name="Chris Stevenson";rol + es=Emeritus,dblevins;name="David Blevins";roles=Emeritus,dlr;name="Dani + el Rall";roles=Emeritus,epunzalan;email="[email protected]";name="Ed + win Punzalan";roles=Emeritus;timezone=-8,felipeal;name="Felipe Leme";ro + les=Emeritus,jdcasey;email="[email protected]";name="John Casey";organ + ization=ASF;roles=Emeritus;timezone=-6,jmcconnell;email="jmcconnell@apa + che.org";name="Jesse McConnell";organization=ASF;roles=Emeritus;timezon + e=-6,joakime;email="[email protected]";name="Joakim Erdfelt";organizat + ion=ASF;roles=Emeritus;timezone=-5,jruiz;email="[email protected]";name= + "Johnny Ruiz III";roles=Emeritus,jstrachan;name="James Strachan";roles= + Emeritus,jtolentino;email="[email protected]";name="Ernesto Tolenti + no Jr.";organization=ASF;roles=Emeritus;timezone="+8",kenney;email="ken + [email protected]";name="Kenney Westerhof";organization=Neonics;roles=Emer + itus;timezone="+1",mperham;email="[email protected]";name="Mike Perham" + ;organization=IBM;roles=Emeritus;timezone=-6,ogusakov;name="Oleg Gusako + v";roles=Emeritus,pschneider;email="[email protected]";name="Patrick + Schneider";roles=Emeritus;timezone=-6,rinku;name="Rahul Thakur";roles= + Emeritus,shinobu;name="Shinobu Kuwai";roles=Emeritus,smorgrav;name="Tor + bjorn Eikli Smorgrav";roles=Emeritus,trygvis;email="[email protected]" + ;name="Trygve Laugstol";organization=ASF;roles=Emeritus;timezone="+1",w + smoak;email="[email protected]";name="Wendy Smoak";roles=Emeritus;timez + one=-7 +Bundle-DocURL: https://maven.apache.org/resolver/maven-resolver-api/ +Bundle-License: "Apache-2.0";link="https://www.apache.org/licenses/LICEN + SE-2.0.txt" +Bundle-ManifestVersion: 2 +Bundle-Name: Maven Artifact Resolver API +Bundle-SCM: url="https://github.com/apache/maven-resolver/tree/maven-res + olver-1.9.22/maven-resolver-api",connection="scm:git:https://gitbox.apa + che.org/repos/asf/maven-resolver.git/maven-resolver-api",developer-conn + ection="scm:git:https://gitbox.apache.org/repos/asf/maven-resolver.git/ + maven-resolver-api",tag="maven-resolver-1.9.22" +Bundle-SymbolicName: org.apache.maven.resolver.api +Bundle-Vendor: The Apache Software Foundation +Bundle-Version: 1.9.22 +Export-Package: org.eclipse.aether;uses:="org.eclipse.aether.artifact,or + g.eclipse.aether.collection,org.eclipse.aether.deployment,org.eclipse.a + ether.installation,org.eclipse.aether.metadata,org.eclipse.aether.repos + itory,org.eclipse.aether.resolution,org.eclipse.aether.transfer,org.ecl + ipse.aether.transform";version="1.9.22",org.eclipse.aether.artifact;ver + sion="1.9.22",org.eclipse.aether.collection;uses:="org.eclipse.aether,o + rg.eclipse.aether.artifact,org.eclipse.aether.graph,org.eclipse.aether. + repository,org.eclipse.aether.version";version="1.9.22",org.eclipse.aet + her.deployment;uses:="org.eclipse.aether,org.eclipse.aether.artifact,or + g.eclipse.aether.metadata,org.eclipse.aether.repository";version="1.9.2 + 2",org.eclipse.aether.graph;uses:="org.eclipse.aether.artifact,org.ecli + pse.aether.repository,org.eclipse.aether.version";version="1.9.22",org. + eclipse.aether.installation;uses:="org.eclipse.aether,org.eclipse.aethe + r.artifact,org.eclipse.aether.metadata";version="1.9.22",org.eclipse.ae + ther.metadata;uses:="org.eclipse.aether";version="1.9.22",org.eclipse.a + ether.repository;uses:="org.eclipse.aether,org.eclipse.aether.artifact, + org.eclipse.aether.metadata";version="1.9.22",org.eclipse.aether.resolu + tion;uses:="org.eclipse.aether,org.eclipse.aether.artifact,org.eclipse. + aether.collection,org.eclipse.aether.graph,org.eclipse.aether.metadata, + org.eclipse.aether.repository,org.eclipse.aether.version";version="1.9. + 22",org.eclipse.aether.transfer;uses:="org.eclipse.aether,org.eclipse.a + ether.artifact,org.eclipse.aether.metadata,org.eclipse.aether.repositor + y";version="1.9.22",org.eclipse.aether.transform;uses:="org.eclipse.aet + her.artifact";version="1.9.22",org.eclipse.aether.version;uses:="org.ec + lipse.aether";version="1.9.22" +Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" + diff --git a/src/test/test_cvv.py b/src/test/test_cvv.py index e872161..8c0e4e9 100644 --- a/src/test/test_cvv.py +++ b/src/test/test_cvv.py @@ -4,6 +4,7 @@ import javatoolkit.cvv as cvv from zipfile import ZipFile import struct import typing as T +import os def create_class_header(version: int) -> bytes: @@ -211,3 +212,26 @@ class SimpleTest(TestCase): ]) self.assertListEqual(m.bad, []) self.assertListEqual(m.skipped, []) + + def test_maven_generated_manifest(self): + m = cvv.CVVMagic('10') + jar_path = cvv.FileLoc('a.jar') + + jar = ZipFile(io.BytesIO(), 'w') + jar.writestr('A.class', create_class_header(10)) + jar.writestr('META-INF/versions/12/A.class', create_class_header(12)) + this_dir = os.path.dirname(os.path.realpath(__file__)) + with open(f'{this_dir}/res/maven-generated-manifest.mf', 'rb') as f: + jar.writestr('META-INF/MANIFEST.MF', f.read()) + + m.do_jar(jar, jar_path) + + def jar_member(member: str) -> cvv.JarLoc: + return cvv.JarLoc(jar_path, member) + + self.assertListEqual(m.good, [ + cvv.GoodFile(jar_member('A.class'), '10', '10'), + cvv.GoodFile(jar_member('META-INF/versions/12/A.class'), '12', '12'), + ]) + self.assertListEqual(m.bad, []) + self.assertListEqual(m.skipped, [])
