[Git][reproducible-builds/diffoscope][master] Add NuGet package support

Chris Lamb (@lamby) gitlab at salsa.debian.org
Mon May 12 23:27:30 UTC 2025



Chris Lamb pushed to branch master at Reproducible Builds / diffoscope


Commits:
09abd4cd by Omair Majid at 2025-05-12T22:47:32+00:00
Add NuGet package support

NuGet packages (commonly with file extension .nupkg) are used by .NET to
transport libraries, similar to jar files. NuGet packages are
essentially zip files with some expected contents. A mininial library
looks like this:

	$ unzip -l ClassLibrary.0.0.1.nupkg
	Archive:  ClassLibrary.0.0.1.nupkg
	  Length      Date    Time    Name
	---------  ---------- -----   ----
	      502  04-14-2025 18:14   _rels/.rels
	      407  04-14-2025 18:14   ClassLibrary.nuspec
	     3584  04-14-2025 22:14   lib/net8.0/ClassLibrary.dll
	      459  04-14-2025 18:14   [Content_Types].xml
	      625  04-14-2025 18:14   package/services/metadata/core-properties/b44ebb537bbf4983b9527f9e3820fda6.psmdcp
	---------                     -------

Some of these content are similar to the contents of a Microsoft OOXML
file, and `file` utility doesn't recognize this correctly. Eee
https://bugs.astron.com/view.php?id=644

Support NuGet packages in diffoscope will make it easier to verify the
.NET SDK and .NET libraries. It will also contribute towards making the
.NET SDK itself reproducible (see
https://github.com/dotnet/source-build/issues/4963).

- - - - -


6 changed files:

- diffoscope/comparators/__init__.py
- diffoscope/comparators/zip.py
- tests/comparators/test_zip.py
- + tests/data/nupkg_expected_diff
- + tests/data/test1.nupkg
- + tests/data/test2.nupkg


Changes:

=====================================
diffoscope/comparators/__init__.py
=====================================
@@ -98,6 +98,7 @@ class ComparatorManager:
         ("ocaml.OcamlInterfaceFile",),
         ("docx.DocxFile",),
         ("zip.MozillaZipFile",),
+        ("zip.NuGetPackageFile",),
         ("zip.JmodJavaModule",),
         ("zip.ZipFile",),
         ("image.JPEGImageFile",),


=====================================
diffoscope/comparators/zip.py
=====================================
@@ -342,6 +342,13 @@ class MozillaZipFile(ZipFile):
         return file.file_header[4:8] == b"PK\x01\x02"
 
 
+class NuGetPackageFile(ZipFile):
+    DESCRIPTION = "NuGet packages"
+    CONTAINER_CLASSES = [ZipContainer]
+    FILE_TYPE_HEADER_PREFIX = b"PK\x03\x04"
+    FILE_EXTENSION_SUFFIX = {".nupkg"}
+
+
 class JmodJavaModule(ZipFile):
     DESCRIPTION = "Java .jmod modules"
     FILE_TYPE_RE = re.compile(r"^(Zip archive data|Java jmod module)")


=====================================
tests/comparators/test_zip.py
=====================================
@@ -20,7 +20,12 @@
 import pytest
 import subprocess
 
-from diffoscope.comparators.zip import ZipFile, MozillaZipFile, JmodJavaModule
+from diffoscope.comparators.zip import (
+    ZipFile,
+    MozillaZipFile,
+    NuGetPackageFile,
+    JmodJavaModule,
+)
 
 from ..utils.data import load_fixture, assert_diff
 from ..utils.tools import skip_unless_tools_exist, skip_unless_tool_is_at_least
@@ -34,6 +39,8 @@ encrypted_zip1 = load_fixture("encrypted1.zip")
 encrypted_zip2 = load_fixture("encrypted2.zip")
 mozzip1 = load_fixture("test1.mozzip")
 mozzip2 = load_fixture("test2.mozzip")
+nupkg1 = load_fixture("test1.nupkg")
+nupkg2 = load_fixture("test2.nupkg")
 jmod1 = load_fixture("test1.jmod")
 jmod2 = load_fixture("test2.jmod")
 test_comment1 = load_fixture("test_comment1.zip")
@@ -135,6 +142,42 @@ def test_mozzip_compare_non_existing(monkeypatch, mozzip1):
     assert_non_existing(monkeypatch, mozzip1)
 
 
+def test_nupkg_identification(nupkg1):
+    assert isinstance(nupkg1, NuGetPackageFile)
+
+
+def test_nupkg_no_differences(nupkg1):
+    difference = nupkg1.compare(nupkg1)
+    assert difference is None
+
+
+ at pytest.fixture
+def nupkg_differences(nupkg1, nupkg2):
+    return nupkg1.compare(nupkg2).details
+
+
+ at skip_unless_tools_exist("zipinfo")
+def test_nupkg_metadata(nupkg_differences, nupkg1, nupkg2):
+    assert_diff(nupkg_differences[0], "nupkg_expected_diff")
+
+
+ at skip_unless_tools_exist("zipinfo")
+def test_nupkg_compressed_files(nupkg_differences):
+    assert (
+        nupkg_differences[-1].source1
+        == "package/services/metadata/core-properties/b44ebb537bbf4983b9527f9e3820fda6.psmdcp"
+    )
+    assert (
+        nupkg_differences[-1].source2
+        == "package/services/metadata/core-properties/08f1f9d8789a4668a128f78560bd0107.psmdcp"
+    )
+
+
+ at skip_unless_tools_exist("zipinfo")
+def test_nupkg_compare_non_existing(monkeypatch, nupkg1):
+    assert_non_existing(monkeypatch, nupkg1)
+
+
 def test_jmod_identification(jmod1):
     assert isinstance(jmod1, JmodJavaModule)
 


=====================================
tests/data/nupkg_expected_diff
=====================================
@@ -0,0 +1,11 @@
+@@ -1,7 +1,7 @@
+-Zip file size: 3163 bytes, number of entries: 5
++Zip file size: 3162 bytes, number of entries: 5
+ -rw-r--r--  2.0 unx      502 b- defN 25-Apr-14 18:14 _rels/.rels
+ -rw-r--r--  2.0 unx      407 b- defN 25-Apr-14 18:14 ClassLibrary.nuspec
+ -rw-r--r--  2.0 unx     3584 b- defN 25-Apr-14 22:14 lib/net8.0/ClassLibrary.dll
+ -rw-r--r--  2.0 unx      459 b- defN 25-Apr-14 18:14 [Content_Types].xml
+--rw-r--r--  2.0 unx      625 b- defN 25-Apr-14 18:14 package/services/metadata/core-properties/b44ebb537bbf4983b9527f9e3820fda6.psmdcp
+-5 files, 5577 bytes uncompressed, 2447 bytes compressed:  56.1%
++-rw-r--r--  2.0 unx      625 b- defN 25-Apr-14 18:14 package/services/metadata/core-properties/08f1f9d8789a4668a128f78560bd0107.psmdcp
++5 files, 5577 bytes uncompressed, 2446 bytes compressed:  56.1%


=====================================
tests/data/test1.nupkg
=====================================
Binary files /dev/null and b/tests/data/test1.nupkg differ


=====================================
tests/data/test2.nupkg
=====================================
Binary files /dev/null and b/tests/data/test2.nupkg differ



View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/-/commit/09abd4cddbebdf0f2310c47dc562826e44f18088

-- 
View it on GitLab: https://salsa.debian.org/reproducible-builds/diffoscope/-/commit/09abd4cddbebdf0f2310c47dc562826e44f18088
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.reproducible-builds.org/pipermail/rb-commits/attachments/20250512/e51d5617/attachment.htm>


More information about the rb-commits mailing list