public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles
@ 2025-12-17  7:10 Louis Chauvet
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths Louis Chauvet
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17  7:10 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: thomas.petazzoni, Louis Chauvet, Sam James

Currently profiles does not allow using per-package license unmasking.
The only solution is the LICENSE variable, which apply to all the packages.

To allow this, add support for package.license in profile.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Louis Chauvet (4):
      lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths
      lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license
      tests/test_config: Refactor LicenseManager testing to test multiple configurations
      tests/test_config: Add test for package.license in profiles

 .../package/ebuild/_config/LicenseManager.py       |   9 +-
 lib/portage/package/ebuild/config.py               |   3 +-
 lib/portage/tests/ebuild/test_config.py            | 215 ++++++++++++---------
 man/portage.5                                      |   1 +
 4 files changed, 130 insertions(+), 98 deletions(-)
---
base-commit: d7d6fd54f1c936e89c5e4467c6c1f33b217325ca
change-id: 20251216-add_package_license_to_profiles-c6f695182aa3

Best regards,
-- 
Louis Chauvet <louis.chauvet@bootlin.com>



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths
  2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
@ 2025-12-17  7:10 ` Louis Chauvet
  2025-12-18  1:26   ` Sam James
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license Louis Chauvet
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17  7:10 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: thomas.petazzoni, Louis Chauvet

Currently LicenseManager only get the list of all profile locations. This
is enough for reading all license groups, but not for parsing
profile-specific package.license.

Directly pass the LocationsManager so LicenseManager can read
LicenseManager.profiles and read package.license.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 lib/portage/package/ebuild/_config/LicenseManager.py | 7 ++++---
 lib/portage/package/ebuild/config.py                 | 3 +--
 lib/portage/tests/ebuild/test_config.py              | 9 +++------
 3 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/lib/portage/package/ebuild/_config/LicenseManager.py b/lib/portage/package/ebuild/_config/LicenseManager.py
index 90f7742e301c..c59fff6ea4f2 100644
--- a/lib/portage/package/ebuild/_config/LicenseManager.py
+++ b/lib/portage/package/ebuild/_config/LicenseManager.py
@@ -14,20 +14,21 @@ from portage.package.ebuild._config.helper import ordered_by_atom_specificity
 
 
 class LicenseManager:
-    def __init__(self, license_group_locations, abs_user_config, user_config=True):
+    def __init__(self, locations_manager, user_config=True):
         self._accept_license_str = None
         self._accept_license = None
         self._license_groups = {}
         self._plicensedict = ExtendedAtomDict(dict)
         self._undef_lic_groups = set()
 
+        license_group_locations = list(locations_manager.profile_locations)
         if user_config:
-            license_group_locations = list(license_group_locations) + [abs_user_config]
+            license_group_locations.append(locations_manager.abs_user_config)
 
         self._read_license_groups(license_group_locations)
 
         if user_config:
-            self._read_user_config(abs_user_config)
+            self._read_user_config(locations_manager.abs_user_config)
 
     def _read_user_config(self, abs_user_config):
         licdict = grabdict_package(
diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py
index 4f60a71e7011..718f367eb2ed 100644
--- a/lib/portage/package/ebuild/config.py
+++ b/lib/portage/package/ebuild/config.py
@@ -847,8 +847,7 @@ class config:
 
             # Read license_groups and optionally license_groups and package.license from user config
             self._license_manager = LicenseManager(
-                locations_manager.profile_locations,
-                abs_user_config,
+                locations_manager,
                 user_config=local_config,
             )
             # Extract '*/*' entries from package.license
diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
index 743b30bfb0d6..83046a7dc97b 100644
--- a/lib/portage/tests/ebuild/test_config.py
+++ b/lib/portage/tests/ebuild/test_config.py
@@ -7,6 +7,7 @@ import portage
 from portage import os, shutil, _encodings
 from portage.const import USER_CONFIG_PATH
 from portage.dep import Atom
+from portage.package.ebuild._config.LocationsManager import LocationsManager
 from portage.package.ebuild.config import config
 from portage.package.ebuild._config.LicenseManager import LicenseManager
 from portage.tests import TestCase
@@ -95,17 +96,13 @@ class ConfigTestCase(TestCase):
         }
 
         playground = ResolverPlayground(user_config=user_config)
+        settings = config(clone=playground.settings)
         try:
             portage.util.noiselimit = -2
 
-            license_group_locations = (
-                os.path.join(
-                    playground.settings.repositories["test_repo"].location, "profiles"
-                ),
-            )
             pkg_license = os.path.join(playground.eroot, "etc", "portage")
 
-            lic_man = LicenseManager(license_group_locations, pkg_license)
+            lic_man = LicenseManager(settings._locations_manager, pkg_license)
 
             self.assertEqual(lic_man._accept_license_str, None)
             self.assertEqual(lic_man._accept_license, None)

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-portage-dev] [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license
  2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths Louis Chauvet
@ 2025-12-17  7:10 ` Louis Chauvet
  2025-12-18  1:27   ` [gentoo-portage-dev] " Sam James
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations Louis Chauvet
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17  7:10 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: thomas.petazzoni, Louis Chauvet, Sam James

Currently the only way to unmask license in profile is to use the LICENSE
variable in make.defaults. This may be acceptable for "unique" licenses
(linux-fw-redistributable, only used by one package), but not practical for
"generic" licenses.

Read profile-specific package.license in LicenseManager so per-profile
per-pacakge license can be configured.

Suggested-by: Sam James <sam@gentoo.org>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 lib/portage/package/ebuild/_config/LicenseManager.py | 2 ++
 man/portage.5                                        | 1 +
 2 files changed, 3 insertions(+)

diff --git a/lib/portage/package/ebuild/_config/LicenseManager.py b/lib/portage/package/ebuild/_config/LicenseManager.py
index c59fff6ea4f2..f515740071a7 100644
--- a/lib/portage/package/ebuild/_config/LicenseManager.py
+++ b/lib/portage/package/ebuild/_config/LicenseManager.py
@@ -28,6 +28,8 @@ class LicenseManager:
         self._read_license_groups(license_group_locations)
 
         if user_config:
+            for profile in locations_manager.profiles:
+                self._read_user_config(profile)
             self._read_user_config(locations_manager.abs_user_config)
 
     def _read_user_config(self, abs_user_config):
diff --git a/man/portage.5 b/man/portage.5
index d7b2063e0fc2..787fc18e1a9f 100644
--- a/man/portage.5
+++ b/man/portage.5
@@ -26,6 +26,7 @@ packages.build
 package.accept_keywords
 package.bashrc
 package.keywords
+package.license
 package.mask
 package.provided
 package.unmask

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations
  2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths Louis Chauvet
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license Louis Chauvet
@ 2025-12-17  7:10 ` Louis Chauvet
  2025-12-18  1:27   ` Sam James
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles Louis Chauvet
  2025-12-17  9:33 ` [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Ulrich Müller
  4 siblings, 1 reply; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17  7:10 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: thomas.petazzoni, Louis Chauvet

In order to easly test per-profile per-package license unmasking, extract
common code from testLicenseManager.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 lib/portage/tests/ebuild/test_config.py | 181 ++++++++++++++++----------------
 1 file changed, 88 insertions(+), 93 deletions(-)

diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
index 83046a7dc97b..b36073504b11 100644
--- a/lib/portage/tests/ebuild/test_config.py
+++ b/lib/portage/tests/ebuild/test_config.py
@@ -83,16 +83,94 @@ class ConfigTestCase(TestCase):
         finally:
             playground.cleanup()
 
+    _testLicenseManagerPackageLicense = (
+        "dev-libs/* TEST",
+        "dev-libs/A -TEST2",
+        "=dev-libs/A-2 TEST3 @TEST",
+        "*/* @EULA TEST2",
+        "=dev-libs/C-1 *",
+        "=dev-libs/C-2 -*",
+    )
+
+    def _testLicenseManager(self, lic_man):
+        self.assertEqual(lic_man._accept_license_str, None)
+        self.assertEqual(lic_man._accept_license, None)
+        self.assertEqual(lic_man._license_groups, {"EULA": frozenset(["TEST"])})
+        self.assertEqual(lic_man._undef_lic_groups, {"TEST"})
+
+        self.assertEqual(lic_man.extract_global_changes(), "TEST TEST2")
+        self.assertEqual(lic_man.extract_global_changes(), "")
+
+        lic_man.set_accept_license_str("TEST TEST2")
+        self.assertEqual(
+            lic_man._getPkgAcceptLicense("dev-libs/B-1", "0", None),
+            ["TEST", "TEST2", "TEST"],
+        )
+        self.assertEqual(
+            lic_man._getPkgAcceptLicense("dev-libs/A-1", "0", None),
+            ["TEST", "TEST2", "TEST", "-TEST2"],
+        )
+        self.assertEqual(
+            lic_man._getPkgAcceptLicense("dev-libs/A-2", "0", None),
+            ["TEST", "TEST2", "TEST", "-TEST2", "TEST3", "@TEST"],
+        )
+
+        self.assertEqual(
+            lic_man.get_prunned_accept_license("dev-libs/B-1", [], "TEST", "0", None),
+            "TEST",
+        )
+        self.assertEqual(
+            lic_man.get_prunned_accept_license("dev-libs/A-1", [], "-TEST2", "0", None),
+            "",
+        )
+        self.assertEqual(
+            lic_man.get_prunned_accept_license(
+                "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
+            ),
+            "TEST",
+        )
+        self.assertEqual(
+            lic_man.get_prunned_accept_license("dev-libs/C-1", [], "TEST5", "0", None),
+            "TEST5",
+        )
+        self.assertEqual(
+            lic_man.get_prunned_accept_license("dev-libs/C-2", [], "TEST2", "0", None),
+            "",
+        )
+
+        self.assertEqual(
+            lic_man.getMissingLicenses("dev-libs/B-1", [], "TEST", "0", None), []
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses("dev-libs/A-1", [], "-TEST2", "0", None),
+            ["-TEST2"],
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses(
+                "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
+            ),
+            [],
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses(
+                "dev-libs/A-3", [], "|| ( TEST2 || ( TEST3 TEST4 ) )", "0", None
+            ),
+            ["TEST2", "TEST3", "TEST4"],
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses("dev-libs/C-1", [], "TEST5", "0", None), []
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses("dev-libs/C-2", [], "TEST2", "0", None),
+            ["TEST2"],
+        )
+        self.assertEqual(
+            lic_man.getMissingLicenses("dev-libs/D-1", [], "", "0", None), []
+        )
+
     def testLicenseManager(self):
         user_config = {
-            "package.license": (
-                "dev-libs/* TEST",
-                "dev-libs/A -TEST2",
-                "=dev-libs/A-2 TEST3 @TEST",
-                "*/* @EULA TEST2",
-                "=dev-libs/C-1 *",
-                "=dev-libs/C-2 -*",
-            ),
+            "package.license": self._testLicenseManagerPackageLicense,
         }
 
         playground = ResolverPlayground(user_config=user_config)
@@ -100,92 +178,9 @@ class ConfigTestCase(TestCase):
         try:
             portage.util.noiselimit = -2
 
-            pkg_license = os.path.join(playground.eroot, "etc", "portage")
-
-            lic_man = LicenseManager(settings._locations_manager, pkg_license)
-
-            self.assertEqual(lic_man._accept_license_str, None)
-            self.assertEqual(lic_man._accept_license, None)
-            self.assertEqual(lic_man._license_groups, {"EULA": frozenset(["TEST"])})
-            self.assertEqual(lic_man._undef_lic_groups, {"TEST"})
-
-            self.assertEqual(lic_man.extract_global_changes(), "TEST TEST2")
-            self.assertEqual(lic_man.extract_global_changes(), "")
-
-            lic_man.set_accept_license_str("TEST TEST2")
-            self.assertEqual(
-                lic_man._getPkgAcceptLicense("dev-libs/B-1", "0", None),
-                ["TEST", "TEST2", "TEST"],
-            )
-            self.assertEqual(
-                lic_man._getPkgAcceptLicense("dev-libs/A-1", "0", None),
-                ["TEST", "TEST2", "TEST", "-TEST2"],
-            )
-            self.assertEqual(
-                lic_man._getPkgAcceptLicense("dev-libs/A-2", "0", None),
-                ["TEST", "TEST2", "TEST", "-TEST2", "TEST3", "@TEST"],
-            )
-
-            self.assertEqual(
-                lic_man.get_prunned_accept_license(
-                    "dev-libs/B-1", [], "TEST", "0", None
-                ),
-                "TEST",
-            )
-            self.assertEqual(
-                lic_man.get_prunned_accept_license(
-                    "dev-libs/A-1", [], "-TEST2", "0", None
-                ),
-                "",
-            )
-            self.assertEqual(
-                lic_man.get_prunned_accept_license(
-                    "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
-                ),
-                "TEST",
-            )
-            self.assertEqual(
-                lic_man.get_prunned_accept_license(
-                    "dev-libs/C-1", [], "TEST5", "0", None
-                ),
-                "TEST5",
-            )
-            self.assertEqual(
-                lic_man.get_prunned_accept_license(
-                    "dev-libs/C-2", [], "TEST2", "0", None
-                ),
-                "",
-            )
+            lic_man = LicenseManager(settings._locations_manager)
+            self._testLicenseManager(lic_man)
 
-            self.assertEqual(
-                lic_man.getMissingLicenses("dev-libs/B-1", [], "TEST", "0", None), []
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses("dev-libs/A-1", [], "-TEST2", "0", None),
-                ["-TEST2"],
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses(
-                    "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
-                ),
-                [],
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses(
-                    "dev-libs/A-3", [], "|| ( TEST2 || ( TEST3 TEST4 ) )", "0", None
-                ),
-                ["TEST2", "TEST3", "TEST4"],
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses("dev-libs/C-1", [], "TEST5", "0", None), []
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses("dev-libs/C-2", [], "TEST2", "0", None),
-                ["TEST2"],
-            )
-            self.assertEqual(
-                lic_man.getMissingLicenses("dev-libs/D-1", [], "", "0", None), []
-            )
         finally:
             portage.util.noiselimit = 0
             playground.cleanup()

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles
  2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
                   ` (2 preceding siblings ...)
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations Louis Chauvet
@ 2025-12-17  7:10 ` Louis Chauvet
  2025-12-18  1:28   ` Sam James
  2025-12-17  9:33 ` [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Ulrich Müller
  4 siblings, 1 reply; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17  7:10 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: thomas.petazzoni, Louis Chauvet

Now package.license can be read from profiles, add two tests to ensure that
user and profile configuration are properly read.

Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
 lib/portage/tests/ebuild/test_config.py | 37 +++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
index b36073504b11..43940987254b 100644
--- a/lib/portage/tests/ebuild/test_config.py
+++ b/lib/portage/tests/ebuild/test_config.py
@@ -185,6 +185,43 @@ class ConfigTestCase(TestCase):
             portage.util.noiselimit = 0
             playground.cleanup()
 
+    def testLicenseManagerProfile(self):
+        profile_config = {
+            "package.license": self._testLicenseManagerPackageLicense,
+        }
+
+        playground = ResolverPlayground(profile=profile_config)
+        settings = config(clone=playground.settings)
+        try:
+            portage.util.noiselimit = -2
+
+            lic_man = LicenseManager(settings._locations_manager)
+            self._testLicenseManager(lic_man)
+
+        finally:
+            portage.util.noiselimit = 0
+            playground.cleanup()
+
+    def testLicenseManagerMixed(self):
+        profile_config = {
+            "package.license": self._testLicenseManagerPackageLicense[:4],
+        }
+        user_config = {
+            "package.license": self._testLicenseManagerPackageLicense[4:],
+        }
+
+        playground = ResolverPlayground(user_config=user_config, profile=profile_config)
+        settings = config(clone=playground.settings)
+        try:
+            portage.util.noiselimit = -2
+
+            lic_man = LicenseManager(settings._locations_manager)
+            self._testLicenseManager(lic_man)
+
+        finally:
+            portage.util.noiselimit = 0
+            playground.cleanup()
+
     def testPackageMaskOrder(self):
         ebuilds = {
             "dev-libs/A-1": {},

-- 
2.51.2



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles
  2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
                   ` (3 preceding siblings ...)
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles Louis Chauvet
@ 2025-12-17  9:33 ` Ulrich Müller
  2025-12-17 10:15   ` Michael Orlitzky
  2025-12-17 11:10   ` Louis Chauvet
  4 siblings, 2 replies; 13+ messages in thread
From: Ulrich Müller @ 2025-12-17  9:33 UTC (permalink / raw
  To: Louis Chauvet; +Cc: gentoo-portage-dev, thomas.petazzoni, Sam James

[-- Attachment #1: Type: text/plain, Size: 372 bytes --]

>>>>> On Wed, 17 Dec 2025, Louis Chauvet wrote:

> Currently profiles does not allow using per-package license unmasking.
> The only solution is the LICENSE variable, which apply to all the packages.

What would be the application for this? I understand package.license
in user configuration, but why would we ever want to unmask nonfree
per-package licenses in profiles?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 544 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles
  2025-12-17  9:33 ` [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Ulrich Müller
@ 2025-12-17 10:15   ` Michael Orlitzky
  2025-12-17 11:10   ` Louis Chauvet
  1 sibling, 0 replies; 13+ messages in thread
From: Michael Orlitzky @ 2025-12-17 10:15 UTC (permalink / raw
  To: gentoo-portage-dev; +Cc: Louis Chauvet, thomas.petazzoni, Sam James

On 2025-12-17 10:33:47, Ulrich Müller wrote:
> 
> > Currently profiles does not allow using per-package license unmasking.
> > The only solution is the LICENSE variable, which apply to all the packages.
> 
> What would be the application for this? I understand package.license
> in user configuration, but why would we ever want to unmask nonfree
> per-package licenses in profiles?

I would unmask e.g.

  sys-firmware/intel-microcode intel-ucode

in the custom profile I use at work for all of our intel servers.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles
  2025-12-17  9:33 ` [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Ulrich Müller
  2025-12-17 10:15   ` Michael Orlitzky
@ 2025-12-17 11:10   ` Louis Chauvet
  2025-12-18  1:28     ` Sam James
  1 sibling, 1 reply; 13+ messages in thread
From: Louis Chauvet @ 2025-12-17 11:10 UTC (permalink / raw
  To: Ulrich Müller; +Cc: gentoo-portage-dev, thomas.petazzoni, Sam James



On 12/17/25 10:33, Ulrich Müller wrote:
>>>>>> On Wed, 17 Dec 2025, Louis Chauvet wrote:
> 
>> Currently profiles does not allow using per-package license unmasking.
>> The only solution is the LICENSE variable, which apply to all the packages.
> 
> What would be the application for this? I understand package.license
> in user configuration, but why would we ever want to unmask nonfree
> per-package licenses in profiles?

My goal is to create my own custom profile to use the same set of 
packages, version, use between my laptop and my desktop.

I have some non-free packages (linux-firmware, Saleae, intel-microcode), 
so for me that make sense to have a package.license file in the profile.

For information, I also opened a pull request on Codeberg [1] because I 
wasn’t sure if the mailing list was active.

[1]:https://codeberg.org/gentoo/portage/pulls/1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths Louis Chauvet
@ 2025-12-18  1:26   ` Sam James
  0 siblings, 0 replies; 13+ messages in thread
From: Sam James @ 2025-12-18  1:26 UTC (permalink / raw
  To: Louis Chauvet; +Cc: gentoo-portage-dev, thomas.petazzoni

Louis Chauvet <louis.chauvet@bootlin.com> writes:

> Currently LicenseManager only get the list of all profile locations. This
> is enough for reading all license groups, but not for parsing
> profile-specific package.license.
>
> Directly pass the LocationsManager so LicenseManager can read
> LicenseManager.profiles and read package.license.
>

Reviewed-by: Sam James <sam@gentoo.org>

> Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
> ---
>  lib/portage/package/ebuild/_config/LicenseManager.py | 7 ++++---
>  lib/portage/package/ebuild/config.py                 | 3 +--
>  lib/portage/tests/ebuild/test_config.py              | 9 +++------
>  3 files changed, 8 insertions(+), 11 deletions(-)
>
> diff --git a/lib/portage/package/ebuild/_config/LicenseManager.py b/lib/portage/package/ebuild/_config/LicenseManager.py
> index 90f7742e301c..c59fff6ea4f2 100644
> --- a/lib/portage/package/ebuild/_config/LicenseManager.py
> +++ b/lib/portage/package/ebuild/_config/LicenseManager.py
> @@ -14,20 +14,21 @@ from portage.package.ebuild._config.helper import ordered_by_atom_specificity
>  
>  
>  class LicenseManager:
> -    def __init__(self, license_group_locations, abs_user_config, user_config=True):
> +    def __init__(self, locations_manager, user_config=True):
>          self._accept_license_str = None
>          self._accept_license = None
>          self._license_groups = {}
>          self._plicensedict = ExtendedAtomDict(dict)
>          self._undef_lic_groups = set()
>  
> +        license_group_locations = list(locations_manager.profile_locations)
>          if user_config:
> -            license_group_locations = list(license_group_locations) + [abs_user_config]
> +            license_group_locations.append(locations_manager.abs_user_config)
>  
>          self._read_license_groups(license_group_locations)
>  
>          if user_config:
> -            self._read_user_config(abs_user_config)
> +            self._read_user_config(locations_manager.abs_user_config)
>  
>      def _read_user_config(self, abs_user_config):
>          licdict = grabdict_package(
> diff --git a/lib/portage/package/ebuild/config.py b/lib/portage/package/ebuild/config.py
> index 4f60a71e7011..718f367eb2ed 100644
> --- a/lib/portage/package/ebuild/config.py
> +++ b/lib/portage/package/ebuild/config.py
> @@ -847,8 +847,7 @@ class config:
>  
>              # Read license_groups and optionally license_groups and package.license from user config
>              self._license_manager = LicenseManager(
> -                locations_manager.profile_locations,
> -                abs_user_config,
> +                locations_manager,
>                  user_config=local_config,
>              )
>              # Extract '*/*' entries from package.license
> diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
> index 743b30bfb0d6..83046a7dc97b 100644
> --- a/lib/portage/tests/ebuild/test_config.py
> +++ b/lib/portage/tests/ebuild/test_config.py
> @@ -7,6 +7,7 @@ import portage
>  from portage import os, shutil, _encodings
>  from portage.const import USER_CONFIG_PATH
>  from portage.dep import Atom
> +from portage.package.ebuild._config.LocationsManager import LocationsManager
>  from portage.package.ebuild.config import config
>  from portage.package.ebuild._config.LicenseManager import LicenseManager
>  from portage.tests import TestCase
> @@ -95,17 +96,13 @@ class ConfigTestCase(TestCase):
>          }
>  
>          playground = ResolverPlayground(user_config=user_config)
> +        settings = config(clone=playground.settings)
>          try:
>              portage.util.noiselimit = -2
>  
> -            license_group_locations = (
> -                os.path.join(
> -                    playground.settings.repositories["test_repo"].location, "profiles"
> -                ),
> -            )
>              pkg_license = os.path.join(playground.eroot, "etc", "portage")
>  
> -            lic_man = LicenseManager(license_group_locations, pkg_license)
> +            lic_man = LicenseManager(settings._locations_manager, pkg_license)
>  
>              self.assertEqual(lic_man._accept_license_str, None)
>              self.assertEqual(lic_man._accept_license, None)


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [gentoo-portage-dev] Re: [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license Louis Chauvet
@ 2025-12-18  1:27   ` Sam James
  0 siblings, 0 replies; 13+ messages in thread
From: Sam James @ 2025-12-18  1:27 UTC (permalink / raw
  To: Louis Chauvet; +Cc: gentoo-portage-dev, thomas.petazzoni

Louis Chauvet <louis.chauvet@bootlin.com> writes:

> Currently the only way to unmask license in profile is to use the LICENSE
> variable in make.defaults. This may be acceptable for "unique" licenses
> (linux-fw-redistributable, only used by one package), but not practical for
> "generic" licenses.
>
> Read profile-specific package.license in LicenseManager so per-profile
> per-pacakge license can be configured.
>

Reviewed-by: Sam James <sam@gentoo.org>

> Suggested-by: Sam James <sam@gentoo.org>
> Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
> ---
>  lib/portage/package/ebuild/_config/LicenseManager.py | 2 ++
>  man/portage.5                                        | 1 +
>  2 files changed, 3 insertions(+)
>
> diff --git a/lib/portage/package/ebuild/_config/LicenseManager.py b/lib/portage/package/ebuild/_config/LicenseManager.py
> index c59fff6ea4f2..f515740071a7 100644
> --- a/lib/portage/package/ebuild/_config/LicenseManager.py
> +++ b/lib/portage/package/ebuild/_config/LicenseManager.py
> @@ -28,6 +28,8 @@ class LicenseManager:
>          self._read_license_groups(license_group_locations)
>  
>          if user_config:
> +            for profile in locations_manager.profiles:
> +                self._read_user_config(profile)
>              self._read_user_config(locations_manager.abs_user_config)
>  
>      def _read_user_config(self, abs_user_config):
> diff --git a/man/portage.5 b/man/portage.5
> index d7b2063e0fc2..787fc18e1a9f 100644
> --- a/man/portage.5
> +++ b/man/portage.5
> @@ -26,6 +26,7 @@ packages.build
>  package.accept_keywords
>  package.bashrc
>  package.keywords
> +package.license
>  package.mask
>  package.provided
>  package.unmask


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations Louis Chauvet
@ 2025-12-18  1:27   ` Sam James
  0 siblings, 0 replies; 13+ messages in thread
From: Sam James @ 2025-12-18  1:27 UTC (permalink / raw
  To: Louis Chauvet; +Cc: gentoo-portage-dev, thomas.petazzoni

Louis Chauvet <louis.chauvet@bootlin.com> writes:

> In order to easly test per-profile per-package license unmasking, extract
> common code from testLicenseManager.

Reviewed-by: Sam James <sam@gentoo.org>

>
> Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
> ---
>  lib/portage/tests/ebuild/test_config.py | 181 ++++++++++++++++----------------
>  1 file changed, 88 insertions(+), 93 deletions(-)
>
> diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
> index 83046a7dc97b..b36073504b11 100644
> --- a/lib/portage/tests/ebuild/test_config.py
> +++ b/lib/portage/tests/ebuild/test_config.py
> @@ -83,16 +83,94 @@ class ConfigTestCase(TestCase):
>          finally:
>              playground.cleanup()
>  
> +    _testLicenseManagerPackageLicense = (
> +        "dev-libs/* TEST",
> +        "dev-libs/A -TEST2",
> +        "=dev-libs/A-2 TEST3 @TEST",
> +        "*/* @EULA TEST2",
> +        "=dev-libs/C-1 *",
> +        "=dev-libs/C-2 -*",
> +    )
> +
> +    def _testLicenseManager(self, lic_man):
> +        self.assertEqual(lic_man._accept_license_str, None)
> +        self.assertEqual(lic_man._accept_license, None)
> +        self.assertEqual(lic_man._license_groups, {"EULA": frozenset(["TEST"])})
> +        self.assertEqual(lic_man._undef_lic_groups, {"TEST"})
> +
> +        self.assertEqual(lic_man.extract_global_changes(), "TEST TEST2")
> +        self.assertEqual(lic_man.extract_global_changes(), "")
> +
> +        lic_man.set_accept_license_str("TEST TEST2")
> +        self.assertEqual(
> +            lic_man._getPkgAcceptLicense("dev-libs/B-1", "0", None),
> +            ["TEST", "TEST2", "TEST"],
> +        )
> +        self.assertEqual(
> +            lic_man._getPkgAcceptLicense("dev-libs/A-1", "0", None),
> +            ["TEST", "TEST2", "TEST", "-TEST2"],
> +        )
> +        self.assertEqual(
> +            lic_man._getPkgAcceptLicense("dev-libs/A-2", "0", None),
> +            ["TEST", "TEST2", "TEST", "-TEST2", "TEST3", "@TEST"],
> +        )
> +
> +        self.assertEqual(
> +            lic_man.get_prunned_accept_license("dev-libs/B-1", [], "TEST", "0", None),
> +            "TEST",
> +        )
> +        self.assertEqual(
> +            lic_man.get_prunned_accept_license("dev-libs/A-1", [], "-TEST2", "0", None),
> +            "",
> +        )
> +        self.assertEqual(
> +            lic_man.get_prunned_accept_license(
> +                "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
> +            ),
> +            "TEST",
> +        )
> +        self.assertEqual(
> +            lic_man.get_prunned_accept_license("dev-libs/C-1", [], "TEST5", "0", None),
> +            "TEST5",
> +        )
> +        self.assertEqual(
> +            lic_man.get_prunned_accept_license("dev-libs/C-2", [], "TEST2", "0", None),
> +            "",
> +        )
> +
> +        self.assertEqual(
> +            lic_man.getMissingLicenses("dev-libs/B-1", [], "TEST", "0", None), []
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses("dev-libs/A-1", [], "-TEST2", "0", None),
> +            ["-TEST2"],
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses(
> +                "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
> +            ),
> +            [],
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses(
> +                "dev-libs/A-3", [], "|| ( TEST2 || ( TEST3 TEST4 ) )", "0", None
> +            ),
> +            ["TEST2", "TEST3", "TEST4"],
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses("dev-libs/C-1", [], "TEST5", "0", None), []
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses("dev-libs/C-2", [], "TEST2", "0", None),
> +            ["TEST2"],
> +        )
> +        self.assertEqual(
> +            lic_man.getMissingLicenses("dev-libs/D-1", [], "", "0", None), []
> +        )
> +
>      def testLicenseManager(self):
>          user_config = {
> -            "package.license": (
> -                "dev-libs/* TEST",
> -                "dev-libs/A -TEST2",
> -                "=dev-libs/A-2 TEST3 @TEST",
> -                "*/* @EULA TEST2",
> -                "=dev-libs/C-1 *",
> -                "=dev-libs/C-2 -*",
> -            ),
> +            "package.license": self._testLicenseManagerPackageLicense,
>          }
>  
>          playground = ResolverPlayground(user_config=user_config)
> @@ -100,92 +178,9 @@ class ConfigTestCase(TestCase):
>          try:
>              portage.util.noiselimit = -2
>  
> -            pkg_license = os.path.join(playground.eroot, "etc", "portage")
> -
> -            lic_man = LicenseManager(settings._locations_manager, pkg_license)
> -
> -            self.assertEqual(lic_man._accept_license_str, None)
> -            self.assertEqual(lic_man._accept_license, None)
> -            self.assertEqual(lic_man._license_groups, {"EULA": frozenset(["TEST"])})
> -            self.assertEqual(lic_man._undef_lic_groups, {"TEST"})
> -
> -            self.assertEqual(lic_man.extract_global_changes(), "TEST TEST2")
> -            self.assertEqual(lic_man.extract_global_changes(), "")
> -
> -            lic_man.set_accept_license_str("TEST TEST2")
> -            self.assertEqual(
> -                lic_man._getPkgAcceptLicense("dev-libs/B-1", "0", None),
> -                ["TEST", "TEST2", "TEST"],
> -            )
> -            self.assertEqual(
> -                lic_man._getPkgAcceptLicense("dev-libs/A-1", "0", None),
> -                ["TEST", "TEST2", "TEST", "-TEST2"],
> -            )
> -            self.assertEqual(
> -                lic_man._getPkgAcceptLicense("dev-libs/A-2", "0", None),
> -                ["TEST", "TEST2", "TEST", "-TEST2", "TEST3", "@TEST"],
> -            )
> -
> -            self.assertEqual(
> -                lic_man.get_prunned_accept_license(
> -                    "dev-libs/B-1", [], "TEST", "0", None
> -                ),
> -                "TEST",
> -            )
> -            self.assertEqual(
> -                lic_man.get_prunned_accept_license(
> -                    "dev-libs/A-1", [], "-TEST2", "0", None
> -                ),
> -                "",
> -            )
> -            self.assertEqual(
> -                lic_man.get_prunned_accept_license(
> -                    "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
> -                ),
> -                "TEST",
> -            )
> -            self.assertEqual(
> -                lic_man.get_prunned_accept_license(
> -                    "dev-libs/C-1", [], "TEST5", "0", None
> -                ),
> -                "TEST5",
> -            )
> -            self.assertEqual(
> -                lic_man.get_prunned_accept_license(
> -                    "dev-libs/C-2", [], "TEST2", "0", None
> -                ),
> -                "",
> -            )
> +            lic_man = LicenseManager(settings._locations_manager)
> +            self._testLicenseManager(lic_man)
>  
> -            self.assertEqual(
> -                lic_man.getMissingLicenses("dev-libs/B-1", [], "TEST", "0", None), []
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses("dev-libs/A-1", [], "-TEST2", "0", None),
> -                ["-TEST2"],
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses(
> -                    "dev-libs/A-2", [], "|| ( TEST TEST2 )", "0", None
> -                ),
> -                [],
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses(
> -                    "dev-libs/A-3", [], "|| ( TEST2 || ( TEST3 TEST4 ) )", "0", None
> -                ),
> -                ["TEST2", "TEST3", "TEST4"],
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses("dev-libs/C-1", [], "TEST5", "0", None), []
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses("dev-libs/C-2", [], "TEST2", "0", None),
> -                ["TEST2"],
> -            )
> -            self.assertEqual(
> -                lic_man.getMissingLicenses("dev-libs/D-1", [], "", "0", None), []
> -            )
>          finally:
>              portage.util.noiselimit = 0
>              playground.cleanup()


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles
  2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles Louis Chauvet
@ 2025-12-18  1:28   ` Sam James
  0 siblings, 0 replies; 13+ messages in thread
From: Sam James @ 2025-12-18  1:28 UTC (permalink / raw
  To: Louis Chauvet; +Cc: gentoo-portage-dev, thomas.petazzoni

Louis Chauvet <louis.chauvet@bootlin.com> writes:

> Now package.license can be read from profiles, add two tests to ensure that
> user and profile configuration are properly read.

Reviewed-by: Sam James <sam@gentoo.org>

>
> Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
> ---
>  lib/portage/tests/ebuild/test_config.py | 37 +++++++++++++++++++++++++++++++++
>  1 file changed, 37 insertions(+)
>
> diff --git a/lib/portage/tests/ebuild/test_config.py b/lib/portage/tests/ebuild/test_config.py
> index b36073504b11..43940987254b 100644
> --- a/lib/portage/tests/ebuild/test_config.py
> +++ b/lib/portage/tests/ebuild/test_config.py
> @@ -185,6 +185,43 @@ class ConfigTestCase(TestCase):
>              portage.util.noiselimit = 0
>              playground.cleanup()
>  
> +    def testLicenseManagerProfile(self):
> +        profile_config = {
> +            "package.license": self._testLicenseManagerPackageLicense,
> +        }
> +
> +        playground = ResolverPlayground(profile=profile_config)
> +        settings = config(clone=playground.settings)
> +        try:
> +            portage.util.noiselimit = -2
> +
> +            lic_man = LicenseManager(settings._locations_manager)
> +            self._testLicenseManager(lic_man)
> +
> +        finally:
> +            portage.util.noiselimit = 0
> +            playground.cleanup()
> +
> +    def testLicenseManagerMixed(self):
> +        profile_config = {
> +            "package.license": self._testLicenseManagerPackageLicense[:4],
> +        }
> +        user_config = {
> +            "package.license": self._testLicenseManagerPackageLicense[4:],
> +        }
> +
> +        playground = ResolverPlayground(user_config=user_config, profile=profile_config)
> +        settings = config(clone=playground.settings)
> +        try:
> +            portage.util.noiselimit = -2
> +
> +            lic_man = LicenseManager(settings._locations_manager)
> +            self._testLicenseManager(lic_man)
> +
> +        finally:
> +            portage.util.noiselimit = 0
> +            playground.cleanup()
> +
>      def testPackageMaskOrder(self):
>          ebuilds = {
>              "dev-libs/A-1": {},


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles
  2025-12-17 11:10   ` Louis Chauvet
@ 2025-12-18  1:28     ` Sam James
  0 siblings, 0 replies; 13+ messages in thread
From: Sam James @ 2025-12-18  1:28 UTC (permalink / raw
  To: Louis Chauvet; +Cc: Ulrich Müller, gentoo-portage-dev, thomas.petazzoni

Louis Chauvet <louis.chauvet@bootlin.com> writes:

> On 12/17/25 10:33, Ulrich Müller wrote:
>>>>>>> On Wed, 17 Dec 2025, Louis Chauvet wrote:
>> 
>>> Currently profiles does not allow using per-package license unmasking.
>>> The only solution is the LICENSE variable, which apply to all the packages.
>> What would be the application for this? I understand package.license
>> in user configuration, but why would we ever want to unmask nonfree
>> per-package licenses in profiles?

Profiles aren't just for the type we use in ::gentoo. They are often
used for custom deployments to different machine types in a fleet.

>
> My goal is to create my own custom profile to use the same set of
> packages, version, use between my laptop and my desktop.
>
> I have some non-free packages (linux-firmware, Saleae,
> intel-microcode), so for me that make sense to have a package.license
> file in the profile.

I think it's a reasonable usecase indeed.

>
> For information, I also opened a pull request on Codeberg [1] because
> I wasn’t sure if the mailing list was active.
>
> [1]:https://codeberg.org/gentoo/portage/pulls/1


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-12-18  1:29 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-17  7:10 [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Louis Chauvet
2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 1/4] lib/portage/package/ebuild/_config/LicenseManager.py: Use location_manager instead of paths Louis Chauvet
2025-12-18  1:26   ` Sam James
2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 2/4] lib/portage/package/ebuild/_config/LicenseManager.py: Read per-profile package.license Louis Chauvet
2025-12-18  1:27   ` [gentoo-portage-dev] " Sam James
2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 3/4] tests/test_config: Refactor LicenseManager testing to test multiple configurations Louis Chauvet
2025-12-18  1:27   ` Sam James
2025-12-17  7:10 ` [gentoo-portage-dev] [PATCH RESEND 4/4] tests/test_config: Add test for package.license in profiles Louis Chauvet
2025-12-18  1:28   ` Sam James
2025-12-17  9:33 ` [gentoo-portage-dev] [PATCH RESEND 0/4] Add package.license support to profiles Ulrich Müller
2025-12-17 10:15   ` Michael Orlitzky
2025-12-17 11:10   ` Louis Chauvet
2025-12-18  1:28     ` Sam James

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox