/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2012-2024 Matthias Klumpp * * Licensed under the GNU Lesser General Public License Version 2.1 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the license, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "ascli-actions-mdata.h" #include #include #include #include #include "ascli-utils.h" #include "as-utils-private.h" #include "as-pool-private.h" /** * ascli_refresh_cache: */ int ascli_refresh_cache (const gchar *cachepath, const gchar *datapath, const gchar *const *sources_str, gboolean forced) { g_autoptr(AsPool) pool = NULL; g_autoptr(GError) error = NULL; gboolean cache_updated; gboolean ret = FALSE; if (!as_utils_is_root ()) /* TRANSLATORS: In ascli: Status information during a "refresh" action. */ g_print ("• %s\n", _("Only refreshing metadata cache specific to the current user.")); pool = as_pool_new (); if (sources_str != NULL) { as_pool_set_load_std_data_locations (pool, FALSE); for (guint i = 0; sources_str[i] != NULL; i++) { if (g_strcmp0 (sources_str[i], "os") == 0) { as_pool_add_flags (pool, AS_POOL_FLAG_LOAD_OS_CATALOG | AS_POOL_FLAG_LOAD_OS_METAINFO | AS_POOL_FLAG_LOAD_OS_DESKTOP_FILES); g_print ("• %s\n", _("Updating software metadata cache for the operating system.")); } else if (g_strcmp0 (sources_str[i], "flatpak") == 0) { as_pool_add_flags (pool, AS_POOL_FLAG_LOAD_FLATPAK); g_print ("• %s\n", _("Updating software metadata cache for Flatpak.")); } else { ascli_print_stderr (_("A metadata source group with the name '%s' does not exist!"), sources_str[i]); return 1; } } } if (datapath != NULL) { /* we auto-disable loading data from sources that are not in datapath for now */ as_pool_set_load_std_data_locations (pool, FALSE); /* the user wants data from a different path to be used */ as_pool_add_extra_data_location (pool, datapath, AS_FORMAT_STYLE_CATALOG); } if (cachepath == NULL) { ret = as_pool_refresh_system_cache (pool, forced, &cache_updated, &error); } else { as_pool_override_cache_locations (pool, cachepath, NULL); ret = as_pool_load (pool, NULL, &error); cache_updated = TRUE; } if (!ret) { if (g_error_matches (error, AS_POOL_ERROR, AS_POOL_ERROR_CACHE_WRITE_FAILED)) /* TRANSLATORS: In ascli: The requested action needs higher permissions. */ g_printerr ( "✘ %s\n %s\n", error->message, _("You might need superuser permissions to perform this action.")); else g_printerr ("✘ %s\n", error->message); return 2; } if (cache_updated) { /* TRANSLATORS: Updating the metadata cache succeeded */ g_print ("✔ %s\n", _("Metadata cache was updated successfully.")); } else { /* TRANSLATORS: Metadata cache was not updated, likely because it was recent enough */ g_print ("✔ %s\n", _("Metadata cache update is not necessary.")); } return 0; } /** * ascli_get_component: * * Get component by id */ int ascli_get_component (const gchar *cachepath, const gchar *identifier, gboolean detailed, gboolean no_cache) { g_autoptr(AsPool) dpool = NULL; g_autoptr(GError) error = NULL; g_autoptr(AsComponentBox) result = NULL; if (identifier == NULL) { /* TRANSLATORS: An AppStream component-id is missing in the command-line arguments */ fprintf (stderr, "%s\n", _("You need to specify a component-ID.")); return 2; } dpool = ascli_data_pool_new_and_open (cachepath, no_cache, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } result = as_pool_get_components_by_id (dpool, identifier); if (as_component_box_is_empty (result)) { ascli_print_stderr (_("Unable to find component with ID '%s'!"), identifier); return 4; } ascli_print_components (result, detailed); return 0; } /** * ascli_search_component: */ int ascli_search_component (const gchar *cachepath, const gchar *search_term, gboolean detailed, gboolean no_cache) { g_autoptr(AsPool) pool = NULL; g_autoptr(AsComponentBox) result = NULL; g_autoptr(GError) error = NULL; if (search_term == NULL) { fprintf (stderr, "%s\n", _("You need to specify a term to search for.")); return 2; } pool = ascli_data_pool_new_and_open (cachepath, no_cache, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } result = as_pool_search (pool, search_term); if (as_component_box_is_empty (result)) { /* TRANSLATORS: We got no full-text search results */ ascli_print_stdout (_("No component matching '%s' found."), search_term); return 0; } /* show the result */ ascli_print_components (result, detailed); return 0; } /** * ascli_what_provides: * * Get component providing an item */ int ascli_what_provides (const gchar *cachepath, const gchar *kind_str, const gchar *item, gboolean detailed) { g_autoptr(AsPool) pool = NULL; g_autoptr(AsComponentBox) result = NULL; AsProvidedKind kind; g_autoptr(GError) error = NULL; if (item == NULL) { g_printerr ("%s\n", _("No value for the item to search for was defined.")); return 1; } kind = as_provided_kind_from_string (kind_str); if (kind == AS_PROVIDED_KIND_UNKNOWN) { g_printerr ("%s\n", _("Invalid type for provided item selected. Valid values are:")); for (guint i = 1; i < AS_PROVIDED_KIND_LAST; i++) g_printerr (" • %s\n", as_provided_kind_to_string (i)); return 3; } pool = ascli_data_pool_new_and_open (cachepath, FALSE, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } result = as_pool_get_components_by_provided_item (pool, kind, item); if (as_component_box_len (result) == 0) { /* TRANSLATORS: Search for provided items (e.g. mimetypes, modaliases, ..) yielded no results */ ascli_print_stdout ( _("Could not find component providing '%s::%s'."), kind_str, item); return 0; } /* show results */ ascli_print_components (result, detailed); return 0; } /** * ascli_list_categories: * * List components that match the selected categories. */ int ascli_list_categories (const gchar *cachepath, gchar **categories, gboolean detailed, gboolean no_cache) { g_autoptr(AsPool) pool = NULL; g_autoptr(AsComponentBox) result = NULL; g_autoptr(GError) error = NULL; if (categories == NULL || categories[0] == NULL) { fprintf (stderr, "%s\n", _("You need to specify categories to list.")); return 2; } pool = ascli_data_pool_new_and_open (cachepath, FALSE, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } result = as_pool_get_components_by_categories (pool, categories); if (as_component_box_is_empty (result)) { g_autofree gchar *cats_str = g_strjoinv (", ", categories); /* TRANSLATORS: We got no category list results */ ascli_print_stdout (_("No component found in categories %s."), cats_str); return 0; } /* show results */ ascli_print_components (result, detailed); return 0; } /** * ascli_dump_component: * * Dump the raw upstream XML for a component. */ int ascli_dump_component (const gchar *cachepath, const gchar *identifier, AsFormatKind mformat, gboolean no_cache) { g_autoptr(AsPool) pool = NULL; g_autoptr(AsComponentBox) result = NULL; g_autoptr(AsMetadata) metad = NULL; g_autoptr(GError) error = NULL; if (identifier == NULL) { /* TRANSLATORS: ascli was told to find a software component by its ID, but no component-id was specified. */ fprintf (stderr, "%s\n", _("You need to specify a component-ID.")); return 2; } pool = ascli_data_pool_new_and_open (cachepath, no_cache, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } result = as_pool_get_components_by_id (pool, identifier); if (as_component_box_is_empty (result)) { ascli_print_stderr (_("Unable to find component with ID '%s'!"), identifier); return 4; } /* default to XML if we don't know the format */ if (mformat == AS_FORMAT_KIND_UNKNOWN) mformat = AS_FORMAT_KIND_XML; /* convert the obtained component to XML */ metad = as_metadata_new (); for (guint i = 0; i < as_component_box_len (result); i++) { g_autofree gchar *metadata = NULL; AsComponent *cpt = as_component_box_index (result, i); as_metadata_clear_components (metad); as_metadata_add_component (metad, cpt); if (mformat == AS_FORMAT_KIND_YAML) { /* we allow YAML serialization just this once */ metadata = as_metadata_components_to_catalog (metad, AS_FORMAT_KIND_YAML, NULL); } else { metadata = as_metadata_component_to_metainfo (metad, mformat, NULL); } g_print ("%s\n", metadata); } return 0; } /** * ascli_put_metainfo: * * Install a metainfo file. */ int ascli_put_metainfo (const gchar *fname, const gchar *origin, gboolean for_user) { AsMetadataLocation location; const gchar *dest_dir; g_autoptr(GError) error = NULL; if (fname == NULL) { ascli_print_stderr (_("You need to specify a metadata file.")); return 2; } /* determine our root directory */ dest_dir = g_getenv ("DESTDIR"); location = AS_METADATA_LOCATION_CACHE; if (g_str_has_suffix (fname, ".metainfo.xml") || g_str_has_suffix (fname, ".appdata.xml")) location = AS_METADATA_LOCATION_SHARED; if (for_user) location = AS_METADATA_LOCATION_USER; if (!as_utils_install_metadata_file (location, fname, origin, dest_dir, &error)) { ascli_print_stderr (_("Unable to install metadata file: %s"), error->message); return 3; } return 0; } /** * ascli_convert_data: * * Convert data from YAML to XML and vice versa. */ int ascli_convert_data (const gchar *in_fname, const gchar *out_fname, AsFormatKind mformat) { g_autoptr(AsMetadata) metad = NULL; g_autoptr(GFile) infile = NULL; g_autoptr(GError) error = NULL; if (in_fname == NULL || out_fname == NULL) { ascli_print_stderr (_("You need to specify an input and output file.")); return 3; } /* load input file */ infile = g_file_new_for_path (in_fname); if (!g_file_query_exists (infile, NULL)) { ascli_print_stderr (_("Metadata file '%s' does not exist."), in_fname); return 4; } metad = as_metadata_new (); as_metadata_set_locale (metad, "ALL"); if ((g_str_has_suffix (in_fname, ".yml.gz")) || (g_str_has_suffix (in_fname, ".yaml.gz")) || (g_str_has_suffix (in_fname, ".yml")) || (g_str_has_suffix (in_fname, ".yaml"))) { /* if we have YAML, we also automatically assume a catalog style */ as_metadata_set_format_style (metad, AS_FORMAT_STYLE_CATALOG); } else if (g_str_has_suffix (in_fname, ".metainfo.xml") || g_str_has_suffix (in_fname, ".appdata.xml")) { as_metadata_set_format_style (metad, AS_FORMAT_STYLE_METAINFO); } else { as_metadata_set_format_style (metad, AS_FORMAT_STYLE_CATALOG); } as_metadata_parse_file (metad, infile, AS_FORMAT_KIND_UNKNOWN, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } /* since YAML files are always catalog-YAMLs, we will always run in catalog mode */ as_metadata_set_format_style (metad, AS_FORMAT_STYLE_CATALOG); if (mformat == AS_FORMAT_KIND_UNKNOWN) { if (g_str_has_suffix (in_fname, ".xml") || g_str_has_suffix (in_fname, ".xml.gz")) mformat = AS_FORMAT_KIND_YAML; else if (g_str_has_suffix (in_fname, ".yml") || g_str_has_suffix (in_fname, ".yml.gz") || g_str_has_suffix (in_fname, ".yaml") || g_str_has_suffix (in_fname, ".yaml.gz")) mformat = AS_FORMAT_KIND_XML; if (mformat == AS_FORMAT_KIND_UNKNOWN) { /* TRANSLATORS: User is trying to convert a file in ascli */ ascli_print_stderr ( _("Unable to convert file: Could not determine output format, please set it explicitly using '--format='.")); return 3; } } if (g_strcmp0 (out_fname, "-") == 0) { g_autofree gchar *data = NULL; /* print to stdout */ data = as_metadata_components_to_catalog (metad, mformat, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } g_print ("%s\n", data); } else { /* save to file */ as_metadata_save_catalog (metad, out_fname, mformat, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } } return 0; } /** * ascli_create_metainfo_template: * * Create a metainfo file template to be filed out by the user. */ int ascli_create_metainfo_template (const gchar *out_fname, const gchar *cpt_kind_str, const gchar *desktop_file) { g_autoptr(AsMetadata) metad = NULL; g_autoptr(AsComponent) cpt = NULL; g_autoptr(GError) error = NULL; AsComponentKind cpt_kind = AS_COMPONENT_KIND_UNKNOWN; /* check if we have a component-kind set */ cpt_kind = as_component_kind_from_string (cpt_kind_str); if (cpt_kind == AS_COMPONENT_KIND_UNKNOWN) { if (cpt_kind_str == NULL) { /* TRANSLATORS: The user tried to create a new template, but supplied a wrong component-type string */ ascli_print_stderr ( _("You need to give an AppStream software component type to generate a template. Possible values are:")); } else { /* TRANSLATORS: The user tried to create a new template, but supplied a wrong component-type string */ ascli_print_stderr (_("The software component type '%s' is not valid in AppStream. Possible values are:"), cpt_kind_str); } for (guint i = 1; i < AS_COMPONENT_KIND_LAST; i++) ascli_print_stderr (" • %s", as_component_kind_to_string (i)); return 3; } /* new metadata parser, limited to one locale */ metad = as_metadata_new (); as_metadata_set_locale (metad, "C"); if (desktop_file == NULL) { cpt = as_component_new (); as_metadata_add_component (metad, cpt); } else { g_autoptr(GFile) defile = NULL; defile = g_file_new_for_path (desktop_file); if (!g_file_query_exists (defile, NULL)) { ascli_print_stderr (_("The .desktop file '%s' does not exist."), desktop_file); return 4; } as_metadata_parse_file (metad, defile, AS_FORMAT_KIND_DESKTOP_ENTRY, &error); if (error != NULL) { ascli_print_stderr (_("Unable to read the .desktop file: %s"), error->message); return 1; } cpt = g_object_ref (as_metadata_get_component (metad)); } as_component_set_context_locale (cpt, "C"); as_component_set_kind (cpt, cpt_kind); if (cpt_kind == AS_COMPONENT_KIND_FONT) { as_component_set_id (cpt, "org.example.FontPackageName"); } else if (cpt_kind == AS_COMPONENT_KIND_ADDON) { as_component_set_id (cpt, "org.example.FooBar.my-addon"); } else { if (as_component_get_id (cpt) == NULL) as_component_set_id (cpt, "org.example.SoftwareName"); } if (as_component_get_name (cpt) == NULL) as_component_set_name (cpt, "The human-readable name of this software", "C"); if (as_component_get_summary (cpt) == NULL) as_component_set_summary (cpt, "A short summary describing what this software is about", "C"); if (as_component_get_description (cpt) == NULL) as_component_set_description (cpt, "

Multiple paragraphs of long description, " "describing this software component.

" "

You can also use ordered and unordered lists:

" "
  • Feature 1
  • Feature 2
" "

Keep in mind to XML-escape characters, and that " "this is not HTML markup.

", "C"); as_component_set_metadata_license ( cpt, "A permissive license for this metadata, e.g. \"FSFAP\""); as_component_set_project_license ( cpt, "The license of this software as SPDX string, e.g. \"GPL-3+\""); as_developer_set_name (as_component_get_developer (cpt), "The software vendor name, e.g. \"ACME Corporation\"", "C"); /* console-app specific */ if (cpt_kind == AS_COMPONENT_KIND_CONSOLE_APP) { g_autoptr(AsProvided) prov = as_provided_new (); as_provided_set_kind (prov, AS_PROVIDED_KIND_BINARY); as_provided_add_item (prov, "The binary name of this software in PATH"); as_component_add_provided (cpt, prov); } /* addon specific */ if (cpt_kind == AS_COMPONENT_KIND_ADDON) as_component_add_extends (cpt, "The component-id of the software that is extended by " "this addon, e.g. \"org.example.FooBar\""); /* font specific */ if (cpt_kind == AS_COMPONENT_KIND_FONT) { g_autoptr(AsProvided) prov = as_provided_new (); as_provided_set_kind (prov, AS_PROVIDED_KIND_FONT); as_provided_add_item (prov, "A full font name, consisting of the fonts family and style, " "e.g. \"Lato Heavy Italic\""); as_provided_add_item (prov, "Liberation Serif Bold Italic"); as_component_add_provided (cpt, prov); } /* driver specific */ if (cpt_kind == AS_COMPONENT_KIND_DRIVER) { g_autoptr(AsProvided) prov = as_provided_new (); as_provided_set_kind (prov, AS_PROVIDED_KIND_MODALIAS); as_provided_add_item (prov, "Modalias of the hardware this software handles"); as_component_add_provided (cpt, prov); } /* print to console or save to file */ if ((out_fname == NULL) || (g_strcmp0 (out_fname, "-") == 0)) { g_autofree gchar *metainfo_xml = NULL; metainfo_xml = as_metadata_component_to_metainfo (metad, AS_FORMAT_KIND_XML, &error); if (error != NULL) { ascli_print_stderr (_("Unable to build the template metainfo file: %s"), error->message); return 1; } g_print ("%s\n", metainfo_xml); } else { as_metadata_save_metainfo (metad, out_fname, AS_FORMAT_KIND_XML, &error); if (error != NULL) { ascli_print_stderr (_("Unable to save the template metainfo file: %s"), error->message); return 1; } } return 0; } /** * ascli_print_satisfy_check_results: * * Helper for %ascli_check_is_satisfied */ static gboolean ascli_print_satisfy_check_results (GPtrArray *rc_results, AsSystemInfo *sysinfo) { gboolean res = TRUE; const gchar *fail_char; for (guint i = 0; i < rc_results->len; i++) { AsRelationCheckResult *rcr = AS_RELATION_CHECK_RESULT ( g_ptr_array_index (rc_results, i)); AsRelation *relation; AsRelationStatus status; status = as_relation_check_result_get_status (rcr); relation = as_relation_check_result_get_relation (rcr); if (as_relation_get_kind (relation) == AS_RELATION_KIND_SUPPORTS) fail_char = "•"; else fail_char = ASCLI_CHAR_FAIL; if (status == AS_RELATION_STATUS_ERROR) { if (as_relation_get_item_kind (relation) == AS_RELATION_ITEM_KIND_DISPLAY_LENGTH && as_system_info_get_display_length (sysinfo, AS_DISPLAY_SIDE_KIND_LONGEST) == 0) { g_print (" • %s\n", _("Unable to check display size: Can not read information without GUI toolkit access.")); } else if (as_relation_check_result_get_error_code (rcr) == AS_RELATION_ERROR_NOT_IMPLEMENTED) { g_print (" • %s\n", as_relation_check_result_get_message (rcr)); res = FALSE; } else { g_print (" %s %s: %s\n", fail_char, _("ERROR"), as_relation_check_result_get_message (rcr)); res = FALSE; } } else { const gchar *message = as_relation_check_result_get_message (rcr); if (as_relation_check_result_get_status (rcr) == AS_RELATION_STATUS_SATISFIED) { g_print (" %s %s\n", ASCLI_CHAR_SUCCESS, message); } else { g_print (" %s %s\n", fail_char, message); res = FALSE; } } } return res; } /** * ascli_check_is_satisfied: * * Verify if the selected component is satisfied on the current system. */ gint ascli_check_is_satisfied (const gchar *fname_or_cid, const gchar *cachepath, gboolean no_cache) { g_autoptr(AsComponent) cpt = NULL; g_autoptr(GError) error = NULL; g_autoptr(AsPool) pool = NULL; g_autoptr(AsSystemInfo) sysinfo = NULL; g_autoptr(GPtrArray) requires_rcr = NULL; g_autoptr(GPtrArray) recommends_rcr = NULL; g_autoptr(GPtrArray) supports_rcr = NULL; gboolean res = TRUE; if (fname_or_cid == NULL) { ascli_print_stderr (_("You need to specify a MetaInfo filename or component ID.")); return 2; } /* open the metadata pool with default options */ pool = ascli_data_pool_new_and_open (cachepath, no_cache, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return ASCLI_EXIT_CODE_FAILED; } /* get the current component, either from file or from the pool */ if (g_strstr_len (fname_or_cid, -1, "/") != NULL || g_file_test (fname_or_cid, G_FILE_TEST_EXISTS)) { g_autoptr(GFile) mi_file = NULL; g_autoptr(AsMetadata) mdata = NULL; mi_file = g_file_new_for_path (fname_or_cid); if (!g_file_query_exists (mi_file, NULL)) { ascli_print_stderr (_("Metainfo file '%s' does not exist."), fname_or_cid); return 4; } /* read the metainfo file */ mdata = as_metadata_new (); as_metadata_set_locale (mdata, "ALL"); as_metadata_parse_file (mdata, mi_file, AS_FORMAT_KIND_XML, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } cpt = g_object_ref (as_metadata_get_component (mdata)); } else { g_autoptr(AsComponentBox) cbox = NULL; cbox = as_pool_get_components_by_id (pool, fname_or_cid); if (as_component_box_is_empty (cbox)) { ascli_print_stderr (_("Unable to find component with ID '%s'!"), fname_or_cid); return ASCLI_EXIT_CODE_NO_RESULT; } cpt = g_object_ref (as_component_box_index (cbox, 0)); } /* TRANSLATORS: We are testing the relations (requires, recommends & supports data) for being satisfied on the current system. */ ascli_print_stdout (_("Relation check for: %s"), as_component_get_data_id (cpt)); g_print ("\n"); sysinfo = as_system_info_new (); requires_rcr = as_component_check_relations (cpt, sysinfo, pool, AS_RELATION_KIND_REQUIRES); recommends_rcr = as_component_check_relations (cpt, sysinfo, pool, AS_RELATION_KIND_RECOMMENDS); supports_rcr = as_component_check_relations (cpt, sysinfo, pool, AS_RELATION_KIND_SUPPORTS); ascli_print_highlight (_("Requirements:")); if (requires_rcr->len == 0) { g_print (" • %s\n", _("No required items are set for this software.")); } else { res = ascli_print_satisfy_check_results (requires_rcr, sysinfo) ? res : FALSE; } ascli_print_highlight (_("Recommendations:")); if (recommends_rcr->len == 0) { g_print (" • %s\n", _("No recommended items are set for this software.")); } else { res = ascli_print_satisfy_check_results (recommends_rcr, sysinfo) ? res : FALSE; } ascli_print_highlight (_("Supported:")); if (supports_rcr->len == 0) { g_print (" • %s\n", _("No supported items are set for this software.")); } else { ascli_print_satisfy_check_results (supports_rcr, sysinfo); } return res ? ASCLI_EXIT_CODE_SUCCESS : ASCLI_EXIT_CODE_FAILED; } /** * as_chassis_kind_to_header: * @kind: the #AsChassisKind. * * Converts the enumerated value to a human-readble * and translated text representation. * * Returns: string version of @kind * * Since: 1.0.0 **/ static const gchar * as_chassis_kind_to_header (AsChassisKind kind) { if (kind == AS_CHASSIS_KIND_DESKTOP) /* TRANSLATORS: This represents a computer chassis type. */ return _("Desktop"); if (kind == AS_CHASSIS_KIND_LAPTOP) /* TRANSLATORS: This represents a computer chassis type. */ return _("Laptop"); if (kind == AS_CHASSIS_KIND_SERVER) /* TRANSLATORS: This represents a computer chassis type. */ return _("Server"); if (kind == AS_CHASSIS_KIND_TABLET) /* TRANSLATORS: This represents a computer chassis type. */ return _("Tablet"); if (kind == AS_CHASSIS_KIND_HANDSET) /* TRANSLATORS: This represents a computer chassis type. */ return _("Handset"); return _("Unknown"); } /** * ascli_check_syscompat: * * Verify if the selected component is satisfied on a bunch of mock configurations. */ gint ascli_check_syscompat (const gchar *fname_or_cid, const gchar *cachepath, gboolean no_cache, gboolean show_details) { g_autoptr(AsComponent) cpt = NULL; g_autoptr(GError) error = NULL; if (fname_or_cid == NULL) { ascli_print_stderr (_("You need to specify a MetaInfo filename or component ID.")); return 2; } /* get the current component, either from file or from the pool */ if (g_strstr_len (fname_or_cid, -1, "/") != NULL || g_file_test (fname_or_cid, G_FILE_TEST_EXISTS)) { g_autoptr(GFile) mi_file = NULL; g_autoptr(AsMetadata) mdata = NULL; mi_file = g_file_new_for_path (fname_or_cid); if (!g_file_query_exists (mi_file, NULL)) { ascli_print_stderr (_("Metainfo file '%s' does not exist."), fname_or_cid); return 4; } /* read the metainfo file */ mdata = as_metadata_new (); as_metadata_set_locale (mdata, "ALL"); as_metadata_parse_file (mdata, mi_file, AS_FORMAT_KIND_XML, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return 1; } cpt = g_object_ref (as_metadata_get_component (mdata)); } else { g_autoptr(AsPool) pool = NULL; g_autoptr(AsComponentBox) cbox = NULL; /* open the metadata pool with default options */ pool = ascli_data_pool_new_and_open (cachepath, no_cache, &error); if (error != NULL) { g_printerr ("%s\n", error->message); return ASCLI_EXIT_CODE_FAILED; } cbox = as_pool_get_components_by_id (pool, fname_or_cid); if (as_component_box_is_empty (cbox)) { ascli_print_stderr (_("Unable to find component with ID '%s'!"), fname_or_cid); return ASCLI_EXIT_CODE_NO_RESULT; } cpt = g_object_ref (as_component_box_index (cbox, 0)); } /* TRANSLATORS: We are testing compatibility of a component with a common representation of hardware for a specific chassis (phone/tablet/desktop, etc.) */ ascli_print_stdout (_("Chassis compatibility check for: %s"), as_component_get_data_id (cpt)); for (guint chassis = AS_CHASSIS_KIND_DESKTOP; chassis < AS_CHASSIS_KIND_LAST; chassis++) { g_autoptr(AsSystemInfo) sysinfo = NULL; g_autoptr(GPtrArray) rc_results = NULL; gint score; sysinfo = as_system_info_new_template_for_chassis (chassis, NULL); if (sysinfo == NULL) continue; g_print ("\n"); ascli_print_highlight ("%s:", as_chassis_kind_to_header (chassis)); score = as_component_get_system_compatibility_score (cpt, sysinfo, TRUE, &rc_results); if (score < 50) { g_print (" %s %s\n", ASCLI_CHAR_FAIL, _("Incompatible")); if (!show_details) continue; for (guint i = 0; i < rc_results->len; i++) { AsRelationCheckResult *rcr = AS_RELATION_CHECK_RESULT ( g_ptr_array_index (rc_results, i)); AsRelation *relation; AsRelationStatus status; AsRelationKind rel_kind; g_autofree gchar *prefix = NULL; status = as_relation_check_result_get_status (rcr); relation = as_relation_check_result_get_relation (rcr); rel_kind = as_relation_get_kind (relation); if (status == AS_RELATION_STATUS_ERROR) { g_print (" %s %s: %s\n", "•", _("ERROR"), as_relation_check_result_get_message (rcr)); continue; } /* ignore any successes */ if (status == AS_RELATION_STATUS_SATISFIED) continue; g_print (" %s %s: %s\n", "•", as_relation_kind_to_string (rel_kind), as_relation_check_result_get_message (rcr)); } } else { g_print (" %s %s (%d%%)\n", ASCLI_CHAR_SUCCESS, _("Compatible"), score); } } return ASCLI_EXIT_CODE_SUCCESS; }