Commit 09abd4cd authored by Omair Majid's avatar Omair Majid Committed by Chris Lamb
Browse files

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).
parent 8425d51c
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ class ComparatorManager:
        ("ocaml.OcamlInterfaceFile",),
        ("docx.DocxFile",),
        ("zip.MozillaZipFile",),
        ("zip.NuGetPackageFile",),
        ("zip.JmodJavaModule",),
        ("zip.ZipFile",),
        ("image.JPEGImageFile",),
+7 −0
Original line number Diff line number Diff line
@@ -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)")
+44 −1
Original line number Diff line number Diff line
@@ -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


@pytest.fixture
def nupkg_differences(nupkg1, nupkg2):
    return nupkg1.compare(nupkg2).details


@skip_unless_tools_exist("zipinfo")
def test_nupkg_metadata(nupkg_differences, nupkg1, nupkg2):
    assert_diff(nupkg_differences[0], "nupkg_expected_diff")


@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"
    )


@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)

+11 −0
Original line number Diff line number Diff line
@@ -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

0 → 100644
+3.09 KiB

File added.

No diff preview for this file type.

Loading