go.mod: update osbuild/images to v0.118.0

Replace ifcfg with net-lib for EL10 and F42 installers.

In RHEL 10 and Fedora 42, the ifcfg module was replaced by net-lib.

This PR removes ifcfg from common anaconda dracut stage modules and adds
either ifcfg or net-lib to each installer based on distro version.
This commit is contained in:
Achilleas Koutsou 2025-02-19 15:27:09 +01:00 committed by Tomáš Hozza
parent 2fc64aeaca
commit 5817db95f8
43 changed files with 900 additions and 307 deletions

4
go.mod
View file

@ -44,14 +44,14 @@ require (
github.com/labstack/gommon v0.4.2
github.com/openshift-online/ocm-sdk-go v0.1.438
github.com/oracle/oci-go-sdk/v54 v54.0.0
github.com/osbuild/images v0.117.0
github.com/osbuild/images v0.118.0
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d
github.com/osbuild/pulp-client v0.1.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.5
github.com/segmentio/ksuid v1.0.4
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
github.com/ubccr/kerby v0.0.0-20230802201021-412be7bfaee5
github.com/vmware/govmomi v0.48.1

11
go.sum
View file

@ -191,7 +191,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
@ -547,8 +547,8 @@ github.com/openshift-online/ocm-sdk-go v0.1.438 h1:tsLCCUzbLCTL4RZG02y9RuopmGCXp
github.com/openshift-online/ocm-sdk-go v0.1.438/go.mod h1:CiAu2jwl3ITKOxkeV0Qnhzv4gs35AmpIzVABQLtcI2Y=
github.com/oracle/oci-go-sdk/v54 v54.0.0 h1:CDLjeSejv2aDpElAJrhKpi6zvT/zhZCZuXchUUZ+LS4=
github.com/oracle/oci-go-sdk/v54 v54.0.0/go.mod h1:+t+yvcFGVp+3ZnztnyxqXfQDsMlq8U25faBLa+mqCMc=
github.com/osbuild/images v0.117.0 h1:5crTgWMnzHMtTXJ7wgkgpF2Pif8D6tDa83kDCCz/ZYM=
github.com/osbuild/images v0.117.0/go.mod h1:vLzVEw/752cjLLOwXW+mS73xCdfmwqYn09f9RVEhDkM=
github.com/osbuild/images v0.118.0 h1:anQrnshrAPby9bEoiRD4T1clbDxxgGd+8elRc5g1zCY=
github.com/osbuild/images v0.118.0/go.mod h1:Ag87vmyxooiPQBJEDILbypG8/SRIear75YA78NwLix0=
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d h1:r9BFPDv0uuA9k1947Jybcxs36c/pTywWS1gjeizvtcQ=
github.com/osbuild/osbuild-composer/pkg/splunk_logger v0.0.0-20240814102216-0239db53236d/go.mod h1:zR1iu/hOuf+OQNJlk70tju9IqzzM4ycq0ectkFBm94U=
github.com/osbuild/pulp-client v0.1.0 h1:L0C4ezBJGTamN3BKdv+rKLuq/WxXJbsFwz/Hj7aEmJ8=
@ -618,9 +618,8 @@ github.com/smallstep/pkcs7 v0.1.1 h1:x+rPdt2W088V9Vkjho4KtoggyktZJlMduZAtRHm68LU
github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA=
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b h1:br+bPNZsJWKicw/5rALEo67QHs5weyD5tf8WST+4sJ0=
github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stefanberger/go-pkcs11uri v0.0.0-20230803200340-78284954bff6 h1:pnnLyeX7o/5aX8qUQ69P/mLojDqwda8hFOCBTmP/6hw=

View file

@ -58,5 +58,13 @@
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGTSYSwBEACTHP7OFONk+1B1awJeYToUFMVbYZIjNvj9M7zwf5vzH52FlpXX\ndsbs1AWh6NUe0zV1J5JjCGiI24Vjacysg7L2zsbgT48vVv3mXrXorjYOzT/cxsAh\n7PNhEx+OevKzAx3oy0Ok27c11Dz0W4ynwVy80gB6XHI2rd04v74TiC0xQYlxj1Sh\nj6irdLmHMD/NtTCWmCM7MRf91UcC4rk6JOap715UKey2fk1h/wylv0guMP3o+CpG\njxDHENkfl/GsWCSYBaHec7o5/qg5RoAkN5NImVI00CqiEO1WHPBaCJalgwbuQCiW\n006jwVDHJHRoufS85PEKaY9yqd5Fr76kdqCLsf3Ys9yxGVfOTvCaKOa+ElWBo+i6\nyOtEO6Qp1Qd5spomBJ+FVPjU89lR9aDnvxIVX7X6zu638qV0K3Lb2HKmqiVG6ccJ\nIdxNVXJAekvu7ypwvRzEc0mGgfkZ47flaj7X8SxiebbXhYWdqRBF0rMYc7ppkbCp\n5NsD+KJilkfeOGb7VK6Rx5vXmySiNCb9GqN51KRl4Z1qllrc/Q1k5CCMt3AUq0hv\n1fwK3eFGtd4/YgF9LoZ0tW8WFZ6h/zWnRvJ/SDBPhtovoSpxptCd18MWiakwvwW0\nsxueKFlctdDjW1a/gri3V4RdTOZbr0AqDjGGcYndt/oxMeLxaK9qvs2xIQARAQAB\ntDFGZWRvcmEgKDQxKSA8ZmVkb3JhLTQxLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJOBBMBCAA4FiEERmzy2LYLwwV6qUU+0GIkYumdatEFAmTSYSwCGw8FCwkI\nBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ0GIkYumdatFHIQ//bTSVGDvJGmUxgHJw\nMnGM2G6Rc9PNAKuXbh6t4qsrRKp22pWNnMmqqcGaoiBxKP989a2cJgIVP49SsC4C\newaafEYhsitUtKagx6z3F7UObnvQpOz5U5iFcJCvRDtC4FXq+VkMdhT09zMZY4Ey\nia29bV1B1R7pe7yXh6l3WyVj9AAXUSEBR/OsakaYEMzScLnROBEU1YbWR9iHsc7M\nrEsqju8tVUh1XAqIqJgLW3VrKs0g0nDVR0rBc8aDhrtVfylwWVl61gHsPFJfAkjj\nOPgvQgThrhlCWo23EZSk/Hj8YRrnhUbEDnk+Z3Xv5Uyl1kxGRk5dGBnv+7u3CKvV\nG6sU3tPtna/8rFblfKSMZIPhzTADdsUZ88Fn9pZkfqgPi8LZ4sS8vHtaykZmbfj6\nt9a2mBYJQ+/pxiH8olzyhKMdNyesLPeQmESgwM/qlJ+b2Hbogwuuzp8o2JMezxIe\nCAwLoPh+hxMPGnBRklh6Vj5R5z29wIZd6pKCavVRfJ+ON94wuOSEofhBfQNZIIFV\njagEbk60iksysxsObfVEHFhtGnZCEgCRC87BfX6tzIIDv23Zs4Bv9gcaaRXTAml2\nkZXktduHkV9q3hhcoha5FgGSe244C4GsMUkWCsZtuN6tevUPo+n2ZZAA7ikQ768r\nIz9rPOI8/Ra7qnwSlNIVnkTb9bc=\n=e2ew\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
],
"riscv64": [
{
"name": "fedora",
"baseurl": "http://fedora.riscv.rocks/repos/f41-build/latest/riscv64",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGTSYSwBEACTHP7OFONk+1B1awJeYToUFMVbYZIjNvj9M7zwf5vzH52FlpXXdsbs1AWh6NUe0zV1J5JjCGiI24Vjacysg7L2zsbgT48vVv3mXrXorjYOzT/cxsAh7PNhEx+OevKzAx3oy0Ok27c11Dz0W4ynwVy80gB6XHI2rd04v74TiC0xQYlxj1Shj6irdLmHMD/NtTCWmCM7MRf91UcC4rk6JOap715UKey2fk1h/wylv0guMP3o+CpGjxDHENkfl/GsWCSYBaHec7o5/qg5RoAkN5NImVI00CqiEO1WHPBaCJalgwbuQCiW006jwVDHJHRoufS85PEKaY9yqd5Fr76kdqCLsf3Ys9yxGVfOTvCaKOa+ElWBo+i6yOtEO6Qp1Qd5spomBJ+FVPjU89lR9aDnvxIVX7X6zu638qV0K3Lb2HKmqiVG6ccJIdxNVXJAekvu7ypwvRzEc0mGgfkZ47flaj7X8SxiebbXhYWdqRBF0rMYc7ppkbCp5NsD+KJilkfeOGb7VK6Rx5vXmySiNCb9GqN51KRl4Z1qllrc/Q1k5CCMt3AUq0hv1fwK3eFGtd4/YgF9LoZ0tW8WFZ6h/zWnRvJ/SDBPhtovoSpxptCd18MWiakwvwW0sxueKFlctdDjW1a/gri3V4RdTOZbr0AqDjGGcYndt/oxMeLxaK9qvs2xIQARAQABtDFGZWRvcmEgKDQxKSA8ZmVkb3JhLTQxLXByaW1hcnlAZmVkb3JhcHJvamVjdC5vcmc+iQJOBBMBCAA4FiEERmzy2LYLwwV6qUU+0GIkYumdatEFAmTSYSwCGw8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ0GIkYumdatFHIQ//bTSVGDvJGmUxgHJwMnGM2G6Rc9PNAKuXbh6t4qsrRKp22pWNnMmqqcGaoiBxKP989a2cJgIVP49SsC4CewaafEYhsitUtKagx6z3F7UObnvQpOz5U5iFcJCvRDtC4FXq+VkMdhT09zMZY4Eyia29bV1B1R7pe7yXh6l3WyVj9AAXUSEBR/OsakaYEMzScLnROBEU1YbWR9iHsc7MrEsqju8tVUh1XAqIqJgLW3VrKs0g0nDVR0rBc8aDhrtVfylwWVl61gHsPFJfAkjjOPgvQgThrhlCWo23EZSk/Hj8YRrnhUbEDnk+Z3Xv5Uyl1kxGRk5dGBnv+7u3CKvVG6sU3tPtna/8rFblfKSMZIPhzTADdsUZ88Fn9pZkfqgPi8LZ4sS8vHtaykZmbfj6t9a2mBYJQ+/pxiH8olzyhKMdNyesLPeQmESgwM/qlJ+b2Hbogwuuzp8o2JMezxIeCAwLoPh+hxMPGnBRklh6Vj5R5z29wIZd6pKCavVRfJ+ON94wuOSEofhBfQNZIIFVjagEbk60iksysxsObfVEHFhtGnZCEgCRC87BfX6tzIIDv23Zs4Bv9gcaaRXTAml2kZXktduHkV9q3hhcoha5FgGSe244C4GsMUkWCsZtuN6tevUPo+n2ZZAA7ikQ768rIz9rPOI8/Ra7qnwSlNIVnkTb9bc=\n=e2ew\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
]
}

View file

@ -58,5 +58,13 @@
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGXKg9EBEACvsAjRcllcH6mVReU/0hi5YnwqulP7gNgUM4jYPiqucF51g0oW\nMbFk0VjDn3QXjrwLNLtj4oxsU+E6OW0jl1732qvjUJ9geEZBuidyFZgq0CCn9K8d\n661dPDjN/DzWWogFhnDySFHRLdh6dYCuu75/HKSIVfCud2IFCvT7Bhk4AOpxv4c7\nmmX874LFgi49jkAYC0M6UbJ9o3KSCndipf/k0ra2g9dGacqlPfn3PMiTszPDr99d\no4qZ5dVZYC6Sna8GjNhN7b/2xLGQuzdd9LHgPHC/PX7XsvBLu42rqi3q0umJBtjZ\nCyFxF5Dp0VMwmVfrKFZOHvVsGjPLrxomLU16/EDzIrw6cHikdQKLf4sl0rX0m8j0\nPNAGOSDmE9YgByiPo12CGMOuAvsDUI0JID4p4WqpBShTBuiIrITn8XVTCOQ+tKq9\ndE/qI+mm2hnZjJajM2UWfKE0mVH4SDOiSilgKR/h5HuLZqwtYXFExDZsAcxaLfRB\nKCrIOyJdpV7YIj8PaP89XeycHM2MaIfwdHSx3Pz39zZNzi6vJkLj9SWdQT7lOvZx\nxTQ3dK0Rcpjx+rGHgihMT4yBd+JO9mZS3ghNGbypYnNn/mohPOAxguXuPuPRj00o\nC7C3lIEEL/hZXZbN1SuiopZjxbU/x/5lO8n0Un1GCzynObPDvpDLTjsdKQARAQAB\ntDFGZWRvcmEgKDQyKSA8ZmVkb3JhLTQyLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJOBBMBCAA4FiEEsPSVBFj2nhFQxsXtyKxJFhBe+UQFAmXKg9ECGw8FCwkI\nBwIGFQoJCAsCBBYCAwECHgECF4AACgkQyKxJFhBe+US4mQ//e4gIGhA6TJuEqrVP\ngKtSnDawIj30TGbkXIywECtKCu9N8anTlkU2/XSKGyE3ZDdKDO77O11382Ci1xJg\nCpdbqKg4G02ecEKT1Dtng37gt55SkhffQ0EeDb3Zl+Pu5qohHQUiMzio4B4q8n0H\nD+L9klQ3I1rLmymguBRd34jQH/z025GE2SBbCpDnQCChZT7Fq1D/onOQgC6skN6Q\nE2dvYqOnSlHkkfuVlRRYoLNmynxHKlL6VZkiM7m1zKi7cMEK63mKJQ3jH3Mc9grh\n+OwBDxOjx5UoYMeYqq7oXyTPKvvf6ssuHtjWM3tNkyi5R1nB+4SHMttrbt2pLMSH\nJg6pNXoLAP8ahlvxdgVRjgN/6OMC/DwXnLxippelBXXDyBnwVd8/WohbJDcq7e5t\ndymZpRsNxzhWSuwbHzeJY1DKtePhbjblShLjxTzLnS4GBPJV5TXpHkZWgQmz2aA0\nCHV47j37P6kAOEtsJkJUWWz+/Rx1N5Mm5lxvghaAzlTBtwQhRgl9Y8kCTznG40QQ\n64N2FOrcExUJmujLRISDjM2Ps9MtBlbYs7H4JDziX4jpNyvhVAbEdjbzVfL5oi35\nl+K/QRtQJnt78qhLpNNB7SdQkNmD8eMeXF7mA/MH6eFM88hF4l6NeKklyMIa5thg\nLFx0UyEgoLXDBg+thUzby61gnA8=\n=OCXB\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
],
"riscv64": [
{
"name": "fedora",
"baseurl": "http://fedora.riscv.rocks/repos/f42-build/latest/riscv64",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGTSYSwBEACTHP7OFONk+1B1awJeYToUFMVbYZIjNvj9M7zwf5vzH52FlpXXdsbs1AWh6NUe0zV1J5JjCGiI24Vjacysg7L2zsbgT48vVv3mXrXorjYOzT/cxsAh7PNhEx+OevKzAx3oy0Ok27c11Dz0W4ynwVy80gB6XHI2rd04v74TiC0xQYlxj1Shj6irdLmHMD/NtTCWmCM7MRf91UcC4rk6JOap715UKey2fk1h/wylv0guMP3o+CpGjxDHENkfl/GsWCSYBaHec7o5/qg5RoAkN5NImVI00CqiEO1WHPBaCJalgwbuQCiW006jwVDHJHRoufS85PEKaY9yqd5Fr76kdqCLsf3Ys9yxGVfOTvCaKOa+ElWBo+i6yOtEO6Qp1Qd5spomBJ+FVPjU89lR9aDnvxIVX7X6zu638qV0K3Lb2HKmqiVG6ccJIdxNVXJAekvu7ypwvRzEc0mGgfkZ47flaj7X8SxiebbXhYWdqRBF0rMYc7ppkbCp5NsD+KJilkfeOGb7VK6Rx5vXmySiNCb9GqN51KRl4Z1qllrc/Q1k5CCMt3AUq0hv1fwK3eFGtd4/YgF9LoZ0tW8WFZ6h/zWnRvJ/SDBPhtovoSpxptCd18MWiakwvwW0sxueKFlctdDjW1a/gri3V4RdTOZbr0AqDjGGcYndt/oxMeLxaK9qvs2xIQARAQABtDFGZWRvcmEgKDQxKSA8ZmVkb3JhLTQxLXByaW1hcnlAZmVkb3JhcHJvamVjdC5vcmc+iQJOBBMBCAA4FiEERmzy2LYLwwV6qUU+0GIkYumdatEFAmTSYSwCGw8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQ0GIkYumdatFHIQ//bTSVGDvJGmUxgHJwMnGM2G6Rc9PNAKuXbh6t4qsrRKp22pWNnMmqqcGaoiBxKP989a2cJgIVP49SsC4CewaafEYhsitUtKagx6z3F7UObnvQpOz5U5iFcJCvRDtC4FXq+VkMdhT09zMZY4Eyia29bV1B1R7pe7yXh6l3WyVj9AAXUSEBR/OsakaYEMzScLnROBEU1YbWR9iHsc7MrEsqju8tVUh1XAqIqJgLW3VrKs0g0nDVR0rBc8aDhrtVfylwWVl61gHsPFJfAkjjOPgvQgThrhlCWo23EZSk/Hj8YRrnhUbEDnk+Z3Xv5Uyl1kxGRk5dGBnv+7u3CKvVG6sU3tPtna/8rFblfKSMZIPhzTADdsUZ88Fn9pZkfqgPi8LZ4sS8vHtaykZmbfj6t9a2mBYJQ+/pxiH8olzyhKMdNyesLPeQmESgwM/qlJ+b2Hbogwuuzp8o2JMezxIeCAwLoPh+hxMPGnBRklh6Vj5R5z29wIZd6pKCavVRfJ+ON94wuOSEofhBfQNZIIFVjagEbk60iksysxsObfVEHFhtGnZCEgCRC87BfX6tzIIDv23Zs4Bv9gcaaRXTAml2kZXktduHkV9q3hhcoha5FgGSe244C4GsMUkWCsZtuN6tevUPo+n2ZZAA7ikQ768rIz9rPOI8/Ra7qnwSlNIVnkTb9bc=\n=e2ew\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
]
}

View file

@ -0,0 +1,34 @@
{
"x86_64": [
{
"name": "fedora",
"metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-rawhide&arch=x86_64",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGa23M8BEAC47NwKLi/g2S9I2p5JtUbJ0y3m2St9zqkSENmYw/+R+WKvaP3S\nKSFQF3Qi6pqGXJ88ADJUkFYpOGGyoc0dieLCmIPqtWbwGvBVMxBRBeU3+hClwbSQ\nsysVnr8VxUwidfsIjNJavCZwB0ZoZbxdCPMQMOgQyTLX4OI/uKlPUzeymDHwxjb/\ntllflSTOGtdYe3giRzidxN+xbCb6UoXkl0+lJEFbsmp41O5D/Ur5N05lBrsEXoDu\nFr99Kfv3Av7f3JfzDlkqC/EhmfxZEZvWj3hRdAfi2fFmtVcrdLfGIpQg6Y2Baphp\nPhaHqKl9zD5GWqu5GSXGoLaGXusBvwBKjS/g+VLo7pJfMsUF3sUduJNG3UThAsrp\nQLV3wQz0AMHVElRErOWdBDY0ddAKLPL7/mtxj39pGEpZ/dNtQkzgm7VCdP10QnQZ\nrwR2l8k7CPu0pylPCXmXvKFWV1uv9RnztlWY6BRmufKn+lJsN3Blh7ndi5rlCjR6\nmHVrQD/l6+8VmSD3/mDnbEXPyzBkSY5D1wpR7M5VXN5jVHROc4ZA5M88SyI48ESG\nNmeAwtGar45/X+wG47+EC4+JXpNO7BQrEvHgJxBdyoQ6KLDrEaqn/OQpxB4Gfmcv\nSwkWDpSk8wFm/pGlFK6J4b+ba7eOetW+aXrWSiFB1sTAg0OY+gds67OpWQARAQAB\ntDFGZWRvcmEgKDQzKSA8ZmVkb3JhLTQzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJSBBMBCAA8FiEExufwgc+A4TFGZ26IgptgZjFkVTEFAma23M8CGw8FCwkI\nBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJEIKbYGYxZFUxagQP/RYWw5j0Gfvv\nlWkDQTjTVAnHtbKuQLYM13Lx5d3W1k0g6Xdrolf4yPjh4YPYVQDXksB4i6ULLbMo\n8u46UCPMQwCXTd3Ax9imYn+V74Isl/CkBbKQD9YfSJjhW3mSlPa27jo2uhqpdV0S\nxp05NWYnWrZN+GbtCUs1+rNTBevagOURtlZ8f0iPVRA/PxWzpjbRaGrCHlIYc3JO\nGKLUuQueLvOUg2pP8dtpll7S3xUe5Abyq2ifT34T0wHi6hJA3bfpXo1uNXRvGrNw\ngbJ7V6P7ioTcvyhS1h4zjelKFyvTnOKOy5D08HKmvTMWZQWEL7kDNymh1jMV7Abg\n4TPp808EiPF1GGAzXU56feaURSvIuix3MkjhGZsSQQH2kkkEIzq6j/EwmpyEMW38\ndtql4T2bVS/cTk/hRaqUKZlyrsL657g/4mFA1wDDM3895fYkHOpYF4JZ9SeDrhuc\nTgpC7/TW55l6vSiFtnQvcMfjpfCA6mCA4b75k+/xG9RxxBnYU0qVuUo/8pON31yQ\nD2AM2v7WbJBYVRYLlqPrkAZU5fe7+2wY7P7N0IAPwVA0TFJ1x6as3Kezdi/304mg\noC98DBLjHaUpX2bTxKMtCzlmeqPiwtyNkA9O9IQO7qQzArBKxmAgof4wblN5SL8i\nfsjiJUqsK/gTYwJ744I/tzxOy5FXjA7z\n=Bqds\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
],
"aarch64": [
{
"name": "fedora",
"metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-rawhide&arch=aarch64",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGa23M8BEAC47NwKLi/g2S9I2p5JtUbJ0y3m2St9zqkSENmYw/+R+WKvaP3S\nKSFQF3Qi6pqGXJ88ADJUkFYpOGGyoc0dieLCmIPqtWbwGvBVMxBRBeU3+hClwbSQ\nsysVnr8VxUwidfsIjNJavCZwB0ZoZbxdCPMQMOgQyTLX4OI/uKlPUzeymDHwxjb/\ntllflSTOGtdYe3giRzidxN+xbCb6UoXkl0+lJEFbsmp41O5D/Ur5N05lBrsEXoDu\nFr99Kfv3Av7f3JfzDlkqC/EhmfxZEZvWj3hRdAfi2fFmtVcrdLfGIpQg6Y2Baphp\nPhaHqKl9zD5GWqu5GSXGoLaGXusBvwBKjS/g+VLo7pJfMsUF3sUduJNG3UThAsrp\nQLV3wQz0AMHVElRErOWdBDY0ddAKLPL7/mtxj39pGEpZ/dNtQkzgm7VCdP10QnQZ\nrwR2l8k7CPu0pylPCXmXvKFWV1uv9RnztlWY6BRmufKn+lJsN3Blh7ndi5rlCjR6\nmHVrQD/l6+8VmSD3/mDnbEXPyzBkSY5D1wpR7M5VXN5jVHROc4ZA5M88SyI48ESG\nNmeAwtGar45/X+wG47+EC4+JXpNO7BQrEvHgJxBdyoQ6KLDrEaqn/OQpxB4Gfmcv\nSwkWDpSk8wFm/pGlFK6J4b+ba7eOetW+aXrWSiFB1sTAg0OY+gds67OpWQARAQAB\ntDFGZWRvcmEgKDQzKSA8ZmVkb3JhLTQzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJSBBMBCAA8FiEExufwgc+A4TFGZ26IgptgZjFkVTEFAma23M8CGw8FCwkI\nBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJEIKbYGYxZFUxagQP/RYWw5j0Gfvv\nlWkDQTjTVAnHtbKuQLYM13Lx5d3W1k0g6Xdrolf4yPjh4YPYVQDXksB4i6ULLbMo\n8u46UCPMQwCXTd3Ax9imYn+V74Isl/CkBbKQD9YfSJjhW3mSlPa27jo2uhqpdV0S\nxp05NWYnWrZN+GbtCUs1+rNTBevagOURtlZ8f0iPVRA/PxWzpjbRaGrCHlIYc3JO\nGKLUuQueLvOUg2pP8dtpll7S3xUe5Abyq2ifT34T0wHi6hJA3bfpXo1uNXRvGrNw\ngbJ7V6P7ioTcvyhS1h4zjelKFyvTnOKOy5D08HKmvTMWZQWEL7kDNymh1jMV7Abg\n4TPp808EiPF1GGAzXU56feaURSvIuix3MkjhGZsSQQH2kkkEIzq6j/EwmpyEMW38\ndtql4T2bVS/cTk/hRaqUKZlyrsL657g/4mFA1wDDM3895fYkHOpYF4JZ9SeDrhuc\nTgpC7/TW55l6vSiFtnQvcMfjpfCA6mCA4b75k+/xG9RxxBnYU0qVuUo/8pON31yQ\nD2AM2v7WbJBYVRYLlqPrkAZU5fe7+2wY7P7N0IAPwVA0TFJ1x6as3Kezdi/304mg\noC98DBLjHaUpX2bTxKMtCzlmeqPiwtyNkA9O9IQO7qQzArBKxmAgof4wblN5SL8i\nfsjiJUqsK/gTYwJ744I/tzxOy5FXjA7z\n=Bqds\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
],
"ppc64le": [
{
"name": "fedora",
"metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-rawhide&arch=ppc64le",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGa23M8BEAC47NwKLi/g2S9I2p5JtUbJ0y3m2St9zqkSENmYw/+R+WKvaP3S\nKSFQF3Qi6pqGXJ88ADJUkFYpOGGyoc0dieLCmIPqtWbwGvBVMxBRBeU3+hClwbSQ\nsysVnr8VxUwidfsIjNJavCZwB0ZoZbxdCPMQMOgQyTLX4OI/uKlPUzeymDHwxjb/\ntllflSTOGtdYe3giRzidxN+xbCb6UoXkl0+lJEFbsmp41O5D/Ur5N05lBrsEXoDu\nFr99Kfv3Av7f3JfzDlkqC/EhmfxZEZvWj3hRdAfi2fFmtVcrdLfGIpQg6Y2Baphp\nPhaHqKl9zD5GWqu5GSXGoLaGXusBvwBKjS/g+VLo7pJfMsUF3sUduJNG3UThAsrp\nQLV3wQz0AMHVElRErOWdBDY0ddAKLPL7/mtxj39pGEpZ/dNtQkzgm7VCdP10QnQZ\nrwR2l8k7CPu0pylPCXmXvKFWV1uv9RnztlWY6BRmufKn+lJsN3Blh7ndi5rlCjR6\nmHVrQD/l6+8VmSD3/mDnbEXPyzBkSY5D1wpR7M5VXN5jVHROc4ZA5M88SyI48ESG\nNmeAwtGar45/X+wG47+EC4+JXpNO7BQrEvHgJxBdyoQ6KLDrEaqn/OQpxB4Gfmcv\nSwkWDpSk8wFm/pGlFK6J4b+ba7eOetW+aXrWSiFB1sTAg0OY+gds67OpWQARAQAB\ntDFGZWRvcmEgKDQzKSA8ZmVkb3JhLTQzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJSBBMBCAA8FiEExufwgc+A4TFGZ26IgptgZjFkVTEFAma23M8CGw8FCwkI\nBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJEIKbYGYxZFUxagQP/RYWw5j0Gfvv\nlWkDQTjTVAnHtbKuQLYM13Lx5d3W1k0g6Xdrolf4yPjh4YPYVQDXksB4i6ULLbMo\n8u46UCPMQwCXTd3Ax9imYn+V74Isl/CkBbKQD9YfSJjhW3mSlPa27jo2uhqpdV0S\nxp05NWYnWrZN+GbtCUs1+rNTBevagOURtlZ8f0iPVRA/PxWzpjbRaGrCHlIYc3JO\nGKLUuQueLvOUg2pP8dtpll7S3xUe5Abyq2ifT34T0wHi6hJA3bfpXo1uNXRvGrNw\ngbJ7V6P7ioTcvyhS1h4zjelKFyvTnOKOy5D08HKmvTMWZQWEL7kDNymh1jMV7Abg\n4TPp808EiPF1GGAzXU56feaURSvIuix3MkjhGZsSQQH2kkkEIzq6j/EwmpyEMW38\ndtql4T2bVS/cTk/hRaqUKZlyrsL657g/4mFA1wDDM3895fYkHOpYF4JZ9SeDrhuc\nTgpC7/TW55l6vSiFtnQvcMfjpfCA6mCA4b75k+/xG9RxxBnYU0qVuUo/8pON31yQ\nD2AM2v7WbJBYVRYLlqPrkAZU5fe7+2wY7P7N0IAPwVA0TFJ1x6as3Kezdi/304mg\noC98DBLjHaUpX2bTxKMtCzlmeqPiwtyNkA9O9IQO7qQzArBKxmAgof4wblN5SL8i\nfsjiJUqsK/gTYwJ744I/tzxOy5FXjA7z\n=Bqds\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
],
"s390x": [
{
"name": "fedora",
"metalink": "https://mirrors.fedoraproject.org/metalink?repo=fedora-rawhide&arch=s390x",
"gpgkey": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBGa23M8BEAC47NwKLi/g2S9I2p5JtUbJ0y3m2St9zqkSENmYw/+R+WKvaP3S\nKSFQF3Qi6pqGXJ88ADJUkFYpOGGyoc0dieLCmIPqtWbwGvBVMxBRBeU3+hClwbSQ\nsysVnr8VxUwidfsIjNJavCZwB0ZoZbxdCPMQMOgQyTLX4OI/uKlPUzeymDHwxjb/\ntllflSTOGtdYe3giRzidxN+xbCb6UoXkl0+lJEFbsmp41O5D/Ur5N05lBrsEXoDu\nFr99Kfv3Av7f3JfzDlkqC/EhmfxZEZvWj3hRdAfi2fFmtVcrdLfGIpQg6Y2Baphp\nPhaHqKl9zD5GWqu5GSXGoLaGXusBvwBKjS/g+VLo7pJfMsUF3sUduJNG3UThAsrp\nQLV3wQz0AMHVElRErOWdBDY0ddAKLPL7/mtxj39pGEpZ/dNtQkzgm7VCdP10QnQZ\nrwR2l8k7CPu0pylPCXmXvKFWV1uv9RnztlWY6BRmufKn+lJsN3Blh7ndi5rlCjR6\nmHVrQD/l6+8VmSD3/mDnbEXPyzBkSY5D1wpR7M5VXN5jVHROc4ZA5M88SyI48ESG\nNmeAwtGar45/X+wG47+EC4+JXpNO7BQrEvHgJxBdyoQ6KLDrEaqn/OQpxB4Gfmcv\nSwkWDpSk8wFm/pGlFK6J4b+ba7eOetW+aXrWSiFB1sTAg0OY+gds67OpWQARAQAB\ntDFGZWRvcmEgKDQzKSA8ZmVkb3JhLTQzLXByaW1hcnlAZmVkb3JhcHJvamVjdC5v\ncmc+iQJSBBMBCAA8FiEExufwgc+A4TFGZ26IgptgZjFkVTEFAma23M8CGw8FCwkI\nBwIDIgIBBhUKCQgLAgQWAgMBAh4HAheAAAoJEIKbYGYxZFUxagQP/RYWw5j0Gfvv\nlWkDQTjTVAnHtbKuQLYM13Lx5d3W1k0g6Xdrolf4yPjh4YPYVQDXksB4i6ULLbMo\n8u46UCPMQwCXTd3Ax9imYn+V74Isl/CkBbKQD9YfSJjhW3mSlPa27jo2uhqpdV0S\nxp05NWYnWrZN+GbtCUs1+rNTBevagOURtlZ8f0iPVRA/PxWzpjbRaGrCHlIYc3JO\nGKLUuQueLvOUg2pP8dtpll7S3xUe5Abyq2ifT34T0wHi6hJA3bfpXo1uNXRvGrNw\ngbJ7V6P7ioTcvyhS1h4zjelKFyvTnOKOy5D08HKmvTMWZQWEL7kDNymh1jMV7Abg\n4TPp808EiPF1GGAzXU56feaURSvIuix3MkjhGZsSQQH2kkkEIzq6j/EwmpyEMW38\ndtql4T2bVS/cTk/hRaqUKZlyrsL657g/4mFA1wDDM3895fYkHOpYF4JZ9SeDrhuc\nTgpC7/TW55l6vSiFtnQvcMfjpfCA6mCA4b75k+/xG9RxxBnYU0qVuUo/8pON31yQ\nD2AM2v7WbJBYVRYLlqPrkAZU5fe7+2wY7P7N0IAPwVA0TFJ1x6as3Kezdi/304mg\noC98DBLjHaUpX2bTxKMtCzlmeqPiwtyNkA9O9IQO7qQzArBKxmAgof4wblN5SL8i\nfsjiJUqsK/gTYwJ744I/tzxOy5FXjA7z\n=Bqds\n-----END PGP PUBLIC KEY BLOCK-----\n",
"check_gpg": true
}
]
}

View file

@ -12,6 +12,7 @@ const ( // architecture enum
ARCH_PPC64LE
ARCH_S390X
ARCH_X86_64
ARCH_RISCV64
)
func (a Arch) String() string {
@ -26,6 +27,8 @@ func (a Arch) String() string {
return "s390x"
case ARCH_X86_64:
return "x86_64"
case ARCH_RISCV64:
return "riscv64"
default:
panic("invalid architecture")
}
@ -33,18 +36,16 @@ func (a Arch) String() string {
func FromString(a string) Arch {
switch a {
case "amd64":
fallthrough
case "x86_64":
case "amd64", "x86_64":
return ARCH_X86_64
case "arm64":
fallthrough
case "aarch64":
case "arm64", "aarch64":
return ARCH_AARCH64
case "s390x":
return ARCH_S390X
case "ppc64le":
return ARCH_PPC64LE
case "riscv64":
return ARCH_RISCV64
default:
panic("unsupported architecture")
}
@ -53,18 +54,7 @@ func FromString(a string) Arch {
var runtimeGOARCH = runtime.GOARCH
func Current() Arch {
switch runtimeGOARCH {
case "amd64":
return ARCH_X86_64
case "arm64":
return ARCH_AARCH64
case "ppc64le":
return ARCH_PPC64LE
case "s390x":
return ARCH_S390X
default:
panic("unsupported architecture")
}
return FromString(runtimeGOARCH)
}
func IsX86_64() bool {
@ -82,3 +72,7 @@ func IsPPC() bool {
func IsS390x() bool {
return Current() == ARCH_S390X
}
func IsRISCV64() bool {
return Current() == ARCH_RISCV64
}

View file

@ -29,6 +29,7 @@ import (
"slices"
"github.com/google/uuid"
"github.com/osbuild/images/pkg/arch"
)
const (
@ -40,26 +41,29 @@ const (
// rounded to the next MiB.
DefaultGrainBytes = uint64(1048576) // 1 MiB
// UUIDs for GPT disks
BIOSBootPartitionGUID = "21686148-6449-6E6F-744E-656564454649"
BIOSBootPartitionUUID = "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
// GUIDs (partition types) for partitions on GPT disks
// The SD_GPT name next to each constant is the partition type shown in
// systemd-gpt-auto-generator(8) (if present)
// See also
// - https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/
// - https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
BIOSBootPartitionGUID = "21686148-6449-6E6F-744E-656564454649"
FilesystemDataGUID = "0FC63DAF-8483-4772-8E79-3D69D8477DE4" // SD_GPT_LINUX_GENERIC
EFISystemPartitionGUID = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" // SD_GPT_ESP
LVMPartitionGUID = "E6D6D379-F507-44C2-A23C-238F2A3DF928"
PRePartitionGUID = "9E1A2D38-C612-4316-AA26-8B49521E5A8B"
SwapPartitionGUID = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F" // SD_GPT_SWAP
XBootLDRPartitionGUID = "BC13C2FF-59E6-4262-A352-B275FD6F7172" // SD_GPT_XBOOTLDR
FilesystemDataGUID = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
FilesystemDataUUID = "CB07C243-BC44-4717-853E-28852021225B"
RootPartitionX86_64GUID = "4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709" // SD_GPT_ROOT_X86_64
RootPartitionAarch64GUID = "B921B045-1DF0-41C3-AF44-4C6F280D3FAE" // SD_GPT_ROOT_ARM64
RootPartitionPpc64leGUID = "C31C45E6-3F39-412E-80FB-4809C4980599" // SD_GPT_ROOT_PPC64_LE
RootPartitionS390xGUID = "5EEAD9A9-FE09-4A1E-A1D7-520D00531306" // SD_GPT_ROOT_S390X
EFISystemPartitionGUID = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
EFISystemPartitionUUID = "68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
EFIFilesystemUUID = "7B77-95E7"
LVMPartitionGUID = "E6D6D379-F507-44C2-A23C-238F2A3DF928"
PRePartitionGUID = "9E1A2D38-C612-4316-AA26-8B49521E5A8B"
RootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562"
SwapPartitionGUID = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F"
// Extended Boot Loader Partition
XBootLDRPartitionGUID = "BC13C2FF-59E6-4262-A352-B275FD6F7172"
UsrPartitionX86_64GUID = "8484680C-9521-48C6-9C11-B0720656F69E" // SD_GPT_USR_X86_64
UsrPartitionAarch64GUID = "B0E01050-EE5F-4390-949A-9101B17104E9" // SD_GPT_USR_ARM64
UsrPartitionPpc64leGUID = "15BB03AF-77E7-4D4A-B12B-C0D084F7491C" // SD_GPT_USR_PPC64_LE
UsrPartitionS390xGUID = "8A4F5770-50AA-4ED3-874A-99B710DB6FEA" // SD_GPT_USR_S390X
// Partition type IDs for DOS disks
@ -86,38 +90,88 @@ const (
// Partition type ID for PRep on dos
PRepPartitionDOSID = "41"
// static UUIDs for partitions and filesystems
// NOTE(akoutsou): These are unnecessary and have stuck around since the
// beginning where (I believe) the goal was to have predictable,
// reproducible partition tables. They might be removed soon in favour of
// proper, random UUIDs, with reproducibility being controlled by fixing
// rng seeds.
BIOSBootPartitionUUID = "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
RootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562"
DataPartitionUUID = "CB07C243-BC44-4717-853E-28852021225B"
EFISystemPartitionUUID = "68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
EFIFilesystemUUID = "7B77-95E7"
)
// pt type -> type -> ID mapping for convenience
var idMap = map[PartitionTableType]map[string]string{
PT_DOS: {
"bios": BIOSBootPartitionDOSID,
"boot": FilesystemLinuxDOSID,
"data": FilesystemLinuxDOSID,
"esp": EFISystemPartitionDOSID,
"lvm": LVMPartitionDOSID,
"swap": SwapPartitionDOSID,
},
PT_GPT: {
"bios": BIOSBootPartitionGUID,
"boot": XBootLDRPartitionGUID,
"data": FilesystemDataGUID,
"esp": EFISystemPartitionGUID,
"lvm": LVMPartitionGUID,
"swap": SwapPartitionGUID,
},
}
func getPartitionTypeIDfor(ptType PartitionTableType, partTypeName string) (string, error) {
ptMap, ok := idMap[ptType]
if !ok {
func getPartitionTypeIDfor(ptType PartitionTableType, partTypeName string, architecture arch.Arch) (string, error) {
switch ptType {
case PT_DOS:
switch partTypeName {
case "bios":
return BIOSBootPartitionDOSID, nil
case "data", "boot", "root", "usr":
return FilesystemLinuxDOSID, nil
case "esp":
return EFISystemPartitionDOSID, nil
case "lvm":
return LVMPartitionDOSID, nil
case "swap":
return SwapPartitionDOSID, nil
default:
return "", fmt.Errorf("unknown or unsupported partition type name: %s", partTypeName)
}
case PT_GPT:
switch partTypeName {
case "bios":
return BIOSBootPartitionGUID, nil
case "boot":
return XBootLDRPartitionGUID, nil
case "data":
return FilesystemDataGUID, nil
case "esp":
return EFISystemPartitionGUID, nil
case "lvm":
return LVMPartitionGUID, nil
case "swap":
return SwapPartitionGUID, nil
case "root":
switch architecture {
case arch.ARCH_X86_64:
return RootPartitionX86_64GUID, nil
case arch.ARCH_AARCH64:
return RootPartitionAarch64GUID, nil
case arch.ARCH_PPC64LE:
return RootPartitionPpc64leGUID, nil
case arch.ARCH_S390X:
return RootPartitionS390xGUID, nil
case arch.ARCH_UNSET:
return "", fmt.Errorf("architecture must be specified for selecting GUID for %q partition", partTypeName)
default:
return "", fmt.Errorf("unknown or unsupported architecture enum value: %d", architecture)
}
case "usr":
switch architecture {
case arch.ARCH_X86_64:
return UsrPartitionX86_64GUID, nil
case arch.ARCH_AARCH64:
return UsrPartitionAarch64GUID, nil
case arch.ARCH_PPC64LE:
return UsrPartitionPpc64leGUID, nil
case arch.ARCH_S390X:
return UsrPartitionS390xGUID, nil
case arch.ARCH_UNSET:
return "", fmt.Errorf("architecture must be specified for selecting GUID for %q partition", partTypeName)
default:
return "", fmt.Errorf("unknown or unsupported architecture enum value: %d", architecture)
}
default:
return "", fmt.Errorf("unknown or unsupported partition type name: %s", partTypeName)
}
default:
return "", fmt.Errorf("unknown or unsupported partition table enum: %d", ptType)
}
id, ok := ptMap[partTypeName]
if !ok {
return "", fmt.Errorf("unknown or unsupported partition type name: %s", partTypeName)
}
return id, nil
}
// FSType is the filesystem type enum.

View file

@ -7,6 +7,7 @@ import (
"github.com/google/uuid"
"github.com/osbuild/images/pkg/arch"
"github.com/osbuild/images/pkg/blueprint"
"github.com/osbuild/images/pkg/datasizes"
"github.com/osbuild/images/pkg/platform"
@ -97,7 +98,7 @@ const (
// containing the root filesystem is grown to fill any left over space on the
// partition table. Logical Volumes are not grown to fill the space in the
// Volume Group since they are trivial to grow on a live system.
func NewPartitionTable(basePT *PartitionTable, mountpoints []blueprint.FilesystemCustomization, imageSize uint64, mode PartitioningMode, requiredSizes map[string]uint64, rng *rand.Rand) (*PartitionTable, error) {
func NewPartitionTable(basePT *PartitionTable, mountpoints []blueprint.FilesystemCustomization, imageSize uint64, mode PartitioningMode, architecture arch.Arch, requiredSizes map[string]uint64, rng *rand.Rand) (*PartitionTable, error) {
newPT := basePT.Clone().(*PartitionTable)
if basePT.features().LVM && (mode == RawPartitioningMode || mode == BtrfsPartitioningMode) {
@ -126,7 +127,7 @@ func NewPartitionTable(basePT *PartitionTable, mountpoints []blueprint.Filesyste
return nil, err
}
} else if ensureBtrfs {
err := newPT.ensureBtrfs()
err := newPT.ensureBtrfs(architecture)
if err != nil {
return nil, err
}
@ -767,7 +768,7 @@ func (pt *PartitionTable) ensureLVM() error {
// ensureBtrfs will ensure that the root partition is on a btrfs subvolume, i.e. if
// it currently is not, it will wrap it in one
func (pt *PartitionTable) ensureBtrfs() error {
func (pt *PartitionTable) ensureBtrfs(architecture arch.Arch) error {
rootPath := entityPath(pt, "/")
if rootPath == nil {
@ -823,7 +824,7 @@ func (pt *PartitionTable) ensureBtrfs() error {
// reset the btrfs partition size - it will be grown later
part.Size = 0
part.Type, err = getPartitionTypeIDfor(pt.Type, "data")
part.Type, err = getPartitionTypeIDfor(pt.Type, "root", architecture)
if err != nil {
return fmt.Errorf("error converting partition table to btrfs: %w", err)
}
@ -942,7 +943,7 @@ func (pt *PartitionTable) GetMountpointSize(mountpoint string) (uint64, error) {
// - At the end of the plain partitions.
//
// For LVM and Plain, the fsType argument must be a valid filesystem type.
func EnsureRootFilesystem(pt *PartitionTable, defaultFsType FSType) error {
func EnsureRootFilesystem(pt *PartitionTable, defaultFsType FSType, architecture arch.Arch) error {
// collect all labels and subvolume names to avoid conflicts
subvolNames := make(map[string]bool)
labels := make(map[string]bool)
@ -1015,7 +1016,7 @@ func EnsureRootFilesystem(pt *PartitionTable, defaultFsType FSType) error {
return fmt.Errorf("error creating root partition: %w", err)
}
partType, err := getPartitionTypeIDfor(pt.Type, "data")
partType, err := getPartitionTypeIDfor(pt.Type, "root", architecture)
if err != nil {
return fmt.Errorf("error creating root partition: %w", err)
}
@ -1053,7 +1054,7 @@ func addBootPartition(pt *PartitionTable, bootFsType FSType) error {
return fmt.Errorf("error creating boot partition: %w", err)
}
partType, err := getPartitionTypeIDfor(pt.Type, "boot")
partType, err := getPartitionTypeIDfor(pt.Type, "boot", arch.ARCH_UNSET)
if err != nil {
return fmt.Errorf("error creating boot partition: %w", err)
}
@ -1117,7 +1118,7 @@ func addPartitionsForBootMode(pt *PartitionTable, bootMode platform.BootMode) er
}
func mkBIOSBoot(ptType PartitionTableType) (Partition, error) {
partType, err := getPartitionTypeIDfor(ptType, "bios")
partType, err := getPartitionTypeIDfor(ptType, "bios", arch.ARCH_UNSET)
if err != nil {
return Partition{}, fmt.Errorf("error creating BIOS boot partition: %w", err)
}
@ -1130,7 +1131,7 @@ func mkBIOSBoot(ptType PartitionTableType) (Partition, error) {
}
func mkESP(size uint64, ptType PartitionTableType) (Partition, error) {
partType, err := getPartitionTypeIDfor(ptType, "esp")
partType, err := getPartitionTypeIDfor(ptType, "esp", arch.ARCH_UNSET)
if err != nil {
return Partition{}, fmt.Errorf("error creating EFI system partition: %w", err)
}
@ -1151,7 +1152,7 @@ func mkESP(size uint64, ptType PartitionTableType) (Partition, error) {
}
type CustomPartitionTableOptions struct {
// PartitionTableType must be either "dos" or "gpt". Defaults to "gpt".
// PartitionTableType must be either PT_DOS or PT_GPT. Defaults to PT_GPT.
PartitionTableType PartitionTableType
// BootMode determines the types of boot-related partitions that are
@ -1176,6 +1177,12 @@ type CustomPartitionTableOptions struct {
// mountpoint's partition is the sum of all the required directory sizes it
// will contain.
RequiredMinSizes map[string]uint64
// Architecture of the hardware that will use the partition table. This is
// used to select appropriate partition types for GPT formatted disks to
// enable automatic discovery. It has no effect and is not required when
// the PartitionTableType is PT_DOS.
Architecture arch.Arch
}
// Returns the default filesystem type if the fstype is empty. If both are
@ -1283,7 +1290,7 @@ func NewCustomPartitionTable(customizations *blueprint.DiskCustomization, option
}
}
if err := EnsureRootFilesystem(pt, options.DefaultFSType); err != nil {
if err := EnsureRootFilesystem(pt, options.DefaultFSType, options.Architecture); err != nil {
return nil, fmt.Errorf("%s %w", errPrefix, err)
}
@ -1316,6 +1323,10 @@ func addPlainPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
// all user-defined partitions are data partitions except boot and swap
var typeName string
switch {
case partition.Mountpoint == "/":
typeName = "root"
case partition.Mountpoint == "/usr":
typeName = "usr"
case partition.Mountpoint == "/boot":
typeName = "boot"
case fstype == "swap":
@ -1324,7 +1335,7 @@ func addPlainPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
typeName = "data"
}
partType, err := getPartitionTypeIDfor(pt.Type, typeName)
partType, err := getPartitionTypeIDfor(pt.Type, typeName, options.Architecture)
if err != nil {
return fmt.Errorf("error getting partition type ID for %q: %w", partition.Mountpoint, err)
}
@ -1408,7 +1419,7 @@ func addLVMPartition(pt *PartitionTable, partition blueprint.PartitionCustomizat
}
// create partition for volume group
partType, err := getPartitionTypeIDfor(pt.Type, "lvm")
partType, err := getPartitionTypeIDfor(pt.Type, "lvm", arch.ARCH_UNSET)
if err != nil {
return fmt.Errorf("error creating lvm partition %q: %w", vgname, err)
}
@ -1437,7 +1448,7 @@ func addBtrfsPartition(pt *PartitionTable, partition blueprint.PartitionCustomiz
}
// create partition for btrfs volume
partType, err := getPartitionTypeIDfor(pt.Type, "data")
partType, err := getPartitionTypeIDfor(pt.Type, "data", arch.ARCH_UNSET)
if err != nil {
return fmt.Errorf("error creating btrfs partition: %w", err)
}

View file

@ -475,6 +475,18 @@ var defaultDistroImageConfig = &distro.ImageConfig{
DefaultOSCAPDatastream: common.ToPtr(oscap.DefaultFedoraDatastream()),
}
func defaultDistroInstallerConfig(d *distribution) *distro.InstallerConfig {
config := distro.InstallerConfig{}
// In Fedora 42 the ifcfg module was replaced by net-lib.
if common.VersionLessThan(d.osVersion, "42") {
config.AdditionalDracutModules = append(config.AdditionalDracutModules, "ifcfg")
} else {
config.AdditionalDracutModules = append(config.AdditionalDracutModules, "net-lib")
}
return &config
}
func getISOLabelFunc(variant string) isoLabelFunc {
const ISO_LABEL = "%s-%s-%s-%s"
@ -646,6 +658,11 @@ func newDistro(version int) distro.Distro {
name: arch.ARCH_S390X.String(),
}
riscv64 := architecture{
name: arch.ARCH_RISCV64.String(),
distro: &rd,
}
ociImgType := qcow2ImgType
ociImgType.name = "oci"
@ -746,6 +763,12 @@ func newDistro(version int) distro.Distro {
containerImgType,
wslImgType,
)
// add distro installer configuration to all installer types
distroInstallerConfig := defaultDistroInstallerConfig(&rd)
liveInstallerImgType.defaultInstallerConfig = distroInstallerConfig
imageInstallerImgType.defaultInstallerConfig = distroInstallerConfig
iotInstallerImgType.defaultInstallerConfig = distroInstallerConfig
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
@ -907,6 +930,7 @@ func newDistro(version int) distro.Distro {
minimalrawImgType,
)
iotSimplifiedInstallerImgType.defaultInstallerConfig = distroInstallerConfig
x86_64.addImageTypes(
&platform.X86{
BasePlatform: platform.BasePlatform{
@ -1039,7 +1063,12 @@ func newDistro(version int) distro.Distro {
containerImgType,
)
rd.addArches(x86_64, aarch64, ppc64le, s390x)
riscv64.addImageTypes(
&platform.RISCV64{},
containerImgType,
)
rd.addArches(x86_64, aarch64, ppc64le, s390x, riscv64)
return &rd
}

View file

@ -411,6 +411,16 @@ func liveInstallerImage(workload workload.Workload,
img.Locale = *locale
}
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
return img, nil
}
@ -464,6 +474,16 @@ func imageInstallerImage(workload workload.Workload,
img.ExtraBasePackages = packageSets[installerPkgsKey]
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
d := t.arch.distro
img.Product = d.product
@ -671,6 +691,16 @@ func iotInstallerImage(workload workload.Workload,
anaconda.ModuleUsers,
}...)
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
img.Product = d.product
img.Variant = "IoT"
img.OSVersion = d.osVersion
@ -794,6 +824,16 @@ func iotSimplifiedInstallerImage(workload workload.Workload,
}
}
installerConfig, err := t.getDefaultInstallerConfig()
if err != nil {
return nil, err
}
if installerConfig != nil {
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
img.AdditionalDracutModules = append(img.AdditionalDracutModules, "dbus-broker")
d := t.arch.distro

View file

@ -30,24 +30,25 @@ type packageSetFunc func(t *imageType) rpmmd.PackageSet
type isoLabelFunc func(t *imageType) string
type imageType struct {
arch *architecture
platform platform.Platform
environment environment.Environment
workload workload.Workload
name string
nameAliases []string
filename string
compression string
mimeType string
packageSets map[string]packageSetFunc
defaultImageConfig *distro.ImageConfig
kernelOptions string
defaultSize uint64
buildPipelines []string
payloadPipelines []string
exports []string
image imageFunc
isoLabel isoLabelFunc
arch *architecture
platform platform.Platform
environment environment.Environment
workload workload.Workload
name string
nameAliases []string
filename string
compression string
mimeType string
packageSets map[string]packageSetFunc
defaultImageConfig *distro.ImageConfig
defaultInstallerConfig *distro.InstallerConfig
kernelOptions string
defaultSize uint64
buildPipelines []string
payloadPipelines []string
exports []string
image imageFunc
isoLabel isoLabelFunc
// bootISO: installable ISO
bootISO bool
@ -166,6 +167,7 @@ func (t *imageType) getPartitionTable(
BootMode: t.BootMode(),
DefaultFSType: disk.FS_EXT4, // default fs type for Fedora
RequiredMinSizes: t.requiredPartitionSizes,
Architecture: t.platform.GetArch(),
}
return disk.NewCustomPartitionTable(partitioning, partOptions, rng)
}
@ -182,7 +184,7 @@ func (t *imageType) getPartitionTable(
}
mountpoints := customizations.GetFilesystems()
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, partitioningMode, t.requiredPartitionSizes, rng)
return disk.NewPartitionTable(&basePartitionTable, mountpoints, imageSize, partitioningMode, t.platform.GetArch(), t.requiredPartitionSizes, rng)
}
func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
@ -195,6 +197,14 @@ func (t *imageType) getDefaultImageConfig() *distro.ImageConfig {
}
func (t *imageType) getDefaultInstallerConfig() (*distro.InstallerConfig, error) {
if !t.bootISO {
return nil, fmt.Errorf("image type %q is not an ISO", t.name)
}
return t.defaultInstallerConfig, nil
}
func (t *imageType) PartitionType() disk.PartitionTableType {
basePartitionTable, exists := t.basePartitionTables[t.arch.Name()]
if !exists {

View file

@ -35,7 +35,7 @@ var defaultBasePartitionTables = distro.BasePartitionTableMap{
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",
@ -81,7 +81,7 @@ var defaultBasePartitionTables = distro.BasePartitionTableMap{
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",
@ -192,7 +192,7 @@ var minimalrawPartitionTables = distro.BasePartitionTableMap{
{
Size: 1 * datasizes.GibiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",
@ -287,7 +287,7 @@ var iotBasePartitionTables = distro.BasePartitionTableMap{
{
Size: 1 * datasizes.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",
@ -381,7 +381,7 @@ var iotSimplifiedInstallerPartitionTables = distro.BasePartitionTableMap{
{
Size: 1 * datasizes.GibiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",
@ -451,7 +451,7 @@ var iotSimplifiedInstallerPartitionTables = distro.BasePartitionTableMap{
{
Size: 1 * datasizes.GibiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "ext4",
Mountpoint: "/boot",

View file

@ -506,8 +506,8 @@ func EdgeInstallerImage(workload workload.Workload,
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
img.AdditionalDrivers = installerConfig.AdditionalDrivers
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
instCust, err := customizations.GetInstaller()
@ -660,7 +660,8 @@ func EdgeSimplifiedInstallerImage(workload workload.Workload,
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
return img, nil
@ -706,8 +707,8 @@ func ImageInstallerImage(workload workload.Workload,
}
if installerConfig != nil {
img.AdditionalDracutModules = installerConfig.AdditionalDracutModules
img.AdditionalDrivers = installerConfig.AdditionalDrivers
img.AdditionalDracutModules = append(img.AdditionalDracutModules, installerConfig.AdditionalDracutModules...)
img.AdditionalDrivers = append(img.AdditionalDrivers, installerConfig.AdditionalDrivers...)
}
instCust, err := customizations.GetInstaller()

View file

@ -217,11 +217,12 @@ func (t *ImageType) GetPartitionTable(
BootMode: t.BootMode(),
DefaultFSType: disk.FS_XFS, // default fs type for RHEL
RequiredMinSizes: requiredDirectorySizes,
Architecture: t.platform.GetArch(),
}
return disk.NewCustomPartitionTable(partitioning, partOptions, rng)
}
return disk.NewPartitionTable(&basePartitionTable, customizations.GetFilesystems(), imageSize, options.PartitioningMode, nil, rng)
return disk.NewPartitionTable(&basePartitionTable, customizations.GetFilesystems(), imageSize, options.PartitioningMode, t.platform.GetArch(), nil, rng)
}
func (t *ImageType) getDefaultImageConfig() *distro.ImageConfig {

View file

@ -202,7 +202,7 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
{
Size: 1 * datasizes.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -312,7 +312,7 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
{
Size: 1 * datasizes.GibiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -53,6 +53,7 @@ func mkImageInstallerImgType() *rhel.ImageType {
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
"net-lib",
},
AdditionalDrivers: []string{
"ipmi_devintf",

View file

@ -305,7 +305,7 @@ func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool)
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -37,7 +37,7 @@ func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -306,7 +306,7 @@ func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool)
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -416,7 +416,7 @@ func azureRhuiBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool)
{
Size: 500 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -32,6 +32,7 @@ func mkImageInstaller() *rhel.ImageType {
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
"ifcfg",
},
}

View file

@ -130,6 +130,7 @@ func mkEdgeInstallerImgType(rd *rhel.Distribution) *rhel.ImageType {
AdditionalDracutModules: []string{
"prefixdevname",
"prefixdevname-tools",
"ifcfg",
},
}
it.RPMOSTree = true

View file

@ -161,7 +161,7 @@ func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: 384 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -224,7 +224,7 @@ func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: 384 * datasizes.MebiByte,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -373,7 +373,7 @@ func ec2PartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: aarch64BootSize,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -215,7 +215,7 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
{
Size: bootSize,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -324,7 +324,7 @@ func azureInternalBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, b
{
Size: bootSize,
Type: disk.FilesystemDataGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -54,6 +54,7 @@ func mkImageInstallerImgType() *rhel.ImageType {
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
"ifcfg",
},
AdditionalDrivers: []string{
"cuse",

View file

@ -148,6 +148,7 @@ func mkEdgeInstallerImgType() *rhel.ImageType {
"nvdimm", // non-volatile DIMM firmware (provides nfit, cuse, and nd_e820)
"prefixdevname",
"prefixdevname-tools",
"ifcfg",
},
AdditionalDrivers: []string{
"cuse",
@ -393,7 +394,7 @@ func minimalrawPartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: bootSize,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -441,7 +442,7 @@ func minimalrawPartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: bootSize,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -501,7 +502,7 @@ func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: 384 * datasizes.MebiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -572,7 +573,7 @@ func edgeBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: 384 * datasizes.MebiByte,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -41,7 +41,7 @@ func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: bootSize,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -94,7 +94,7 @@ func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: bootSize,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",
@ -141,7 +141,7 @@ func defaultBasePartitionTables(t *rhel.ImageType) (disk.PartitionTable, bool) {
{
Size: bootSize,
Type: disk.XBootLDRPartitionGUID,
UUID: disk.FilesystemDataUUID,
UUID: disk.DataPartitionUUID,
Payload: &disk.Filesystem{
Type: "xfs",
Mountpoint: "/boot",

View file

@ -38,11 +38,13 @@ type AnacondaContainerInstaller struct {
Filename string
AdditionalDracutModules []string
AdditionalAnacondaModules []string
DisabledAnacondaModules []string
AdditionalDrivers []string
FIPS bool
AdditionalDracutModules []string
AdditionalDrivers []string
FIPS bool
Kickstart *kickstart.Options
@ -92,7 +94,6 @@ func (img *AnacondaContainerInstaller) InstantiateManifest(m *manifest.Manifest,
anacondaPipeline.Variant = img.Variant
anacondaPipeline.Biosdevname = (img.Platform.GetArch() == arch.ARCH_X86_64)
anacondaPipeline.Checkpoint()
anacondaPipeline.AdditionalDracutModules = img.AdditionalDracutModules
anacondaPipeline.AdditionalAnacondaModules = img.AdditionalAnacondaModules
anacondaPipeline.DisabledAnacondaModules = img.DisabledAnacondaModules
if img.FIPS {
@ -101,6 +102,7 @@ func (img *AnacondaContainerInstaller) InstantiateManifest(m *manifest.Manifest,
anaconda.ModuleSecurity,
)
}
anacondaPipeline.AdditionalDracutModules = img.AdditionalDracutModules
anacondaPipeline.AdditionalDrivers = img.AdditionalDrivers
anacondaPipeline.Locale = img.Locale

View file

@ -40,6 +40,9 @@ type AnacondaLiveInstaller struct {
// Locale for the installer. This should be set to the same locale as the
// ISO OS payload, if known.
Locale string
AdditionalDracutModules []string
AdditionalDrivers []string
}
func NewAnacondaLiveInstaller() *AnacondaLiveInstaller {

View file

@ -42,11 +42,13 @@ type AnacondaOSTreeInstaller struct {
Filename string
AdditionalDracutModules []string
AdditionalAnacondaModules []string
DisabledAnacondaModules []string
AdditionalDrivers []string
FIPS bool
AdditionalDracutModules []string
AdditionalDrivers []string
FIPS bool
// Uses the old, deprecated, Anaconda config option "kickstart-modules".
// Only for RHEL 8.

View file

@ -71,8 +71,9 @@ type AnacondaTarInstaller struct {
AdditionalKernelOpts []string
AdditionalAnacondaModules []string
DisabledAnacondaModules []string
AdditionalDracutModules []string
AdditionalDrivers []string
AdditionalDracutModules []string
AdditionalDrivers []string
// Uses the old, deprecated, Anaconda config option "kickstart-modules".
// Only for RHEL 8.

View file

@ -59,6 +59,7 @@ type OSTreeSimplifiedInstaller struct {
IgnitionEmbedded *ignition.EmbeddedOptions
AdditionalDracutModules []string
AdditionalDrivers []string
}
func NewOSTreeSimplifiedInstaller(rawImage *OSTreeDiskImage, installDevice string) *OSTreeSimplifiedInstaller {
@ -98,6 +99,7 @@ func (img *OSTreeSimplifiedInstaller) InstantiateManifest(m *manifest.Manifest,
coiPipeline.Biosdevname = (img.Platform.GetArch() == arch.ARCH_X86_64)
coiPipeline.Variant = img.Variant
coiPipeline.AdditionalDracutModules = img.AdditionalDracutModules
coiPipeline.AdditionalDrivers = img.AdditionalDrivers
var isoLabel string

View file

@ -422,7 +422,6 @@ func dracutStageOptions(kernelVer string, biosdevname bool, additionalModules []
"convertfs",
"network-manager",
"network",
"ifcfg",
"url-lib",
"drm",
"plymouth",

View file

@ -42,6 +42,7 @@ type CoreOSInstaller struct {
Ignition *ignition.EmbeddedOptions
AdditionalDracutModules []string
AdditionalDrivers []string
}
// NewCoreOSInstaller creates an CoreOS installer pipeline object.
@ -206,10 +207,12 @@ func (p *CoreOSInstaller) serialize() osbuild.Pipeline {
if p.Biosdevname {
dracutModules = append(dracutModules, "biosdevname")
}
drivers := p.AdditionalDrivers
dracutStageOptions := &osbuild.DracutStageOptions{
Kernel: []string{p.kernelVer},
Modules: dracutModules,
Install: []string{"/.buildstamp"},
Kernel: []string{p.kernelVer},
Modules: dracutModules,
Install: []string{"/.buildstamp"},
AddDrivers: drivers,
}
if p.FDO != nil && p.FDO.DiunPubKeyRootCerts != "" {
pipeline.AddStage(osbuild.NewFDOStageForRootCerts(p.FDO.DiunPubKeyRootCerts))

View file

@ -8,6 +8,8 @@ import (
"os"
"os/exec"
"strings"
"github.com/osbuild/images/pkg/datasizes"
)
// Run an instance of osbuild, returning a parsed osbuild.Result.
@ -34,6 +36,11 @@ func RunOSBuild(manifest []byte, store, outputDirectory string, exports, checkpo
cmd.Args = append(cmd.Args, "--checkpoint", checkpoint)
}
if len(checkpoints) > 0 {
// set the cache-max-size to a reasonable size that the checkpoints actually get stored
cmd.Args = append(cmd.Args, "--cache-max-size", fmt.Sprint(20*datasizes.GiB))
}
if result {
cmd.Args = append(cmd.Args, "--json")
cmd.Stdout = &stdoutBuffer

View file

@ -0,0 +1,25 @@
package platform
import (
"github.com/osbuild/images/pkg/arch"
)
type RISCV64 struct {
BasePlatform
}
func (p *RISCV64) GetArch() arch.Arch {
return arch.ARCH_RISCV64
}
func (p *RISCV64) GetPackages() []string {
packages := p.BasePlatform.FirmwarePackages
return packages
}
func (p *RISCV64) GetBuildPackages() []string {
var packages []string
return packages
}

View file

@ -1,4 +1,5 @@
![cobra logo](assets/CobraMain.png)
![cobra logo](https://github.com/user-attachments/assets/cbc3adf8-0dff-46e9-a88d-5e2d971c169e)
Cobra is a library for creating powerful modern CLI applications.
@ -105,7 +106,7 @@ go install github.com/spf13/cobra-cli@latest
For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)
For complete details on using the Cobra library, please read the [The Cobra User Guide](site/content/user_guide.md).
For complete details on using the Cobra library, please read [The Cobra User Guide](site/content/user_guide.md).
# License

View file

@ -35,7 +35,7 @@ const (
// This function can be called multiple times before and/or after completions are added to
// the array. Each time this function is called with the same array, the new
// ActiveHelp line will be shown below the previous ones when completion is triggered.
func AppendActiveHelp(compArray []string, activeHelpStr string) []string {
func AppendActiveHelp(compArray []Completion, activeHelpStr string) []Completion {
return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr))
}

View file

@ -146,7 +146,7 @@ __%[1]s_process_completion_results() {
if (((directive & shellCompDirectiveFilterFileExt) != 0)); then
# File extension filtering
local fullFilter filter filteringCmd
local fullFilter="" filter filteringCmd
# Do not use quotes around the $completions variable or else newline
# characters will be kept.
@ -177,20 +177,71 @@ __%[1]s_process_completion_results() {
__%[1]s_handle_special_char "$cur" =
# Print the activeHelp statements before we finish
if ((${#activeHelp[*]} != 0)); then
printf "\n";
printf "%%s\n" "${activeHelp[@]}"
printf "\n"
__%[1]s_handle_activeHelp
}
# The prompt format is only available from bash 4.4.
# We test if it is available before using it.
if (x=${PS1@P}) 2> /dev/null; then
printf "%%s" "${PS1@P}${COMP_LINE[@]}"
else
# Can't print the prompt. Just print the
# text the user had typed, it is workable enough.
printf "%%s" "${COMP_LINE[@]}"
__%[1]s_handle_activeHelp() {
# Print the activeHelp statements
if ((${#activeHelp[*]} != 0)); then
if [ -z $COMP_TYPE ]; then
# Bash v3 does not set the COMP_TYPE variable.
printf "\n";
printf "%%s\n" "${activeHelp[@]}"
printf "\n"
__%[1]s_reprint_commandLine
return
fi
# Only print ActiveHelp on the second TAB press
if [ $COMP_TYPE -eq 63 ]; then
printf "\n"
printf "%%s\n" "${activeHelp[@]}"
if ((${#COMPREPLY[*]} == 0)); then
# When there are no completion choices from the program, file completion
# may kick in if the program has not disabled it; in such a case, we want
# to know if any files will match what the user typed, so that we know if
# there will be completions presented, so that we know how to handle ActiveHelp.
# To find out, we actually trigger the file completion ourselves;
# the call to _filedir will fill COMPREPLY if files match.
if (((directive & shellCompDirectiveNoFileComp) == 0)); then
__%[1]s_debug "Listing files"
_filedir
fi
fi
if ((${#COMPREPLY[*]} != 0)); then
# If there are completion choices to be shown, print a delimiter.
# Re-printing the command-line will automatically be done
# by the shell when it prints the completion choices.
printf -- "--"
else
# When there are no completion choices at all, we need
# to re-print the command-line since the shell will
# not be doing it itself.
__%[1]s_reprint_commandLine
fi
elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ]; then
# For completion type: menu-complete/menu-complete-backward and insert-completions
# the completions are immediately inserted into the command-line, so we first
# print the activeHelp message and reprint the command-line since the shell won't.
printf "\n"
printf "%%s\n" "${activeHelp[@]}"
__%[1]s_reprint_commandLine
fi
fi
}
__%[1]s_reprint_commandLine() {
# The prompt format is only available from bash 4.4.
# We test if it is available before using it.
if (x=${PS1@P}) 2> /dev/null; then
printf "%%s" "${PS1@P}${COMP_LINE[@]}"
else
# Can't print the prompt. Just print the
# text the user had typed, it is workable enough.
printf "%%s" "${COMP_LINE[@]}"
fi
}
@ -201,6 +252,8 @@ __%[1]s_extract_activeHelp() {
local endIndex=${#activeHelpMarker}
while IFS='' read -r comp; do
[[ -z $comp ]] && continue
if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then
comp=${comp:endIndex}
__%[1]s_debug "ActiveHelp found: $comp"
@ -223,16 +276,21 @@ __%[1]s_handle_completion_types() {
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
local tab=$'\t' comp
while IFS='' read -r comp; do
[[ -z $comp ]] && continue
# Strip any description
comp=${comp%%%%$tab*}
# Only consider the completions that match
if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
done < <(printf "%%s\n" "${completions[@]}")
# If there are no completions, we don't need to do anything
(( ${#completions[@]} == 0 )) && return 0
local tab=$'\t'
# Strip any description and escape the completion to handled special characters
IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]%%%%$tab*}")
# Only consider the completions that match
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
# compgen looses the escaping so we need to escape all completions again since they will
# all be inserted on the command-line.
IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}")
;;
*)
@ -243,11 +301,25 @@ __%[1]s_handle_completion_types() {
}
__%[1]s_handle_standard_completion_case() {
local tab=$'\t' comp
local tab=$'\t'
# If there are no completions, we don't need to do anything
(( ${#completions[@]} == 0 )) && return 0
# Short circuit to optimize if we don't have descriptions
if [[ "${completions[*]}" != *$tab* ]]; then
IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
# First, escape the completions to handle special characters
IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]}")
# Only consider the completions that match what the user typed
IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}")
# compgen looses the escaping so, if there is only a single completion, we need to
# escape it again because it will be inserted on the command-line. If there are multiple
# completions, we don't want to escape them because they will be printed in a list
# and we don't want to show escape characters in that list.
if (( ${#COMPREPLY[@]} == 1 )); then
COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]}")
fi
return 0
fi
@ -256,23 +328,39 @@ __%[1]s_handle_standard_completion_case() {
# Look for the longest completion so that we can format things nicely
while IFS='' read -r compline; do
[[ -z $compline ]] && continue
# Strip any description before checking the length
comp=${compline%%%%$tab*}
# Before checking if the completion matches what the user typed,
# we need to strip any description and escape the completion to handle special
# characters because those escape characters are part of what the user typed.
# Don't call "printf" in a sub-shell because it will be much slower
# since we are in a loop.
printf -v comp "%%q" "${compline%%%%$tab*}" &>/dev/null || comp=$(printf "%%q" "${compline%%%%$tab*}")
# Only consider the completions that match
[[ $comp == "$cur"* ]] || continue
# The completions matches. Add it to the list of full completions including
# its description. We don't escape the completion because it may get printed
# in a list if there are more than one and we don't want show escape characters
# in that list.
COMPREPLY+=("$compline")
# Strip any description before checking the length, and again, don't escape
# the completion because this length is only used when printing the completions
# in a list and we don't want show escape characters in that list.
comp=${compline%%%%$tab*}
if ((${#comp}>longest)); then
longest=${#comp}
fi
done < <(printf "%%s\n" "${completions[@]}")
# If there is a single completion left, remove the description text
# If there is a single completion left, remove the description text and escape any special characters
if ((${#COMPREPLY[*]} == 1)); then
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
comp="${COMPREPLY[0]%%%%$tab*}"
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
COMPREPLY[0]=$comp
else # Format the descriptions
COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]%%%%$tab*}")
__%[1]s_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}"
else
# Format the descriptions
__%[1]s_format_comp_descriptions $longest
fi
}

View file

@ -176,12 +176,16 @@ func rpad(s string, padding int) string {
return fmt.Sprintf(formattedString, s)
}
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) error {
t := template.New("top")
t.Funcs(templateFuncs)
template.Must(t.Parse(text))
return t.Execute(w, data)
func tmpl(text string) *tmplFunc {
return &tmplFunc{
tmpl: text,
fn: func(w io.Writer, data interface{}) error {
t := template.New("top")
t.Funcs(templateFuncs)
template.Must(t.Parse(text))
return t.Execute(w, data)
},
}
}
// ld compares two strings and returns the levenshtein distance between them.

View file

@ -33,6 +33,9 @@ import (
const (
FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra"
CommandDisplayNameAnnotation = "cobra_annotation_command_display_name"
helpFlagName = "help"
helpCommandName = "help"
)
// FParseErrWhitelist configures Flag parse errors to be ignored
@ -80,11 +83,11 @@ type Command struct {
Example string
// ValidArgs is list of all valid non-flag arguments that are accepted in shell completions
ValidArgs []string
ValidArgs []Completion
// ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion.
// It is a dynamic version of using ValidArgs.
// Only one of ValidArgs and ValidArgsFunction can be used for a command.
ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
ValidArgsFunction CompletionFunc
// Expected arguments
Args PositionalArgs
@ -168,12 +171,12 @@ type Command struct {
// usageFunc is usage func defined by user.
usageFunc func(*Command) error
// usageTemplate is usage template defined by user.
usageTemplate string
usageTemplate *tmplFunc
// flagErrorFunc is func defined by user and it's called when the parsing of
// flags returns an error.
flagErrorFunc func(*Command, error) error
// helpTemplate is help template defined by user.
helpTemplate string
helpTemplate *tmplFunc
// helpFunc is help func defined by user.
helpFunc func(*Command, []string)
// helpCommand is command with usage 'help'. If it's not defined by user,
@ -186,7 +189,7 @@ type Command struct {
completionCommandGroupID string
// versionTemplate is the version template defined by user.
versionTemplate string
versionTemplate *tmplFunc
// errPrefix is the error message prefix defined by user.
errPrefix string
@ -281,6 +284,7 @@ func (c *Command) SetArgs(a []string) {
// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
//
// Deprecated: Use SetOut and/or SetErr instead
func (c *Command) SetOutput(output io.Writer) {
c.outWriter = output
@ -312,7 +316,11 @@ func (c *Command) SetUsageFunc(f func(*Command) error) {
// SetUsageTemplate sets usage template. Can be defined by Application.
func (c *Command) SetUsageTemplate(s string) {
c.usageTemplate = s
if s == "" {
c.usageTemplate = nil
return
}
c.usageTemplate = tmpl(s)
}
// SetFlagErrorFunc sets a function to generate an error when flag parsing
@ -348,12 +356,20 @@ func (c *Command) SetCompletionCommandGroupID(groupID string) {
// SetHelpTemplate sets help template to be used. Application can use it to set custom template.
func (c *Command) SetHelpTemplate(s string) {
c.helpTemplate = s
if s == "" {
c.helpTemplate = nil
return
}
c.helpTemplate = tmpl(s)
}
// SetVersionTemplate sets version template to be used. Application can use it to set custom template.
func (c *Command) SetVersionTemplate(s string) {
c.versionTemplate = s
if s == "" {
c.versionTemplate = nil
return
}
c.versionTemplate = tmpl(s)
}
// SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix.
@ -434,7 +450,8 @@ func (c *Command) UsageFunc() (f func(*Command) error) {
}
return func(c *Command) error {
c.mergePersistentFlags()
err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c)
fn := c.getUsageTemplateFunc()
err := fn(c.OutOrStderr(), c)
if err != nil {
c.PrintErrln(err)
}
@ -442,6 +459,19 @@ func (c *Command) UsageFunc() (f func(*Command) error) {
}
}
// getUsageTemplateFunc returns the usage template function for the command
// going up the command tree if necessary.
func (c *Command) getUsageTemplateFunc() func(w io.Writer, data interface{}) error {
if c.usageTemplate != nil {
return c.usageTemplate.fn
}
if c.HasParent() {
return c.parent.getUsageTemplateFunc()
}
return defaultUsageFunc
}
// Usage puts out the usage for the command.
// Used when a user provides invalid input.
// Can be defined by user by overriding UsageFunc.
@ -460,15 +490,30 @@ func (c *Command) HelpFunc() func(*Command, []string) {
}
return func(c *Command, a []string) {
c.mergePersistentFlags()
fn := c.getHelpTemplateFunc()
// The help should be sent to stdout
// See https://github.com/spf13/cobra/issues/1002
err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c)
err := fn(c.OutOrStdout(), c)
if err != nil {
c.PrintErrln(err)
}
}
}
// getHelpTemplateFunc returns the help template function for the command
// going up the command tree if necessary.
func (c *Command) getHelpTemplateFunc() func(w io.Writer, data interface{}) error {
if c.helpTemplate != nil {
return c.helpTemplate.fn
}
if c.HasParent() {
return c.parent.getHelpTemplateFunc()
}
return defaultHelpFunc
}
// Help puts out the help for the command.
// Used when a user calls help [command].
// Can be defined by user by overriding HelpFunc.
@ -543,71 +588,55 @@ func (c *Command) NamePadding() int {
}
// UsageTemplate returns usage template for the command.
// This function is kept for backwards-compatibility reasons.
func (c *Command) UsageTemplate() string {
if c.usageTemplate != "" {
return c.usageTemplate
if c.usageTemplate != nil {
return c.usageTemplate.tmpl
}
if c.HasParent() {
return c.parent.UsageTemplate()
}
return `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}
{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}
Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
return defaultUsageTemplate
}
// HelpTemplate return help template for the command.
// This function is kept for backwards-compatibility reasons.
func (c *Command) HelpTemplate() string {
if c.helpTemplate != "" {
return c.helpTemplate
if c.helpTemplate != nil {
return c.helpTemplate.tmpl
}
if c.HasParent() {
return c.parent.HelpTemplate()
}
return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
return defaultHelpTemplate
}
// VersionTemplate return version template for the command.
// This function is kept for backwards-compatibility reasons.
func (c *Command) VersionTemplate() string {
if c.versionTemplate != "" {
return c.versionTemplate
if c.versionTemplate != nil {
return c.versionTemplate.tmpl
}
if c.HasParent() {
return c.parent.VersionTemplate()
}
return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
`
return defaultVersionTemplate
}
// getVersionTemplateFunc returns the version template function for the command
// going up the command tree if necessary.
func (c *Command) getVersionTemplateFunc() func(w io.Writer, data interface{}) error {
if c.versionTemplate != nil {
return c.versionTemplate.fn
}
if c.HasParent() {
return c.parent.getVersionTemplateFunc()
}
return defaultVersionFunc
}
// ErrPrefix return error message prefix for the command
@ -894,7 +923,7 @@ func (c *Command) execute(a []string) (err error) {
// If help is called, regardless of other flags, return we want help.
// Also say we need help if the command isn't runnable.
helpVal, err := c.Flags().GetBool("help")
helpVal, err := c.Flags().GetBool(helpFlagName)
if err != nil {
// should be impossible to get here as we always declare a help
// flag in InitDefaultHelpFlag()
@ -914,7 +943,8 @@ func (c *Command) execute(a []string) (err error) {
return err
}
if versionVal {
err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c)
fn := c.getVersionTemplateFunc()
err := fn(c.OutOrStdout(), c)
if err != nil {
c.Println(err)
}
@ -1068,12 +1098,6 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
// initialize help at the last point to allow for user overriding
c.InitDefaultHelpCmd()
// initialize completion at the last point to allow for user overriding
c.InitDefaultCompletionCmd()
// Now that all commands have been created, let's make sure all groups
// are properly created also
c.checkCommandGroups()
args := c.args
@ -1082,9 +1106,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
args = os.Args[1:]
}
// initialize the hidden command to be used for shell completion
// initialize the __complete command to be used for shell completion
c.initCompleteCmd(args)
// initialize the default completion command
c.InitDefaultCompletionCmd(args...)
// Now that all commands have been created, let's make sure all groups
// are properly created also
c.checkCommandGroups()
var flags []string
if c.TraverseChildren {
cmd, flags, err = c.Traverse(args)
@ -1187,16 +1218,16 @@ func (c *Command) checkCommandGroups() {
// If c already has help flag, it will do nothing.
func (c *Command) InitDefaultHelpFlag() {
c.mergePersistentFlags()
if c.Flags().Lookup("help") == nil {
if c.Flags().Lookup(helpFlagName) == nil {
usage := "help for "
name := c.displayName()
name := c.DisplayName()
if name == "" {
usage += "this command"
} else {
usage += name
}
c.Flags().BoolP("help", "h", false, usage)
_ = c.Flags().SetAnnotation("help", FlagSetByCobraAnnotation, []string{"true"})
c.Flags().BoolP(helpFlagName, "h", false, usage)
_ = c.Flags().SetAnnotation(helpFlagName, FlagSetByCobraAnnotation, []string{"true"})
}
}
@ -1215,7 +1246,7 @@ func (c *Command) InitDefaultVersionFlag() {
if c.Name() == "" {
usage += "this command"
} else {
usage += c.Name()
usage += c.DisplayName()
}
if c.Flags().ShorthandLookup("v") == nil {
c.Flags().BoolP("version", "v", false, usage)
@ -1239,9 +1270,9 @@ func (c *Command) InitDefaultHelpCmd() {
Use: "help [command]",
Short: "Help about any command",
Long: `Help provides help for any command in the application.
Simply type ` + c.displayName() + ` help [path to command] for full details.`,
ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
var completions []string
Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,
ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) {
var completions []Completion
cmd, _, e := c.Root().Find(args)
if e != nil {
return nil, ShellCompDirectiveNoFileComp
@ -1253,7 +1284,7 @@ Simply type ` + c.displayName() + ` help [path to command] for full details.`,
for _, subCmd := range cmd.Commands() {
if subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand {
if strings.HasPrefix(subCmd.Name(), toComplete) {
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short))
}
}
}
@ -1430,10 +1461,12 @@ func (c *Command) CommandPath() string {
if c.HasParent() {
return c.Parent().CommandPath() + " " + c.Name()
}
return c.displayName()
return c.DisplayName()
}
func (c *Command) displayName() string {
// DisplayName returns the name to display in help text. Returns command Name()
// If CommandDisplayNameAnnoation is not set
func (c *Command) DisplayName() string {
if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok {
return displayName
}
@ -1443,7 +1476,7 @@ func (c *Command) displayName() string {
// UseLine puts out the full usage for a given command (including parents).
func (c *Command) UseLine() string {
var useline string
use := strings.Replace(c.Use, c.Name(), c.displayName(), 1)
use := strings.Replace(c.Use, c.Name(), c.DisplayName(), 1)
if c.HasParent() {
useline = c.parent.CommandPath() + " " + use
} else {
@ -1649,7 +1682,7 @@ func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) f
// to this command (local and persistent declared here and by all parents).
func (c *Command) Flags() *flag.FlagSet {
if c.flags == nil {
c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
if c.flagErrorBuf == nil {
c.flagErrorBuf = new(bytes.Buffer)
}
@ -1664,7 +1697,7 @@ func (c *Command) Flags() *flag.FlagSet {
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
persistentFlags := c.PersistentFlags()
out := flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
out := flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
c.LocalFlags().VisitAll(func(f *flag.Flag) {
if persistentFlags.Lookup(f.Name) == nil {
out.AddFlag(f)
@ -1679,7 +1712,7 @@ func (c *Command) LocalFlags() *flag.FlagSet {
c.mergePersistentFlags()
if c.lflags == nil {
c.lflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.lflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
if c.flagErrorBuf == nil {
c.flagErrorBuf = new(bytes.Buffer)
}
@ -1707,7 +1740,7 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
c.mergePersistentFlags()
if c.iflags == nil {
c.iflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.iflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
if c.flagErrorBuf == nil {
c.flagErrorBuf = new(bytes.Buffer)
}
@ -1736,7 +1769,7 @@ func (c *Command) NonInheritedFlags() *flag.FlagSet {
// PersistentFlags returns the persistent FlagSet specifically set in the current command.
func (c *Command) PersistentFlags() *flag.FlagSet {
if c.pflags == nil {
c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
if c.flagErrorBuf == nil {
c.flagErrorBuf = new(bytes.Buffer)
}
@ -1749,9 +1782,9 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
func (c *Command) ResetFlags() {
c.flagErrorBuf = new(bytes.Buffer)
c.flagErrorBuf.Reset()
c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
c.flags.SetOutput(c.flagErrorBuf)
c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
c.pflags.SetOutput(c.flagErrorBuf)
c.lflags = nil
@ -1868,7 +1901,7 @@ func (c *Command) mergePersistentFlags() {
// If c.parentsPflags == nil, it makes new.
func (c *Command) updateParentsPflags() {
if c.parentsPflags == nil {
c.parentsPflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError)
c.parentsPflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError)
c.parentsPflags.SetOutput(c.flagErrorBuf)
c.parentsPflags.SortFlags = false
}
@ -1894,3 +1927,141 @@ func commandNameMatches(s string, t string) bool {
return s == t
}
// tmplFunc holds a template and a function that will execute said template.
type tmplFunc struct {
tmpl string
fn func(io.Writer, interface{}) error
}
var defaultUsageTemplate = `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}
{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}
Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
// defaultUsageFunc is equivalent to executing defaultUsageTemplate. The two should be changed in sync.
func defaultUsageFunc(w io.Writer, in interface{}) error {
c := in.(*Command)
fmt.Fprint(w, "Usage:")
if c.Runnable() {
fmt.Fprintf(w, "\n %s", c.UseLine())
}
if c.HasAvailableSubCommands() {
fmt.Fprintf(w, "\n %s [command]", c.CommandPath())
}
if len(c.Aliases) > 0 {
fmt.Fprintf(w, "\n\nAliases:\n")
fmt.Fprintf(w, " %s", c.NameAndAliases())
}
if c.HasExample() {
fmt.Fprintf(w, "\n\nExamples:\n")
fmt.Fprintf(w, "%s", c.Example)
}
if c.HasAvailableSubCommands() {
cmds := c.Commands()
if len(c.Groups()) == 0 {
fmt.Fprintf(w, "\n\nAvailable Commands:")
for _, subcmd := range cmds {
if subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName {
fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short)
}
}
} else {
for _, group := range c.Groups() {
fmt.Fprintf(w, "\n\n%s", group.Title)
for _, subcmd := range cmds {
if subcmd.GroupID == group.ID && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) {
fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short)
}
}
}
if !c.AllChildCommandsHaveGroup() {
fmt.Fprintf(w, "\n\nAdditional Commands:")
for _, subcmd := range cmds {
if subcmd.GroupID == "" && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) {
fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short)
}
}
}
}
}
if c.HasAvailableLocalFlags() {
fmt.Fprintf(w, "\n\nFlags:\n")
fmt.Fprint(w, trimRightSpace(c.LocalFlags().FlagUsages()))
}
if c.HasAvailableInheritedFlags() {
fmt.Fprintf(w, "\n\nGlobal Flags:\n")
fmt.Fprint(w, trimRightSpace(c.InheritedFlags().FlagUsages()))
}
if c.HasHelpSubCommands() {
fmt.Fprintf(w, "\n\nAdditional help topcis:")
for _, subcmd := range c.Commands() {
if subcmd.IsAdditionalHelpTopicCommand() {
fmt.Fprintf(w, "\n %s %s", rpad(subcmd.CommandPath(), subcmd.CommandPathPadding()), subcmd.Short)
}
}
}
if c.HasAvailableSubCommands() {
fmt.Fprintf(w, "\n\nUse \"%s [command] --help\" for more information about a command.", c.CommandPath())
}
fmt.Fprintln(w)
return nil
}
var defaultHelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
// defaultHelpFunc is equivalent to executing defaultHelpTemplate. The two should be changed in sync.
func defaultHelpFunc(w io.Writer, in interface{}) error {
c := in.(*Command)
usage := c.Long
if usage == "" {
usage = c.Short
}
usage = trimRightSpace(usage)
if usage != "" {
fmt.Fprintln(w, usage)
fmt.Fprintln(w)
}
if c.Runnable() || c.HasSubCommands() {
fmt.Fprint(w, c.UsageString())
}
return nil
}
var defaultVersionTemplate = `{{with .DisplayName}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}}
`
// defaultVersionFunc is equivalent to executing defaultVersionTemplate. The two should be changed in sync.
func defaultVersionFunc(w io.Writer, in interface{}) error {
c := in.(*Command)
_, err := fmt.Fprintf(w, "%s version %s\n", c.DisplayName(), c.Version)
return err
}

View file

@ -35,7 +35,7 @@ const (
)
// Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it.
var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}
var flagCompletionFunctions = map[*pflag.Flag]CompletionFunc{}
// lock for reading and writing from flagCompletionFunctions
var flagCompletionMutex = &sync.RWMutex{}
@ -117,22 +117,50 @@ type CompletionOptions struct {
HiddenDefaultCmd bool
}
// Completion is a string that can be used for completions
//
// two formats are supported:
// - the completion choice
// - the completion choice with a textual description (separated by a TAB).
//
// [CompletionWithDesc] can be used to create a completion string with a textual description.
//
// Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used.
type Completion = string
// CompletionFunc is a function that provides completion results.
type CompletionFunc = func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective)
// CompletionWithDesc returns a [Completion] with a description by using the TAB delimited format.
func CompletionWithDesc(choice string, description string) Completion {
return choice + "\t" + description
}
// NoFileCompletions can be used to disable file completion for commands that should
// not trigger file completions.
func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
//
// This method satisfies [CompletionFunc].
// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].
func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) {
return nil, ShellCompDirectiveNoFileComp
}
// FixedCompletions can be used to create a completion function which always
// returns the same results.
func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
//
// This method returns a function that satisfies [CompletionFunc]
// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].
func FixedCompletions(choices []Completion, directive ShellCompDirective) CompletionFunc {
return func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) {
return choices, directive
}
}
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
//
// You can use pre-defined completion functions such as [FixedCompletions] or [NoFileCompletions],
// or you can define your own.
func (c *Command) RegisterFlagCompletionFunc(flagName string, f CompletionFunc) error {
flag := c.Flag(flagName)
if flag == nil {
return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName)
@ -148,7 +176,7 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman
}
// GetFlagCompletionFunc returns the completion function for the given flag of the command, if available.
func (c *Command) GetFlagCompletionFunc(flagName string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) {
func (c *Command) GetFlagCompletionFunc(flagName string) (CompletionFunc, bool) {
flag := c.Flag(flagName)
if flag == nil {
return nil, false
@ -270,7 +298,15 @@ func (c *Command) initCompleteCmd(args []string) {
}
}
func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) {
// SliceValue is a reduced version of [pflag.SliceValue]. It is used to detect
// flags that accept multiple values and therefore can provide completion
// multiple times.
type SliceValue interface {
// GetSlice returns the flag value list as an array of strings.
GetSlice() []string
}
func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCompDirective, error) {
// The last argument, which is not completely typed by the user,
// should not be part of the list of arguments
toComplete := args[len(args)-1]
@ -298,7 +334,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
}
if err != nil {
// Unable to find the real command. E.g., <program> someInvalidCmd <TAB>
return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs)
return c, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs)
}
finalCmd.ctx = c.ctx
@ -328,7 +364,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
// Parse the flags early so we can check if required flags are set
if err = finalCmd.ParseFlags(finalArgs); err != nil {
return finalCmd, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
return finalCmd, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error())
}
realArgCount := finalCmd.Flags().NArg()
@ -340,14 +376,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
if flagErr != nil {
// If error type is flagCompError and we don't want flagCompletion we should ignore the error
if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) {
return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr
return finalCmd, []Completion{}, ShellCompDirectiveDefault, flagErr
}
}
// Look for the --help or --version flags. If they are present,
// there should be no further completions.
if helpOrVersionFlagPresent(finalCmd) {
return finalCmd, []string{}, ShellCompDirectiveNoFileComp, nil
return finalCmd, []Completion{}, ShellCompDirectiveNoFileComp, nil
}
// We only remove the flags from the arguments if DisableFlagParsing is not set.
@ -376,11 +412,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
return finalCmd, subDir, ShellCompDirectiveFilterDirs, nil
}
// Directory completion
return finalCmd, []string{}, ShellCompDirectiveFilterDirs, nil
return finalCmd, []Completion{}, ShellCompDirectiveFilterDirs, nil
}
}
var completions []string
var completions []Completion
var directive ShellCompDirective
// Enforce flag groups before doing flag completions
@ -399,10 +435,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
// If we have not found any required flags, only then can we show regular flags
if len(completions) == 0 {
doCompleteFlags := func(flag *pflag.Flag) {
if !flag.Changed ||
_, acceptsMultiple := flag.Value.(SliceValue)
acceptsMultiple = acceptsMultiple ||
strings.Contains(flag.Value.Type(), "Slice") ||
strings.Contains(flag.Value.Type(), "Array") {
// If the flag is not already present, or if it can be specified multiple times (Array or Slice)
strings.Contains(flag.Value.Type(), "Array") ||
strings.HasPrefix(flag.Value.Type(), "stringTo")
if !flag.Changed || acceptsMultiple {
// If the flag is not already present, or if it can be specified multiple times (Array, Slice, or stringTo)
// we suggest it as a completion
completions = append(completions, getFlagNameCompletions(flag, toComplete)...)
}
@ -462,7 +502,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
for _, subCmd := range finalCmd.Commands() {
if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
if strings.HasPrefix(subCmd.Name(), toComplete) {
completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short))
}
directive = ShellCompDirectiveNoFileComp
}
@ -507,7 +547,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
}
// Find the completion function for the flag or command
var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)
var completionFn CompletionFunc
if flag != nil && flagCompletion {
flagCompletionMutex.RLock()
completionFn = flagCompletionFunctions[flag]
@ -518,7 +558,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
if completionFn != nil {
// Go custom completion defined for this flag or command.
// Call the registered completion function to get the completions.
var comps []string
var comps []Completion
comps, directive = completionFn(finalCmd, finalArgs, toComplete)
completions = append(completions, comps...)
}
@ -531,23 +571,23 @@ func helpOrVersionFlagPresent(cmd *Command) bool {
len(versionFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && versionFlag.Changed {
return true
}
if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil &&
if helpFlag := cmd.Flags().Lookup(helpFlagName); helpFlag != nil &&
len(helpFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && helpFlag.Changed {
return true
}
return false
}
func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []Completion {
if nonCompletableFlag(flag) {
return []string{}
return []Completion{}
}
var completions []string
var completions []Completion
flagName := "--" + flag.Name
if strings.HasPrefix(flagName, toComplete) {
// Flag without the =
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
completions = append(completions, CompletionWithDesc(flagName, flag.Usage))
// Why suggest both long forms: --flag and --flag= ?
// This forces the user to *always* have to type either an = or a space after the flag name.
@ -559,20 +599,20 @@ func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string {
// if len(flag.NoOptDefVal) == 0 {
// // Flag requires a value, so it can be suffixed with =
// flagName += "="
// completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
// completions = append(completions, CompletionWithDesc(flagName, flag.Usage))
// }
}
flagName = "-" + flag.Shorthand
if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) {
completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage))
completions = append(completions, CompletionWithDesc(flagName, flag.Usage))
}
return completions
}
func completeRequireFlags(finalCmd *Command, toComplete string) []string {
var completions []string
func completeRequireFlags(finalCmd *Command, toComplete string) []Completion {
var completions []Completion
doCompleteRequiredFlags := func(flag *pflag.Flag) {
if _, present := flag.Annotations[BashCompOneRequiredFlag]; present {
@ -687,8 +727,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p
// 1- the feature has been explicitly disabled by the program,
// 2- c has no subcommands (to avoid creating one),
// 3- c already has a 'completion' command provided by the program.
func (c *Command) InitDefaultCompletionCmd() {
if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() {
func (c *Command) InitDefaultCompletionCmd(args ...string) {
if c.CompletionOptions.DisableDefaultCmd {
return
}
@ -701,6 +741,16 @@ func (c *Command) InitDefaultCompletionCmd() {
haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions
// Special case to know if there are sub-commands or not.
hasSubCommands := false
for _, cmd := range c.commands {
if cmd.Name() != ShellCompRequestCmd && cmd.Name() != helpCommandName {
// We found a real sub-command (not 'help' or '__complete')
hasSubCommands = true
break
}
}
completionCmd := &Command{
Use: compCmdName,
Short: "Generate the autocompletion script for the specified shell",
@ -714,6 +764,22 @@ See each sub-command's help for details on how to use the generated script.
}
c.AddCommand(completionCmd)
if !hasSubCommands {
// If the 'completion' command will be the only sub-command,
// we only create it if it is actually being called.
// This avoids breaking programs that would suddenly find themselves with
// a subcommand, which would prevent them from accepting arguments.
// We also create the 'completion' command if the user is triggering
// shell completion for it (prog __complete completion '')
subCmd, cmdArgs, err := c.Find(args)
if err != nil || subCmd.Name() != compCmdName &&
!(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) {
// The completion command is not being called or being completed so we remove it.
c.RemoveCommand(completionCmd)
return
}
}
out := c.OutOrStdout()
noDesc := c.CompletionOptions.DisableDescriptions
shortDesc := "Generate the autocompletion script for %s"

View file

@ -162,7 +162,10 @@ filter __%[1]s_escapeStringWithSpecialChars {
if (-Not $Description) {
$Description = " "
}
@{Name="$Name";Description="$Description"}
New-Object -TypeName PSCustomObject -Property @{
Name = "$Name"
Description = "$Description"
}
}
@ -240,7 +243,12 @@ filter __%[1]s_escapeStringWithSpecialChars {
__%[1]s_debug "Only one completion left"
# insert space after value
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
} else {
$CompletionText
}
} else {
# Add the proper number of spaces to align the descriptions
@ -255,7 +263,12 @@ filter __%[1]s_escapeStringWithSpecialChars {
$Description = " ($($comp.Description))"
}
[System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
$CompletionText = "$($comp.Name)$Description"
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)")
} else {
$CompletionText
}
}
}
@ -264,7 +277,13 @@ filter __%[1]s_escapeStringWithSpecialChars {
# insert space after value
# MenuComplete will automatically show the ToolTip of
# the highlighted value at the bottom of the suggestions.
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
} else {
$CompletionText
}
}
# TabCompleteNext and in case we get something unknown
@ -272,7 +291,13 @@ filter __%[1]s_escapeStringWithSpecialChars {
# Like MenuComplete but we don't want to add a space here because
# the user need to press space anyway to get the completion.
# Description will not be shown because that's not possible with TabCompleteNext
[System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
$CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars)
if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){
[System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)")
} else {
$CompletionText
}
}
}

4
vendor/modules.txt vendored
View file

@ -1037,7 +1037,7 @@ github.com/oracle/oci-go-sdk/v54/identity
github.com/oracle/oci-go-sdk/v54/objectstorage
github.com/oracle/oci-go-sdk/v54/objectstorage/transfer
github.com/oracle/oci-go-sdk/v54/workrequests
# github.com/osbuild/images v0.117.0
# github.com/osbuild/images v0.118.0
## explicit; go 1.22.8
github.com/osbuild/images/data/repositories
github.com/osbuild/images/internal/common
@ -1176,7 +1176,7 @@ github.com/smallstep/pkcs7/internal/legacy/x509
# github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b
## explicit; go 1.12
github.com/sony/gobreaker
# github.com/spf13/cobra v1.8.1
# github.com/spf13/cobra v1.9.1
## explicit; go 1.15
github.com/spf13/cobra
# github.com/spf13/pflag v1.0.6