Repository: conan-io/conan-center-index

Issue:
Updating imagl recipe for conan 2.0
imagl/0.2.1

I've updated this recipe for conan 2.0. Most of changes are induced from cmake_lib template.

---

- [x] I've read the [contributing guidelines](https://github.com/conan-io/conan-center-index/blob/master/CONTRIBUTING.md).
- [x] I've used a [recent](https://github.com/conan-io/conan/releases/latest) Conan client version close to the [currently deployed](https://github.com/conan-io/conan-center-index/blob/master/.c3i/config_v1.yml#L6).
- [x] I've tried at least one configuration locally with**out** the [conan-center hook](https://github.com/conan-io/hooks.git) activated. (Documentation says that it's not ready for conan v2.0)

[service] Conan v2 pipeline fails with "Invalid JSON String" error
### What is your problem/feature request?

I try to update the recipe for imagl. It is widely inspired from working recipes of other packages. But for this one, I have a not helping ["Invalid JSON String" error](https://github.com/conan-io/conan-center-index/pull/16698#issuecomment-1579039855) from @conan-center-bot with no log.

Is it possible to have a more helping message from CI? (a raw log, or something that can be used to understand what's wrong.)

Thank you in advance.


Discussion:

Resolving patch:
diff --git a/recipes/imagl/all/conanfile.py b/recipes/imagl/all/conanfile.py
--- a/recipes/imagl/all/conanfile.py
+++ b/recipes/imagl/all/conanfile.py
@@ -1,12 +1,18 @@
-from conans import ConanFile, CMake, tools
-from conans.errors import ConanInvalidConfiguration
+from conan import ConanFile
+from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
+from conan.tools.scm import Version
+from conan.tools.build import check_min_cppstd
+from conan.tools.files import apply_conandata_patches, export_conandata_patches, get, copy
+from conan.tools.microsoft import is_msvc, check_min_vs
+from conan.errors import ConanInvalidConfiguration
+import os
 
-required_conan_version = ">=1.33.0"
+required_conan_version = ">=1.53.0"
 
 
 class ImaglConan(ConanFile):
     name = "imagl"
-    license = "GPL-3.0-or-later"
+    license = "LGPL-3.0-only"
     homepage = "https://github.com/Woazim/imaGL"
     url = "https://github.com/conan-io/conan-center-index"
     description = "A lightweight library to load image for OpenGL application."
@@ -24,108 +30,88 @@ class ImaglConan(ConanFile):
         "with_png": True,
         "with_jpeg": True,
     }
-    generators = "cmake"
-    exports_sources = ["CMakeLists.txt", "patches/**"]
-    _cmake = None
 
     @property
-    def _source_subfolder(self):
-        return "source_subfolder"
-
-    @property
-    def _build_subfolder(self):
-        return "build_subfolder"
+    def _min_cppstd(self):
+        return 20
 
     @property
     def _compilers_minimum_version(self):
-        minimum_versions = {
+        return {
                 "gcc": "9",
-                "Visual Studio": "16.2",
-                "msvc": "19.22",
                 "clang": "10",
                 "apple-clang": "11"
         }
-        if tools.Version(self.version) <= "0.1.1" or tools.Version(self.version) == "0.2.0":
-            minimum_versions["Visual Studio"] = "16.5"
-            minimum_versions["msvc"] = "19.25"
-        return minimum_versions
 
     @property
     def _supports_jpeg(self):
-        return tools.Version(self.version) >= "0.2.0"
+        return Version(self.version) >= "0.2.0"
+
+    def export_sources(self):
+        export_conandata_patches(self)
 
     def config_options(self):
         if self.settings.os == "Windows":
-            del self.options.fPIC
+            self.options.rm_safe("fPIC")
         if not self._supports_jpeg:
-            del self.options.with_jpeg
+            self.options.rm_safe("with_jpeg")
 
     def configure(self):
         if self.options.shared:
-            del self.options.fPIC
+            self.options.rm_safe("fPIC")
+
+    def layout(self):
+        cmake_layout(self, src_folder="src")
 
     def requirements(self):
         if self.options.with_png:
-            self.requires("libpng/1.6.37")
+            self.requires("libpng/1.6.40")
         if self._supports_jpeg and self.options.with_jpeg:
-            self.requires("libjpeg/9d")
+            self.requires("libjpeg/9e")
 
     def validate(self):
         if self.settings.compiler.cppstd:
-            tools.check_min_cppstd(self, 20)
-
-        def lazy_lt_semver(v1, v2):
-            lv1 = [int(v) for v in v1.split(".")]
-            lv2 = [int(v) for v in v2.split(".")]
-            min_length = min(len(lv1), len(lv2))
-            return lv1[:min_length] < lv2[:min_length]
-
-        #Special check for clang that can only be linked to libc++
-        if self.settings.compiler == "clang" and self.settings.compiler.libcxx != "libc++":
+            check_min_cppstd(self, self._min_cppstd)
+        check_min_vs(self, 192)
+        if not is_msvc(self):
+            minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
+            if minimum_version and Version(self.settings.compiler.version) < minimum_version:
+                raise ConanInvalidConfiguration(
+                    f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
+                )
+
+        # INFO: Special check for clang that can only be linked to libc++
+        if self.settings.compiler == "clang" and self.settings.get_safe("compiler.libcxx") != "libc++":
             raise ConanInvalidConfiguration("imagl requires some C++20 features, which are available in libc++ for clang compiler.")
 
-        compiler_version = str(self.settings.compiler.version)
-
-        minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
-        if not minimum_version:
-            self.output.warn("imaGL requires C++20. Your compiler is unknown. Assuming it supports C++20.")
-        elif lazy_lt_semver(compiler_version, minimum_version):
-            raise ConanInvalidConfiguration("imaGL requires some C++20 features, which your {} {} compiler does not support.".format(str(self.settings.compiler), compiler_version))
-        else:
-            print("Your compiler is {} {} and is compatible.".format(str(self.settings.compiler), compiler_version))
 
     def source(self):
-        tools.get(**self.conan_data["sources"][self.version],
-                  destination=self._source_subfolder, strip_root=True)
-
-    def _configure_cmake(self):
-        if self._cmake:
-            return self._cmake
-
-        self._cmake = CMake(self)
-
-        self._cmake.definitions["STATIC_LIB"] = not self.options.shared
-        self._cmake.definitions["SUPPORT_PNG"] = self.options.with_png
+        get(self, **self.conan_data["sources"][self.version], strip_root=True)
+
+    def generate(self):
+        deps = CMakeDeps(self)
+        deps.generate()
+        tc = CMakeToolchain(self)
+        tc.variables["STATIC_LIB"] = not self.options.shared
+        tc.variables["SUPPORT_PNG"] = self.options.with_png
         if self._supports_jpeg:
-            self._cmake.definitions["SUPPORT_JPEG"] = self.options.with_jpeg
-        self._cmake.configure(build_folder=self._build_subfolder)
-        return self._cmake
+            tc.variables["SUPPORT_JPEG"] = self.options.with_jpeg
+        tc.generate()
 
     def build(self):
-        for patch in self.conan_data.get("patches", {}).get(self.version, []):
-            tools.patch(**patch)
-        cmake = self._configure_cmake()
+        apply_conandata_patches(self)
+        cmake = CMake(self)
+        cmake.configure()
         cmake.build()
 
     def package(self):
-        self.copy("LICENSE", dst="licenses", src=self._source_subfolder)
-        cmake = self._configure_cmake()
+        copy(self, "LICENSE", self.source_folder, os.path.join(self.package_folder, "licenses"))
+        cmake = CMake(self)
         cmake.install()
 
     def package_info(self):
         debug_suffix = "d" if self.settings.build_type == "Debug" else ""
         static_suffix = "" if self.options.shared else "s"
-        self.cpp_info.libs = ["imaGL{}{}".format(debug_suffix, static_suffix)]
+        self.cpp_info.libs = [f"imaGL{debug_suffix}{static_suffix}"]
         if not self.options.shared:
             self.cpp_info.defines = ["IMAGL_STATIC=1"]
-


Test patch:
diff --git a/recipes/imagl/all/test_package/CMakeLists.txt b/recipes/imagl/all/test_package/CMakeLists.txt
--- a/recipes/imagl/all/test_package/CMakeLists.txt
+++ b/recipes/imagl/all/test_package/CMakeLists.txt
@@ -1,9 +1,8 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.15)
 project(PackageTest CXX)
 
-include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
-conan_basic_setup()
+find_package(imagl CONFIG REQUIRED)
 
 add_executable(example example.cpp)
-target_link_libraries(example ${CONAN_LIBS})
-set_target_properties(example PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON)
+target_link_libraries(example PRIVATE imagl::imagl)
+target_compile_features(example PRIVATE cxx_std_20)
diff --git a/recipes/imagl/all/test_package/conanfile.py b/recipes/imagl/all/test_package/conanfile.py
--- a/recipes/imagl/all/test_package/conanfile.py
+++ b/recipes/imagl/all/test_package/conanfile.py
@@ -1,10 +1,19 @@
+from conan import ConanFile
+from conan.tools.build import can_run
+from conan.tools.cmake import cmake_layout, CMake
 import os
-from conans import ConanFile, CMake, tools
 
 
 class ImaglTestConan(ConanFile):
     settings = "os", "compiler", "build_type", "arch"
-    generators = "cmake"
+    generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"
+    test_type = "explicit"
+
+    def layout(self):
+        cmake_layout(self)
+
+    def requirements(self):
+        self.requires(self.tested_reference_str)
 
     def build(self):
         cmake = CMake(self)
@@ -12,6 +21,6 @@ def build(self):
         cmake.build()
 
     def test(self):
-        if not tools.cross_building(self):
-            bin_path = os.path.join("bin", "example")
-            self.run(bin_path, run_environment=True)
+        if can_run(self):
+            bin_path = os.path.join(self.cpp.build.bindir, "example")
+            self.run(bin_path, env="conanrun")
diff --git a/recipes/imagl/all/test_v1_package/CMakeLists.txt b/recipes/imagl/all/test_v1_package/CMakeLists.txt
new file mode 100644
--- /dev/null
+++ b/recipes/imagl/all/test_v1_package/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.15)
+project(test_package)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup(TARGETS)
+
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package/
+                 ${CMAKE_CURRENT_BINARY_DIR}/test_package/)
diff --git a/recipes/imagl/all/test_v1_package/conanfile.py b/recipes/imagl/all/test_v1_package/conanfile.py
new file mode 100644
--- /dev/null
+++ b/recipes/imagl/all/test_v1_package/conanfile.py
@@ -0,0 +1,17 @@
+import os
+from conans import ConanFile, CMake, tools
+
+
+class ImaglTestConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "cmake", "cmake_find_package_multi"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        if not tools.cross_building(self):
+            bin_path = os.path.join("bin", "example")
+            self.run(bin_path, run_environment=True)