diff --git a/doc/json_schema.json b/doc/json_schema.json index a22deae4..080b7708 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1469,10 +1469,10 @@ "const": "packages", "description": "List installed package managers and count of installed packages" }, - "winget": { - "description": "Set if winget package count should be detected.\nNote this is very slow operation. Please make sure `winget list` works before enable this option\nWindows only", - "type": "boolean", - "default": false + "disabled": { + "description": "A colon separated list of package managers to be disabled when detecting", + "type": "string", + "default": "winget" }, "key": { "$ref": "#/$defs/key" diff --git a/src/data/help.json b/src/data/help.json index 23b701a8..1bda9745 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -1013,17 +1013,16 @@ } }, { - "long": "packages-winget", - "desc": "Set if winget package count should be detected", + "long": "packages-disabled", + "desc": "A colon separated list of package managers to be disabled when detecting", "remark": [ - "This option is extremely slow.", + "Some detection methods can be very slow.", "You may need to increase value of '--processing-timeout' to make it actually work.", - "Windows only" + "Use `--packages-disabled none` to enable all." ], "arg": { - "type": "bool", - "optional": true, - "default": false + "type": "string", + "default": "winget" } }, { diff --git a/src/detection/packages/packages_apple.c b/src/detection/packages/packages_apple.c index ef0b715e..e770f3f5 100644 --- a/src/detection/packages/packages_apple.c +++ b/src/detection/packages/packages_apple.c @@ -99,14 +99,16 @@ static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname) return num_elements; } -void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options) +void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) { - getBrewPackages(result); - result->macports = getMacPortsPackages(); - - FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(FASTFETCH_TARGET_DIR_ROOT); - result->nixDefault += getNixPackages(&baseDir, "/nix/var/nix/profiles/default"); - result->nixSystem += getNixPackages(&baseDir, "/run/current-system"); - ffStrbufSet(&baseDir, &instance.state.platform.homeDir); - result->nixUser = getNixPackages(&baseDir, "/.nix-profile"); + if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT)) getBrewPackages(result); + if (!(options->disabled & FF_PACKAGES_FLAG_MACPORTS_BIT)) result->macports = getMacPortsPackages(); + if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT)) + { + FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(FASTFETCH_TARGET_DIR_ROOT); + result->nixDefault += getNixPackages(&baseDir, "/nix/var/nix/profiles/default"); + result->nixSystem += getNixPackages(&baseDir, "/run/current-system"); + ffStrbufSet(&baseDir, &instance.state.platform.homeDir); + result->nixUser = getNixPackages(&baseDir, "/.nix-profile"); + } } diff --git a/src/detection/packages/packages_bsd.c b/src/detection/packages/packages_bsd.c index cb909145..5948d678 100644 --- a/src/detection/packages/packages_bsd.c +++ b/src/detection/packages/packages_bsd.c @@ -4,5 +4,6 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options) { - result->pkg = (uint32_t) ffSettingsGetSQLite3Int(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg/local.sqlite", "SELECT count(*) FROM packages"); + if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT)) + result->pkg = (uint32_t) ffSettingsGetSQLite3Int(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg/local.sqlite", "SELECT count(*) FROM packages"); } diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c index 8c838e31..194330fa 100644 --- a/src/detection/packages/packages_linux.c +++ b/src/detection/packages/packages_linux.c @@ -253,38 +253,47 @@ static uint32_t getRpmFromLibrpm(void) #endif //FF_HAVE_RPM -static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts) +static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) { - packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q"); - packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed"); - packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE"); - packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", DT_DIR); - packageCounts->flatpakSystem += getFlatpak(baseDir, "/var/lib/flatpak"); - packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default"); - packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system"); - packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR); - packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", DT_REG); - packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages"); - packageCounts->snap += getSnap(baseDir); - packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps"); - packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", DT_DIR); - packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", DT_DIR); - packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2"); - packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:"); // openwrt + if (!(options->disabled & FF_PACKAGES_FLAG_APK_BIT)) packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q"); + if (!(options->disabled & FF_PACKAGES_FLAG_DPKG_BIT)) packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed"); + if (!(options->disabled & FF_PACKAGES_FLAG_EMERGE_BIT)) packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE"); + if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT)) packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", DT_DIR); + if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) packageCounts->flatpakSystem += getFlatpak(baseDir, "/var/lib/flatpak"); + if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT)) + { + packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default"); + packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system"); + } + if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR); + if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", DT_REG); + if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages"); + if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir); + if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps"); + if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT)) + { + packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", DT_DIR); + packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", DT_DIR); + } + if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT)) packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2"); + if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT)) packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:"); // openwrt } -static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts) +static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) { - getPackageCounts(baseDir, packageCounts); + getPackageCounts(baseDir, packageCounts, options); - uint32_t baseDirLength = baseDir->length; - ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf"); - if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0) - ffStrbufAppendS(&packageCounts->pacmanBranch, "stable"); - ffStrbufSubstrBefore(baseDir, baseDirLength); + if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) + { + uint32_t baseDirLength = baseDir->length; + ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf"); + if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0) + ffStrbufAppendS(&packageCounts->pacmanBranch, "stable"); + ffStrbufSubstrBefore(baseDir, baseDirLength); + } } -static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* packageCounts) +static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) { uint32_t baseDirLength = baseDir->length; @@ -309,32 +318,34 @@ static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* package continue; ffStrbufAppendS(baseDir, entry->d_name); - getPackageCounts(baseDir, packageCounts); + getPackageCounts(baseDir, packageCounts, options); ffStrbufSubstrBefore(baseDir, baseDirLength2); } ffStrbufSubstrBefore(baseDir, baseDirLength); } -void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options) +void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) { FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512); ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT); if(ffStrbufIgnCaseEqualS(&ffDetectOS()->id, "bedrock")) - getPackageCountsBedrock(&baseDir, result); + getPackageCountsBedrock(&baseDir, result, options); else - getPackageCountsRegular(&baseDir, result); + getPackageCountsRegular(&baseDir, result, options); // If SQL failed, we can still try with librpm. // This is needed on openSUSE, which seems to use a proprietary database file // This method doesn't work on bedrock, so we do it here. #ifdef FF_HAVE_RPM - if(result->rpm == 0) + if(!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT) && result->rpm == 0) result->rpm = getRpmFromLibrpm(); #endif ffStrbufSet(&baseDir, &instance.state.platform.homeDir); - result->nixUser = getNixPackages(&baseDir, "/.nix-profile"); - result->flatpakUser = getFlatpak(&baseDir, "/.local/share/flatpak"); + if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT)) + result->nixUser = getNixPackages(&baseDir, "/.nix-profile"); + if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) + result->flatpakUser = getFlatpak(&baseDir, "/.local/share/flatpak"); } diff --git a/src/detection/packages/packages_windows.c b/src/detection/packages/packages_windows.c index 4bd845e2..b5c557a5 100644 --- a/src/detection/packages/packages_windows.c +++ b/src/detection/packages/packages_windows.c @@ -107,9 +107,8 @@ static void detectWinget(FFPackagesResult* result) void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) { - detectScoop(result); - detectChoco(result); - detectPacman(result); - if (options->winget) - detectWinget(result); + if (!(options->disabled & FF_PACKAGES_FLAG_SCOOP_BIT)) detectScoop(result); + if (!(options->disabled & FF_PACKAGES_FLAG_CHOCO_BIT)) detectChoco(result); + if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) detectPacman(result); + if (!(options->disabled & FF_PACKAGES_FLAG_WINGET_BIT)) detectWinget(result); } diff --git a/src/modules/packages/option.h b/src/modules/packages/option.h index afbbcccc..81b5a01b 100644 --- a/src/modules/packages/option.h +++ b/src/modules/packages/option.h @@ -4,12 +4,34 @@ #include "common/option.h" +typedef enum FFPackagesFlags +{ + FF_PACKAGES_FLAG_NONE = 0, + FF_PACKAGES_FLAG_APK_BIT = 1 << 0, + FF_PACKAGES_FLAG_BREW_BIT = 1 << 1, + FF_PACKAGES_FLAG_CHOCO_BIT = 1 << 2, + FF_PACKAGES_FLAG_DPKG_BIT = 1 << 3, + FF_PACKAGES_FLAG_EMERGE_BIT = 1 << 4, + FF_PACKAGES_FLAG_EOPKG_BIT = 1 << 5, + FF_PACKAGES_FLAG_FLATPAK_BIT = 1 << 6, + FF_PACKAGES_FLAG_NIX_BIT = 1 << 7, + FF_PACKAGES_FLAG_OPKG_BIT = 1 << 8, + FF_PACKAGES_FLAG_PACMAN_BIT = 1 << 9, + FF_PACKAGES_FLAG_PALUDIS_BIT = 1 << 10, + FF_PACKAGES_FLAG_PKG_BIT = 1 << 11, + FF_PACKAGES_FLAG_PKGTOOL_BIT = 1 << 12, + FF_PACKAGES_FLAG_MACPORTS_BIT = 1 << 13, + FF_PACKAGES_FLAG_RPM_BIT = 1 << 14, + FF_PACKAGES_FLAG_SCOOP_BIT = 1 << 15, + FF_PACKAGES_FLAG_SNAP_BIT = 1 << 16, + FF_PACKAGES_FLAG_WINGET_BIT = 1 << 17, + FF_PACKAGES_FLAG_XBPS_BIT = 1 << 18, +} FFPackagesFlags; + typedef struct FFPackagesOptions { FFModuleBaseInfo moduleInfo; FFModuleArgs moduleArgs; -#ifdef _WIN32 - bool winget; -#endif + FFPackagesFlags disabled; } FFPackagesOptions; diff --git a/src/modules/packages/packages.c b/src/modules/packages/packages.c index 1417148b..2b17c080 100644 --- a/src/modules/packages/packages.c +++ b/src/modules/packages/packages.c @@ -40,9 +40,8 @@ void ffPrintPackages(FFPackagesOptions* options) if(counts.pacmanBranch.length > 0) printf("[%s]", counts.pacmanBranch.chars); if((all -= counts.pacman) > 0) - fputs(", ", stdout); + printf(", "); }; - FF_PRINT_PACKAGE(dpkg) FF_PRINT_PACKAGE(rpm) FF_PRINT_PACKAGE(emerge) @@ -109,13 +108,52 @@ bool ffParsePackagesCommandOptions(FFPackagesOptions* options, const char* key, if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) return true; - #ifdef _WIN32 - if(ffStrEqualsIgnCase(subKey, "winget")) + if (ffStrEqualsIgnCase(subKey, "disabled")) { - options->winget = ffOptionParseBoolean(value); + options->disabled = FF_PACKAGES_FLAG_NONE; + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + ffOptionParseString(key, value, &buffer); + + char *start = buffer.chars, *end = strchr(start, ':'); + while (true) + { + if (end) + *end = '\0'; + + #define FF_TEST_PACKAGE_NAME(name) else if (ffStrEqualsIgnCase(start, #name)) { options->disabled |= FF_PACKAGES_FLAG_ ## name ## _BIT; } + if (false); + FF_TEST_PACKAGE_NAME(APK) + FF_TEST_PACKAGE_NAME(BREW) + 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(NIX) + FF_TEST_PACKAGE_NAME(OPKG) + FF_TEST_PACKAGE_NAME(PACMAN) + FF_TEST_PACKAGE_NAME(PALUDIS) + FF_TEST_PACKAGE_NAME(PKG) + FF_TEST_PACKAGE_NAME(PKGTOOL) + FF_TEST_PACKAGE_NAME(MACPORTS) + FF_TEST_PACKAGE_NAME(RPM) + FF_TEST_PACKAGE_NAME(SCOOP) + FF_TEST_PACKAGE_NAME(SNAP) + FF_TEST_PACKAGE_NAME(WINGET) + FF_TEST_PACKAGE_NAME(XBPS) + #undef FF_TEST_PACKAGE_NAME + + if (end) + { + start = end + 1; + end = strchr(end, ':'); + } + else + break; + } + return true; } - #endif return false; } @@ -127,19 +165,55 @@ void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module) yyjson_obj_foreach(module, idx, max, key_, val) { const char* key = yyjson_get_str(key_); - if(ffStrEqualsIgnCase(key, "type")) + if (ffStrEqualsIgnCase(key, "type")) continue; if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) continue; - #ifdef _WIN32 - if (ffStrEqualsIgnCase(key, "winget")) + if (ffStrEqualsIgnCase(key, "disabled")) { - options->winget = yyjson_get_bool(val); - continue; + if (!yyjson_is_null(val) && !yyjson_is_arr(val)) + { + ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, "Invalid JSON value for %s", key); + continue; + } + + options->disabled = FF_PACKAGES_FLAG_NONE; + + if (yyjson_is_arr(val)) + { + yyjson_val* flagObj; + size_t flagIdx, flagMax; + yyjson_arr_foreach(val, flagIdx, flagMax, flagObj) + { + const char* flag = yyjson_get_str(flagObj); + + #define FF_TEST_PACKAGE_NAME(name) else if (ffStrEqualsIgnCase(flag, #name)) { options->disabled |= FF_PACKAGES_FLAG_ ## name ## _BIT; } + if (false); + FF_TEST_PACKAGE_NAME(APK) + FF_TEST_PACKAGE_NAME(BREW) + 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(NIX) + FF_TEST_PACKAGE_NAME(OPKG) + FF_TEST_PACKAGE_NAME(PACMAN) + FF_TEST_PACKAGE_NAME(PALUDIS) + FF_TEST_PACKAGE_NAME(PKG) + FF_TEST_PACKAGE_NAME(PKGTOOL) + FF_TEST_PACKAGE_NAME(MACPORTS) + FF_TEST_PACKAGE_NAME(RPM) + FF_TEST_PACKAGE_NAME(SCOOP) + FF_TEST_PACKAGE_NAME(SNAP) + FF_TEST_PACKAGE_NAME(WINGET) + FF_TEST_PACKAGE_NAME(XBPS) + #undef FF_TEST_PACKAGE_NAME + } + } } - #endif ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); } @@ -152,10 +226,32 @@ void ffGeneratePackagesJsonConfig(FFPackagesOptions* options, yyjson_mut_doc* do ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); - #ifdef _WIN32 - if (options->winget != defaultOptions.winget) - yyjson_mut_obj_add_bool(doc, module, "winget", options->winget); - #endif + if (options->disabled != defaultOptions.disabled) + { + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "disabled"); + #define FF_TEST_PACKAGE_NAME(name) else if ((options->disabled & FF_PACKAGES_FLAG_ ## name ## _BIT) != (defaultOptions.disabled & FF_PACKAGES_FLAG_ ## name ## _BIT)) { yyjson_mut_arr_add_str(doc, arr, #name); } + if (false); + FF_TEST_PACKAGE_NAME(APK) + FF_TEST_PACKAGE_NAME(BREW) + 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(NIX) + FF_TEST_PACKAGE_NAME(OPKG) + FF_TEST_PACKAGE_NAME(PACMAN) + FF_TEST_PACKAGE_NAME(PALUDIS) + FF_TEST_PACKAGE_NAME(PKG) + FF_TEST_PACKAGE_NAME(PKGTOOL) + FF_TEST_PACKAGE_NAME(MACPORTS) + FF_TEST_PACKAGE_NAME(RPM) + FF_TEST_PACKAGE_NAME(SCOOP) + FF_TEST_PACKAGE_NAME(SNAP) + FF_TEST_PACKAGE_NAME(WINGET) + FF_TEST_PACKAGE_NAME(XBPS) + #undef FF_TEST_PACKAGE_NAME + } } void ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) @@ -248,9 +344,7 @@ void ffInitPackagesOptions(FFPackagesOptions* options) ); ffOptionInitModuleArg(&options->moduleArgs); - #ifdef _WIN32 - options->winget = false; - #endif + options->disabled = FF_PACKAGES_FLAG_WINGET_BIT; } void ffDestroyPackagesOptions(FFPackagesOptions* options)