diff --git a/platformio/package/manifest/parser.py b/platformio/package/manifest/parser.py index bf017721..837fabd6 100644 --- a/platformio/package/manifest/parser.py +++ b/platformio/package/manifest/parser.py @@ -17,6 +17,7 @@ import io import json import os import re +import tarfile import requests @@ -109,6 +110,17 @@ class ManifestParserFactory(object): remote_url, ) + @staticmethod + def new_from_archive(path): + assert path.endswith("tar.gz") + with tarfile.open(path, mode="r:gz") as tf: + for t in sorted(ManifestFileType.items().values()): + try: + return ManifestParserFactory.new(tf.extractfile(t).read(), t) + except KeyError: + pass + raise UnknownManifestError("Unknown manifest file type in %s archive" % path) + @staticmethod def new( # pylint: disable=redefined-builtin contents, type, remote_url=None, package_dir=None diff --git a/platformio/package/spec.py b/platformio/package/spec.py index 0535d4ba..f031c71c 100644 --- a/platformio/package/spec.py +++ b/platformio/package/spec.py @@ -43,7 +43,7 @@ class PackageType(object): def from_archive(cls, path): assert path.endswith("tar.gz") manifest_map = cls.get_manifest_map() - with tarfile.open(path, mode="r|gz") as tf: + with tarfile.open(path, mode="r:gz") as tf: for t in sorted(cls.items().values()): for manifest in manifest_map[t]: try: diff --git a/tests/package/test_manifest.py b/tests/package/test_manifest.py index 1ad66a75..e497c0b4 100644 --- a/tests/package/test_manifest.py +++ b/tests/package/test_manifest.py @@ -14,6 +14,7 @@ import os import re +import tarfile import jsondiff import pytest @@ -790,6 +791,21 @@ def test_examples_from_dir(tmpdir_factory): ) +def test_parser_from_archive(tmpdir_factory): + pkg_dir = tmpdir_factory.mktemp("package") + pkg_dir.join("package.json").write('{"name": "package.json"}') + pkg_dir.join("library.json").write('{"name": "library.json"}') + pkg_dir.join("library.properties").write("name=library.properties") + + archive_path = os.path.join(str(pkg_dir), "package.tar.gz") + with tarfile.open(archive_path, mode="w|gz") as tf: + for item in os.listdir(str(pkg_dir)): + tf.add(os.path.join(str(pkg_dir), item), item) + + data = parser.ManifestParserFactory.new_from_archive(archive_path).as_dict() + assert data["name"] == "library.json" + + def test_broken_schemas(): # missing required field with pytest.raises(