2026-01-06 09:48:38 +08:00
#include "common/printing.h"
#include "common/jsonconfig.h"
2026-05-28 15:58:08 +08:00
#include "common/strutil.h"
2022-10-08 17:41:25 +08:00
#include "detection/packages/packages.h"
2023-05-26 14:32:27 +08:00
#include "modules/packages/packages.h"
2021-02-18 22:25:36 +01:00
2026-03-29 09:28:49 +08:00
bool ffPrintPackages ( FFPackagesOptions * options ) {
2023-06-13 21:38:06 +08:00
FFPackagesResult counts = {};
ffStrbufInit ( & counts . pacmanBranch );
2022-04-21 17:59:26 +02:00
2023-10-29 19:37:31 +08:00
const char * error = ffDetectPackages ( & counts , options );
2023-06-13 21:38:06 +08:00
2026-03-29 09:28:49 +08:00
if ( error ) {
2026-08-14 23:33:54 +08:00
ffPrintError ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT , "%s" , error );
2025-08-18 13:38:30 +08:00
return false ;
2021-04-03 21:51:50 +02:00
}
2021-05-15 18:17:34 +02:00
2026-04-21 14:00:04 +08:00
if ( counts . all == 0 ) {
2026-08-14 23:33:54 +08:00
ffPrintError ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT , "No packages from known package managers found" );
2026-04-21 14:00:04 +08:00
return false ;
}
2025-07-18 15:55:33 +08:00
uint32_t nixAll = counts . nixDefault + counts . nixSystem + counts . nixUser ;
uint32_t flatpakAll = counts . flatpakSystem + counts . flatpakUser ;
uint32_t brewAll = counts . brew + counts . brewCask ;
uint32_t guixAll = counts . guixSystem + counts . guixUser + counts . guixHome ;
uint32_t hpkgAll = counts . hpkgSystem + counts . hpkgUser ;
uint32_t amAll = counts . amSystem + counts . amUser ;
2025-07-29 19:22:18 +08:00
uint32_t scoopAll = counts . scoopUser + counts . scoopGlobal ;
2025-07-18 15:55:33 +08:00
2026-03-29 09:28:49 +08:00
if ( options -> moduleArgs . outputFormat . length == 0 ) {
2026-08-14 23:33:54 +08:00
ffPrintLogoAndKey ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT );
2021-03-11 19:40:46 +01:00
2026-04-21 14:00:04 +08:00
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreate ();
2026-03-29 09:28:49 +08:00
#define FF_PRINT_PACKAGE_NAME(var, name) \
2026-04-21 14:00:04 +08:00
if (counts.var > 0) { \
ffStrbufAppendUInt(&output, counts.var); \
ffStrbufAppendS(&output, " (" name "), "); \
2026-03-29 09:28:49 +08:00
}
2022-10-13 21:43:31 +02:00
2026-03-29 09:28:49 +08:00
#define FF_PRINT_PACKAGE(name) FF_PRINT_PACKAGE_NAME(name, #name)
2021-03-11 19:40:46 +01:00
2026-04-21 14:00:04 +08:00
#define FF_PRINT_PACKAGE_ALL(name) \
if (name##All > 0) { \
ffStrbufAppendUInt(&output, name##All); \
ffStrbufAppendS(&output, " (" #name "), "); \
2026-03-29 09:28:49 +08:00
}
2025-07-18 15:55:33 +08:00
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_ALL ( am );
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( amSystem , "am" )
FF_PRINT_PACKAGE_NAME ( amUser , "appman" )
2025-07-18 15:55:33 +08:00
}
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( appimage )
2022-08-18 22:02:21 +02:00
FF_PRINT_PACKAGE ( apk )
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_ALL ( brew );
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( brew , "brew" )
FF_PRINT_PACKAGE_NAME ( brewCask , "brew-cask" )
2025-07-18 15:55:33 +08:00
}
2026-04-27 13:31:08 +02:00
FF_PRINT_PACKAGE ( cards )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( choco )
FF_PRINT_PACKAGE ( dpkg )
FF_PRINT_PACKAGE ( emerge )
FF_PRINT_PACKAGE ( eopkg )
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2025-07-18 15:55:33 +08:00
FF_PRINT_PACKAGE_ALL ( flatpak );
2026-04-21 14:00:04 +08:00
} else if ( counts . flatpakUser > 0 ) {
FF_PRINT_PACKAGE_NAME ( flatpakSystem , "flatpak-system" )
2025-07-18 15:55:33 +08:00
FF_PRINT_PACKAGE_NAME ( flatpakUser , "flatpak-user" )
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( flatpakSystem , "flatpak" )
2025-07-18 15:55:33 +08:00
}
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_ALL ( guix );
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( guixSystem , "guix-system" )
FF_PRINT_PACKAGE_NAME ( guixUser , "guix-user" )
FF_PRINT_PACKAGE_NAME ( guixHome , "guix-home" )
2025-07-29 19:22:18 +08:00
}
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_ALL ( hpkg )
} else if ( counts . hpkgUser > 0 ) {
FF_PRINT_PACKAGE_NAME ( hpkgSystem , "hpkg-system" )
FF_PRINT_PACKAGE_NAME ( hpkgUser , "hpkg-user" )
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( hpkgSystem , "hpkg" )
2025-07-18 15:55:33 +08:00
}
2026-06-22 02:23:21 -03:00
FF_PRINT_PACKAGE_NAME ( installrelease , "install-release" )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( kiss )
FF_PRINT_PACKAGE ( linglong )
2024-05-17 09:28:17 +08:00
FF_PRINT_PACKAGE ( lpkg )
FF_PRINT_PACKAGE ( lpkgbuild )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( macports )
FF_PRINT_PACKAGE ( mport )
FF_PRINT_PACKAGE ( moss )
2026-03-29 09:28:49 +08:00
if ( options -> combined ) {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_ALL ( nix );
2026-03-29 09:28:49 +08:00
} else {
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE_NAME ( nixSystem , "nix-system" )
FF_PRINT_PACKAGE_NAME ( nixUser , "nix-user" )
FF_PRINT_PACKAGE_NAME ( nixDefault , "nix-default" )
2025-07-18 15:55:33 +08:00
}
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( opkg )
if ( counts . pacman > 0 ) {
ffStrbufAppendF ( & output , "%u (pacman)" , counts . pacman );
if ( counts . pacmanBranch . length > 0 ) {
ffStrbufAppendC ( & output , '[' );
ffStrbufAppend ( & output , & counts . pacmanBranch );
ffStrbufAppendC ( & output , ']' );
}
ffStrbufAppendS ( & output , ", " );
};
2024-09-22 12:30:37 +08:00
FF_PRINT_PACKAGE ( pacstall )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( paludis )
2025-02-24 10:29:14 +03:00
FF_PRINT_PACKAGE ( pisi )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( pkg )
FF_PRINT_PACKAGE ( pkgsrc )
FF_PRINT_PACKAGE ( pkgtool )
2026-06-19 22:25:33 +03:00
FF_PRINT_PACKAGE ( porg )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( rpm )
if ( options -> combined ) {
FF_PRINT_PACKAGE_ALL ( scoop );
} else if ( counts . scoopGlobal > 0 ) {
FF_PRINT_PACKAGE_NAME ( scoopUser , "scoop-user" )
FF_PRINT_PACKAGE_NAME ( scoopGlobal , "scoop-global" )
} else {
FF_PRINT_PACKAGE_NAME ( scoopUser , "scoop" )
}
FF_PRINT_PACKAGE ( snap )
2025-04-05 21:39:27 +05:45
FF_PRINT_PACKAGE ( soar )
2026-04-21 14:00:04 +08:00
FF_PRINT_PACKAGE ( sorcery )
FF_PRINT_PACKAGE ( winget )
FF_PRINT_PACKAGE ( xbps )
2021-03-11 19:40:46 +01:00
2026-04-21 14:00:04 +08:00
assert ( output . length >= 2 ); // counts.all > 0 guarantees that at least one package count was printed, which guarantees that ", " was appended at least once
ffStrbufSubstrBefore ( & output , output . length - 1 );
output . chars [ output . length - 1 ] = '\n' ;
ffStrbufWriteTo ( & output , stdout );
2026-03-29 09:28:49 +08:00
} else {
2026-08-14 23:33:54 +08:00
FF_PRINT_FORMAT_CHECKED ( FF_MODULE_GET_DISPLAY_NAME ( Packages ),
2026-04-21 14:00:04 +08:00
0 ,
& options -> moduleArgs ,
FF_PRINT_TYPE_DEFAULT ,
(( FFformatarg []) {
FF_ARG ( counts . amSystem , "am-system" ),
FF_ARG ( counts . amUser , "am-user" ),
FF_ARG ( counts . appimage , "appimage" ),
FF_ARG ( counts . apk , "apk" ),
FF_ARG ( counts . brew , "brew" ),
FF_ARG ( counts . brewCask , "brew-cask" ),
2026-04-27 13:31:08 +02:00
FF_ARG ( counts . cards , "cards" ),
2026-04-21 14:00:04 +08:00
FF_ARG ( counts . choco , "choco" ),
FF_ARG ( counts . dpkg , "dpkg" ),
FF_ARG ( counts . emerge , "emerge" ),
FF_ARG ( counts . eopkg , "eopkg" ),
FF_ARG ( counts . flatpakSystem , "flatpak-system" ),
FF_ARG ( counts . flatpakUser , "flatpak-user" ),
FF_ARG ( counts . guixHome , "guix-home" ),
FF_ARG ( counts . guixSystem , "guix-system" ),
FF_ARG ( counts . guixUser , "guix-user" ),
FF_ARG ( counts . hpkgSystem , "hpkg-system" ),
FF_ARG ( counts . hpkgUser , "hpkg-user" ),
2026-06-22 02:23:21 -03:00
FF_ARG ( counts . installrelease , "install-release" ),
2026-04-21 14:00:04 +08:00
FF_ARG ( counts . kiss , "kiss" ),
FF_ARG ( counts . linglong , "linglong" ),
FF_ARG ( counts . lpkg , "lpkg" ),
FF_ARG ( counts . lpkgbuild , "lpkgbuild" ),
FF_ARG ( counts . macports , "macports" ),
FF_ARG ( counts . mport , "mport" ),
FF_ARG ( counts . moss , "moss" ),
FF_ARG ( counts . nixDefault , "nix-default" ),
FF_ARG ( counts . nixSystem , "nix-system" ),
FF_ARG ( counts . nixUser , "nix-user" ),
FF_ARG ( counts . opkg , "opkg" ),
FF_ARG ( counts . pacman , "pacman" ),
FF_ARG ( counts . pacmanBranch , "pacman-branch" ),
FF_ARG ( counts . pacstall , "pacstall" ),
FF_ARG ( counts . paludis , "paludis" ),
FF_ARG ( counts . pisi , "pisi" ),
FF_ARG ( counts . pkg , "pkg" ),
FF_ARG ( counts . pkgsrc , "pkgsrc" ),
FF_ARG ( counts . pkgtool , "pkgtool" ),
2026-06-19 22:25:33 +03:00
FF_ARG ( counts . porg , "porg" ),
2026-04-21 14:00:04 +08:00
FF_ARG ( counts . rpm , "rpm" ),
FF_ARG ( counts . scoopGlobal , "scoop-global" ),
FF_ARG ( counts . scoopUser , "scoop-user" ),
FF_ARG ( counts . snap , "snap" ),
FF_ARG ( counts . soar , "soar" ),
FF_ARG ( counts . sorcery , "sorcery" ),
FF_ARG ( counts . winget , "winget" ),
FF_ARG ( counts . xbps , "xbps" ),
2026-06-12 10:00:39 +08:00
FF_ARG ( brewAll , "brew-all" ),
FF_ARG ( flatpakAll , "flatpak-all" ),
FF_ARG ( guixAll , "guix-all" ),
FF_ARG ( hpkgAll , "hpkg-all" ),
FF_ARG ( nixAll , "nix-all" ),
FF_ARG ( counts . all , "all" ),
2026-04-21 14:00:04 +08:00
}));
2021-03-27 15:39:56 +01:00
}
2023-06-13 21:38:06 +08:00
ffStrbufDestroy ( & counts . pacmanBranch );
2025-08-18 13:38:30 +08:00
return true ;
2021-03-27 18:14:19 +01:00
}
2023-05-26 14:32:27 +08:00
2026-03-29 09:28:49 +08:00
void ffParsePackagesJsonObject ( FFPackagesOptions * options , yyjson_val * module ) {
2025-08-02 18:51:03 +08:00
yyjson_val * key , * val ;
2023-08-17 16:09:41 +08:00
size_t idx , max ;
2026-03-29 09:28:49 +08:00
yyjson_obj_foreach ( module , idx , max , key , val ) {
if ( ffJsonConfigParseModuleArgs ( key , val , & options -> moduleArgs )) {
2023-08-17 16:09:41 +08:00
continue ;
2026-03-29 09:28:49 +08:00
}
2023-05-26 14:32:27 +08:00
2026-06-04 15:45:21 +08:00
#if !FF_PACKAGES_REMOVE_DISABLED
2026-03-29 09:28:49 +08:00
if ( unsafe_yyjson_equals_str ( key , "disabled" )) {
if ( ! yyjson_is_null ( val ) && ! yyjson_is_arr ( val )) {
2026-08-14 23:33:54 +08:00
ffPrintError ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT , "Invalid JSON value for %s" , unsafe_yyjson_get_str ( key ));
2024-02-21 15:56:52 +08:00
continue ;
}
options -> disabled = FF_PACKAGES_FLAG_NONE ;
2026-03-29 09:28:49 +08:00
if ( yyjson_is_arr ( val )) {
2024-02-21 15:56:52 +08:00
yyjson_val * flagObj ;
size_t flagIdx , flagMax ;
2026-03-29 09:28:49 +08:00
yyjson_arr_foreach ( val , flagIdx , flagMax , flagObj ) {
if ( ! yyjson_is_str ( flagObj )) {
2026-08-14 23:33:54 +08:00
ffPrintError ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT , "Invalid JSON value for %s" , unsafe_yyjson_get_str ( key ));
2025-08-02 17:41:19 +08:00
continue ;
}
const char * flag = unsafe_yyjson_get_str ( flagObj );
2024-02-21 15:56:52 +08:00
2026-06-04 15:45:21 +08:00
#define FF_TEST_PACKAGE_NAME(name) \
else if (ffStrEqualsIgnCase(flag, #name)) { \
options->disabled |= FF_PACKAGES_FLAG_##name##_BIT; \
}
2026-03-29 09:28:49 +08:00
switch ( toupper ( flag [ 0 ])) {
case 'A' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( AM )
2026-04-21 11:02:19 +08:00
FF_TEST_PACKAGE_NAME ( APK )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( APPIMAGE )
2024-04-16 09:50:14 +08:00
break ;
2026-03-29 09:28:49 +08:00
case 'B' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( BREW )
break ;
2026-03-29 09:28:49 +08:00
case 'C' :
if ( false )
;
2026-04-27 13:31:08 +02:00
FF_TEST_PACKAGE_NAME ( CARDS )
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( CHOCO )
break ;
2026-03-29 09:28:49 +08:00
case 'D' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( DPKG )
break ;
2026-03-29 09:28:49 +08:00
case 'E' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( EMERGE )
FF_TEST_PACKAGE_NAME ( EOPKG )
break ;
2026-03-29 09:28:49 +08:00
case 'F' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( FLATPAK )
break ;
2026-03-29 09:28:49 +08:00
case 'G' :
if ( false )
;
2024-05-28 02:50:18 +02:00
FF_TEST_PACKAGE_NAME ( GUIX )
break ;
2026-03-29 09:28:49 +08:00
case 'H' :
if ( false )
;
2025-02-18 10:38:14 +08:00
FF_TEST_PACKAGE_NAME ( HPKG )
break ;
2026-06-22 02:23:21 -03:00
case 'I' :
if ( false )
;
FF_TEST_PACKAGE_NAME ( INSTALLRELEASE )
break ;
2026-03-29 09:28:49 +08:00
case 'K' :
if ( false )
;
2025-12-01 09:10:07 +08:00
FF_TEST_PACKAGE_NAME ( KISS )
break ;
2026-03-29 09:28:49 +08:00
case 'L' :
if ( false )
;
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( LINGLONG )
2024-05-16 22:19:26 -03:00
FF_TEST_PACKAGE_NAME ( LPKG )
FF_TEST_PACKAGE_NAME ( LPKGBUILD )
break ;
2026-03-29 09:28:49 +08:00
case 'M' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( MACPORTS )
2026-02-22 22:33:27 +08:00
FF_TEST_PACKAGE_NAME ( MOSS )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( MPORT )
2024-04-16 09:50:14 +08:00
break ;
2026-03-29 09:28:49 +08:00
case 'N' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( NIX )
break ;
2026-03-29 09:28:49 +08:00
case 'O' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( OPKG )
break ;
2026-03-29 09:28:49 +08:00
case 'P' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( PACMAN )
2024-09-22 12:30:37 +08:00
FF_TEST_PACKAGE_NAME ( PACSTALL )
FF_TEST_PACKAGE_NAME ( PALUDIS )
2025-02-24 10:29:14 +03:00
FF_TEST_PACKAGE_NAME ( PISI )
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( PKG )
2025-01-17 10:39:41 +08:00
FF_TEST_PACKAGE_NAME ( PKGSRC )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( PKGTOOL )
2026-06-19 22:25:33 +03:00
FF_TEST_PACKAGE_NAME ( PORG )
2024-04-16 09:50:14 +08:00
break ;
2026-03-29 09:28:49 +08:00
case 'R' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( RPM )
break ;
2026-03-29 09:28:49 +08:00
case 'S' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( SCOOP )
FF_TEST_PACKAGE_NAME ( SNAP )
2025-04-05 21:39:27 +05:45
FF_TEST_PACKAGE_NAME ( SOAR )
2024-04-30 20:25:04 -07:00
FF_TEST_PACKAGE_NAME ( SORCERY )
2024-04-16 09:50:14 +08:00
break ;
2026-03-29 09:28:49 +08:00
case 'W' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( WINGET )
break ;
2026-03-29 09:28:49 +08:00
case 'X' :
if ( false )
;
2024-04-16 09:50:14 +08:00
FF_TEST_PACKAGE_NAME ( XBPS )
break ;
}
2026-06-04 15:45:21 +08:00
#undef FF_TEST_PACKAGE_NAME
2024-02-21 15:56:52 +08:00
}
2024-04-16 10:12:11 +08:00
continue ;
2024-02-21 15:56:52 +08:00
}
2023-10-29 19:37:31 +08:00
}
2026-06-04 15:45:21 +08:00
#endif
2023-10-29 19:37:31 +08:00
2026-03-29 09:28:49 +08:00
if ( unsafe_yyjson_equals_str ( key , "combined" )) {
2025-07-18 15:55:33 +08:00
options -> combined = yyjson_get_bool ( val );
continue ;
}
2026-08-14 23:33:54 +08:00
ffPrintError ( FF_MODULE_GET_DISPLAY_NAME ( Packages ), 0 , & options -> moduleArgs , FF_PRINT_TYPE_DEFAULT , "Unknown JSON key %s" , unsafe_yyjson_get_str ( key ));
2023-05-26 14:32:27 +08:00
}
}
2023-09-08 15:44:44 +08:00
2026-03-29 09:28:49 +08:00
void ffGeneratePackagesJsonConfig ( FFPackagesOptions * options , yyjson_mut_doc * doc , yyjson_mut_val * module ) {
2025-08-04 16:46:28 +08:00
ffJsonConfigGenerateModuleArgsConfig ( doc , module , & options -> moduleArgs );
2023-10-24 14:41:29 +08:00
2026-06-04 15:45:21 +08:00
#if !FF_PACKAGES_REMOVE_DISABLED
2025-08-04 16:46:28 +08:00
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate ();
yyjson_mut_val * arr = yyjson_mut_obj_add_arr ( doc , module , "disabled" );
2026-06-04 15:45:21 +08:00
#define FF_TEST_PACKAGE_NAME(name) \
else if ((options->disabled & FF_PACKAGES_FLAG_##name##_BIT)) { \
ffStrbufSetS(&buf, #name); \
ffStrbufLowerCase(&buf); \
yyjson_mut_arr_add_strbuf(doc, arr, &buf); \
}
2026-03-29 09:28:49 +08:00
if ( false )
;
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( AM )
FF_TEST_PACKAGE_NAME ( APK )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( APPIMAGE )
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( BREW )
2026-04-27 13:31:08 +02:00
FF_TEST_PACKAGE_NAME ( CARDS )
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( CHOCO )
FF_TEST_PACKAGE_NAME ( DPKG )
FF_TEST_PACKAGE_NAME ( EMERGE )
FF_TEST_PACKAGE_NAME ( EOPKG )
FF_TEST_PACKAGE_NAME ( FLATPAK )
FF_TEST_PACKAGE_NAME ( GUIX )
FF_TEST_PACKAGE_NAME ( HPKG )
2025-12-01 09:10:07 +08:00
FF_TEST_PACKAGE_NAME ( KISS )
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( LINGLONG )
FF_TEST_PACKAGE_NAME ( LPKG )
FF_TEST_PACKAGE_NAME ( LPKGBUILD )
FF_TEST_PACKAGE_NAME ( MACPORTS )
2026-02-22 22:33:27 +08:00
FF_TEST_PACKAGE_NAME ( MOSS )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( MPORT )
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( NIX )
FF_TEST_PACKAGE_NAME ( OPKG )
FF_TEST_PACKAGE_NAME ( PACMAN )
FF_TEST_PACKAGE_NAME ( PACSTALL )
FF_TEST_PACKAGE_NAME ( PALUDIS )
FF_TEST_PACKAGE_NAME ( PISI )
FF_TEST_PACKAGE_NAME ( PKG )
FF_TEST_PACKAGE_NAME ( PKGSRC )
2026-04-21 14:00:04 +08:00
FF_TEST_PACKAGE_NAME ( PKGTOOL )
2026-06-19 22:25:33 +03:00
FF_TEST_PACKAGE_NAME ( PORG )
2025-08-04 16:46:28 +08:00
FF_TEST_PACKAGE_NAME ( RPM )
FF_TEST_PACKAGE_NAME ( SCOOP )
FF_TEST_PACKAGE_NAME ( SNAP )
FF_TEST_PACKAGE_NAME ( SOAR )
FF_TEST_PACKAGE_NAME ( SORCERY )
FF_TEST_PACKAGE_NAME ( WINGET )
FF_TEST_PACKAGE_NAME ( XBPS )
2026-06-04 15:45:21 +08:00
#undef FF_TEST_PACKAGE_NAME
#endif
2025-07-18 15:55:33 +08:00
2025-08-04 16:46:28 +08:00
yyjson_mut_obj_add_bool ( doc , module , "combined" , options -> combined );
2023-10-24 14:41:29 +08:00
}
2026-06-04 15:45:21 +08:00
bool ffGeneratePackagesJsonResult ( FFPackagesOptions * options , yyjson_mut_doc * doc , yyjson_mut_val * module ) {
2023-09-08 15:44:44 +08:00
FFPackagesResult counts = {};
ffStrbufInit ( & counts . pacmanBranch );
2023-10-29 19:37:31 +08:00
const char * error = ffDetectPackages ( & counts , options );
2023-09-08 15:44:44 +08:00
2026-03-29 09:28:49 +08:00
if ( error ) {
2023-09-08 15:44:44 +08:00
yyjson_mut_obj_add_str ( doc , module , "error" , error );
2025-08-18 13:38:30 +08:00
return false ;
2023-09-08 15:44:44 +08:00
}
yyjson_mut_val * obj = yyjson_mut_obj_add_obj ( doc , module , "result" );
2026-04-21 14:00:04 +08:00
yyjson_mut_obj_add_uint ( doc , obj , "all" , counts . all );
2023-09-08 15:44:44 +08:00
2026-04-21 14:00:04 +08:00
#define FF_APPEND_PACKAGE_COUNT(name) \
if (counts.name > 0) yyjson_mut_obj_add_uint(doc, obj, #name, counts.name);
2025-01-08 09:44:45 +08:00
FF_APPEND_PACKAGE_COUNT ( amSystem )
FF_APPEND_PACKAGE_COUNT ( amUser )
2026-04-21 11:02:19 +08:00
FF_APPEND_PACKAGE_COUNT ( appimage )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( apk )
FF_APPEND_PACKAGE_COUNT ( brew )
FF_APPEND_PACKAGE_COUNT ( brewCask )
2026-04-27 13:31:08 +02:00
FF_APPEND_PACKAGE_COUNT ( cards )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( choco )
FF_APPEND_PACKAGE_COUNT ( dpkg )
FF_APPEND_PACKAGE_COUNT ( emerge )
FF_APPEND_PACKAGE_COUNT ( eopkg )
FF_APPEND_PACKAGE_COUNT ( flatpakSystem )
FF_APPEND_PACKAGE_COUNT ( flatpakUser )
2026-04-21 14:00:04 +08:00
FF_APPEND_PACKAGE_COUNT ( guixHome )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( guixSystem )
FF_APPEND_PACKAGE_COUNT ( guixUser )
2025-02-18 10:38:14 +08:00
FF_APPEND_PACKAGE_COUNT ( hpkgSystem )
FF_APPEND_PACKAGE_COUNT ( hpkgUser )
2026-06-22 02:23:21 -03:00
FF_APPEND_PACKAGE_COUNT ( installrelease )
2026-02-22 22:33:27 +08:00
FF_APPEND_PACKAGE_COUNT ( kiss )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( linglong )
2026-04-21 14:00:04 +08:00
FF_APPEND_PACKAGE_COUNT ( lpkg )
FF_APPEND_PACKAGE_COUNT ( lpkgbuild )
2026-02-22 22:33:27 +08:00
FF_APPEND_PACKAGE_COUNT ( macports )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( mport )
2026-02-22 22:33:27 +08:00
FF_APPEND_PACKAGE_COUNT ( moss )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( nixDefault )
FF_APPEND_PACKAGE_COUNT ( nixSystem )
FF_APPEND_PACKAGE_COUNT ( nixUser )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( opkg )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( pacman )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( pacstall )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( paludis )
2025-02-24 10:29:14 +03:00
FF_APPEND_PACKAGE_COUNT ( pisi )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( pkg )
2025-01-17 10:39:41 +08:00
FF_APPEND_PACKAGE_COUNT ( pkgsrc )
2026-04-21 14:00:04 +08:00
FF_APPEND_PACKAGE_COUNT ( pkgtool )
2026-06-19 22:25:33 +03:00
FF_APPEND_PACKAGE_COUNT ( porg )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( rpm )
2025-07-29 19:22:18 +08:00
FF_APPEND_PACKAGE_COUNT ( scoopGlobal )
2026-04-21 14:00:04 +08:00
FF_APPEND_PACKAGE_COUNT ( scoopUser )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( snap )
2025-04-05 21:39:27 +05:45
FF_APPEND_PACKAGE_COUNT ( soar )
2024-11-10 23:32:22 +08:00
FF_APPEND_PACKAGE_COUNT ( sorcery )
2023-09-08 15:44:44 +08:00
FF_APPEND_PACKAGE_COUNT ( winget )
FF_APPEND_PACKAGE_COUNT ( xbps )
2026-04-21 14:00:04 +08:00
if ( counts . pacmanBranch . length > 0 ) {
yyjson_mut_obj_add_strbuf ( doc , obj , "pacmanBranch" , & counts . pacmanBranch );
}
2025-08-18 13:38:30 +08:00
return true ;
2023-09-08 15:44:44 +08:00
}
2023-10-07 13:40:40 +08:00
2026-03-29 09:28:49 +08:00
void ffInitPackagesOptions ( FFPackagesOptions * options ) {
2025-08-04 14:25:14 +08:00
ffOptionInitModuleArg ( & options -> moduleArgs , "" );
2026-06-04 15:45:21 +08:00
#if !FF_PACKAGES_REMOVE_DISABLED
2025-08-04 14:25:14 +08:00
options -> disabled = FF_PACKAGES_DISABLE_LIST ;
2026-06-04 15:45:21 +08:00
#endif
2025-08-04 14:25:14 +08:00
options -> combined = false ;
}
2026-03-29 09:28:49 +08:00
void ffDestroyPackagesOptions ( FFPackagesOptions * options ) {
2025-08-04 14:25:14 +08:00
ffOptionDestroyModuleArg ( & options -> moduleArgs );
}
2025-08-03 22:50:56 +08:00
FFModuleBaseInfo ffPackagesModuleInfo = {
2026-08-14 23:33:54 +08:00
. name = "Packages" ,
2024-12-11 10:47:02 +08:00
. description = "List installed package managers and count of installed packages" ,
2026-08-14 20:38:58 +08:00
. displayName = {
. en = "Packages" ,
2026-08-16 10:51:42 +08:00
. ar = "الحزم" ,
2026-08-21 10:19:06 +08:00
. cs = "Balíčky" ,
2026-08-14 20:38:58 +08:00
. de = "Pakete" ,
. es = "Paquetes" ,
. fr = "Paquets" ,
2026-08-20 16:25:32 +00:00
. gl = "Paquetes" ,
2026-08-16 10:51:42 +08:00
. he = "חבילות" ,
2026-08-21 10:19:06 +08:00
. id = "Paket" ,
2026-08-14 20:38:58 +08:00
. it = "Pacchetti" ,
. ja = "パッケージ" ,
. ko = "패키지" ,
. pl = "Pakiety" ,
2026-08-16 10:37:06 +08:00
. pt = "Pacotes" ,
2026-08-14 20:38:58 +08:00
. ru = "Пакеты" ,
2026-08-21 10:19:06 +08:00
. tr = "Paketler" ,
. uk = "Пакети" ,
. vi = "Gói phần mềm" ,
2026-08-14 20:38:58 +08:00
. zh_CN = "软件包" ,
. zh_TW = "軟體包" ,
},
2025-08-03 18:39:41 +08:00
. initOptions = ( void * ) ffInitPackagesOptions ,
. destroyOptions = ( void * ) ffDestroyPackagesOptions ,
2024-12-11 10:47:02 +08:00
. parseJsonObject = ( void * ) ffParsePackagesJsonObject ,
. printModule = ( void * ) ffPrintPackages ,
. generateJsonResult = ( void * ) ffGeneratePackagesJsonResult ,
. generateJsonConfig = ( void * ) ffGeneratePackagesJsonConfig ,
. formatArgs = FF_FORMAT_ARG_LIST ((( FFModuleFormatArg []) {
2026-04-21 14:00:04 +08:00
{ "Number of am-system packages" , "am-system" },
{ "Number of am-user (aka appman) packages" , "am-user" },
{ "Number of appimage packages" , "appimage" },
{ "Number of apk packages" , "apk" },
{ "Number of brew packages" , "brew" },
{ "Number of brew-cask packages" , "brew-cask" },
2026-04-27 13:31:08 +02:00
{ "Number of cards packages" , "cards" },
2026-04-21 14:00:04 +08:00
{ "Number of choco packages" , "choco" },
2026-03-30 10:27:23 +08:00
{ "Number of dpkg packages" , "dpkg" },
{ "Number of emerge packages" , "emerge" },
{ "Number of eopkg packages" , "eopkg" },
{ "Number of flatpak-system app packages" , "flatpak-system" },
{ "Number of flatpak-user app packages" , "flatpak-user" },
2026-04-21 14:00:04 +08:00
{ "Number of guix-home packages" , "guix-home" },
2026-03-30 10:27:23 +08:00
{ "Number of guix-system packages" , "guix-system" },
{ "Number of guix-user packages" , "guix-user" },
{ "Number of hpkg-system packages" , "hpkg-system" },
{ "Number of hpkg-user packages" , "hpkg-user" },
2026-06-22 02:23:21 -03:00
{ "Number of install-release packages" , "install-release" },
2026-03-30 10:27:23 +08:00
{ "Number of kiss packages" , "kiss" },
2026-04-21 14:00:04 +08:00
{ "Number of linglong packages" , "linglong" },
{ "Number of lpkg packages" , "lpkg" },
{ "Number of lpkgbuild packages" , "lpkgbuild" },
{ "Number of macports packages" , "macports" },
{ "Number of mport packages" , "mport" },
2026-03-30 10:27:23 +08:00
{ "Number of moss packages" , "moss" },
2026-04-21 14:00:04 +08:00
{ "Number of nix-default packages" , "nix-default" },
{ "Number of nix-system packages" , "nix-system" },
{ "Number of nix-user packages" , "nix-user" },
{ "Number of opkg packages" , "opkg" },
{ "Number of pacman packages" , "pacman" },
{ "Pacman branch on manjaro" , "pacman-branch" },
{ "Number of pacstall packages" , "pacstall" },
{ "Number of paludis packages" , "paludis" },
{ "Number of pisi packages" , "pisi" },
{ "Number of pkg packages" , "pkg" },
{ "Number of pkgsrc packages" , "pkgsrc" },
{ "Number of pkgtool packages" , "pkgtool" },
2026-06-19 22:25:33 +03:00
{ "Number of porg packages" , "porg" },
2026-04-21 14:00:04 +08:00
{ "Number of rpm packages" , "rpm" },
{ "Number of scoop-global packages" , "scoop-global" },
{ "Number of scoop-user packages" , "scoop-user" },
{ "Number of snap packages" , "snap" },
{ "Number of soar packages" , "soar" },
{ "Number of sorcery packages" , "sorcery" },
{ "Number of winget packages" , "winget" },
{ "Number of xbps packages" , "xbps" },
2026-06-12 10:00:39 +08:00
{ "Total number of all brew packages" , "brew-all" },
{ "Total number of all flatpak app packages" , "flatpak-all" },
{ "Total number of all guix packages" , "guix-all" },
{ "Total number of all hpkg packages" , "hpkg-all" },
{ "Total number of all nix packages" , "nix-all" },
{ "Number of all packages" , "all" },
2026-07-31 10:56:13 +08:00
})),
. defaultOrder = 14 ,
2026-03-30 10:17:45 +08:00
};