Guess the version format when it is not provided

The most important change here is that versions without dots (not a 'semver')
are treated as 'PLAIN' rather than 'UNKNOWN'.
This commit is contained in:
Richard Hughes 2018-11-13 11:12:09 +00:00
parent 69fca1d754
commit ac458d3436
6 changed files with 110 additions and 9 deletions

View File

@ -332,7 +332,7 @@ fu_dell_dock_ec_get_dock_info (FuDevice *device,
device_entry[i].version.version_8[2],
device_entry[i].version.version_8[3]);
g_debug ("\tParsed version %s", self->ec_version);
fu_device_set_version (self, self->ec_version);
fu_device_set_version (FU_DEVICE (self), self->ec_version);
} else if (map->device_type == FU_DELL_DOCK_DEVICETYPE_MST) {
self->raw_versions->mst_version = device_entry[i].version.version_32;

View File

@ -202,6 +202,17 @@ fu_common_vercmp_chunk (const gchar *str1, const gchar *str2)
return fu_common_vercmp_char (str1[i], str2[i]);
}
static gboolean
_g_ascii_is_digits (const gchar *str)
{
g_return_val_if_fail (str != NULL, FALSE);
for (gsize i = 0; str[i] != '\0'; i++) {
if (!g_ascii_isdigit (str[i]))
return FALSE;
}
return TRUE;
}
/**
* fu_common_version_parse:
* @version: A version number
@ -228,7 +239,6 @@ fu_common_version_parse (const gchar *version)
gchar *endptr = NULL;
guint64 tmp;
guint base;
guint i;
/* already dotted decimal */
if (g_strstr_len (version, -1, ".") != NULL)
@ -245,10 +255,8 @@ fu_common_version_parse (const gchar *version)
base = 16;
} else {
/* for non-numeric content, just return the string */
for (i = 0; version[i] != '\0'; i++) {
if (!g_ascii_isdigit (version[i]))
return g_strdup (version);
}
if (!_g_ascii_is_digits (version))
return g_strdup (version);
base = 10;
}
@ -261,6 +269,56 @@ fu_common_version_parse (const gchar *version)
return fu_common_version_from_uint32 ((guint32) tmp, FU_VERSION_FORMAT_TRIPLET);
}
/**
* fu_common_version_guess_format:
* @version: A version number, e.g. "1.2.3"
*
* Guesses the version format from the version number. This is only a heuristic
* and plugins and components should explicitly set the version format whenever
* possible.
*
* If the version format cannot be guessed with any degree of accuracy, the
* %FU_VERSION_FORMAT_UNKNOWN constant is returned.
*
* Returns: A #FuVersionFormat, e.g. %FU_VERSION_FORMAT_QUAD
*
* Since: 1.2.0
*/
FuVersionFormat
fu_common_version_guess_format (const gchar *version)
{
guint sz;
g_auto(GStrv) split = NULL;
/* nothing to use */
if (version == NULL || version[0] == '\0')
return FU_VERSION_FORMAT_UNKNOWN;
/* no dots, assume just text */
split = g_strsplit (version, ".", -1);
sz = g_strv_length (split);
if (sz == 1)
return FU_VERSION_FORMAT_PLAIN;
/* check for only-digit semver version */
for (guint i = 0; split[i] != NULL; i++) {
/* check sections are plain numbers */
if (!_g_ascii_is_digits (split[i]))
return FU_VERSION_FORMAT_UNKNOWN;
}
/* the most common formats */
if (sz == 2)
return FU_VERSION_FORMAT_PAIR;
if (sz == 3)
return FU_VERSION_FORMAT_TRIPLET;
if (sz == 4)
return FU_VERSION_FORMAT_QUAD;
/* unknown! */
return FU_VERSION_FORMAT_UNKNOWN;
}
/**
* fu_common_vercmp:
* @version_a: the release version, e.g. 1.2.3

View File

@ -45,5 +45,6 @@ gchar *fu_common_version_from_uint32 (guint32 val,
gchar *fu_common_version_from_uint16 (guint16 val,
FuVersionFormat flags);
gchar *fu_common_version_parse (const gchar *version);
FuVersionFormat fu_common_version_guess_format (const gchar *version);
#endif /* __FU_COMMON_VERSION_H__ */

View File

@ -14,6 +14,7 @@
#include "fu-common.h"
#include "fu-common-guid.h"
#include "fu-common-version.h"
#include "fu-device-private.h"
#include "fu-mutex.h"
@ -1046,6 +1047,29 @@ fu_device_set_id (FuDevice *self, const gchar *id)
fwupd_device_set_id (FWUPD_DEVICE (self), id_hash);
}
/**
* fu_device_set_version:
* @self: A #FuDevice
* @version: a string, e.g. `1.2.3`
*
* Sets the device version, autodetecting the version format if required.
*
* Since: 1.2.1
**/
void
fu_device_set_version (FuDevice *self, const gchar *version)
{
FuDevicePrivate *priv = GET_PRIVATE (self);
g_return_if_fail (FU_IS_DEVICE (self));
g_return_if_fail (version != NULL);
/* try to autodetect the version-format */
if (priv->version_format == FU_VERSION_FORMAT_UNKNOWN)
priv->version_format = fu_common_version_guess_format (version);
fwupd_device_set_version (FWUPD_DEVICE (self), version);
}
/**
* fu_device_ensure_id:
* @self: A #FuDevice

View File

@ -94,7 +94,6 @@ FuDevice *fu_device_new (void);
#define fu_device_set_update_state(d,v) fwupd_device_set_update_state(FWUPD_DEVICE(d),v)
#define fu_device_set_vendor(d,v) fwupd_device_set_vendor(FWUPD_DEVICE(d),v)
#define fu_device_set_vendor_id(d,v) fwupd_device_set_vendor_id(FWUPD_DEVICE(d),v)
#define fu_device_set_version(d,v) fwupd_device_set_version(FWUPD_DEVICE(d),v)
#define fu_device_set_version_lowest(d,v) fwupd_device_set_version_lowest(FWUPD_DEVICE(d),v)
#define fu_device_set_version_bootloader(d,v) fwupd_device_set_version_bootloader(FWUPD_DEVICE(d),v)
#define fu_device_set_flashes_left(d,v) fwupd_device_set_flashes_left(FWUPD_DEVICE(d),v)
@ -158,6 +157,8 @@ void fu_device_set_metadata_integer (FuDevice *self,
guint value);
void fu_device_set_id (FuDevice *self,
const gchar *id);
void fu_device_set_version (FuDevice *self,
const gchar *version);
const gchar *fu_device_get_physical_id (FuDevice *self);
void fu_device_set_physical_id (FuDevice *self,
const gchar *physical_id);

View File

@ -52,6 +52,20 @@ fu_self_test_mkroot (void)
g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0);
}
static void
fu_common_version_guess_format_func (void)
{
g_assert_cmpint (fu_common_version_guess_format (NULL), ==, FU_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format (""), ==, FU_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format ("1234ac"), ==, FU_VERSION_FORMAT_PLAIN);
g_assert_cmpint (fu_common_version_guess_format ("1.2"), ==, FU_VERSION_FORMAT_PAIR);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3"), ==, FU_VERSION_FORMAT_TRIPLET);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4"), ==, FU_VERSION_FORMAT_QUAD);
g_assert_cmpint (fu_common_version_guess_format ("1.2.3.4.5"), ==, FU_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format ("1a.2b.3"), ==, FU_VERSION_FORMAT_UNKNOWN);
g_assert_cmpint (fu_common_version_guess_format ("1"), ==, FU_VERSION_FORMAT_PLAIN);
}
static void
fu_engine_requirements_missing_func (void)
{
@ -857,7 +871,8 @@ fu_engine_history_func (void)
" [Release]\n"
" Version: 1.2.3\n"
" Checksum: SHA1(%s)\n"
" TrustFlags: none\n",
" TrustFlags: none\n"
" VersionFormat: triplet\n",
checksum);
ret = fu_test_compare_lines (device_str, device_str_expected, &error);
g_assert_no_error (error);
@ -986,7 +1001,8 @@ fu_engine_history_error_func (void)
" [Release]\n"
" Version: 1.2.3\n"
" Checksum: SHA1(%s)\n"
" TrustFlags: none\n",
" TrustFlags: none\n"
" VersionFormat: triplet\n",
checksum);
ret = fu_test_compare_lines (device_str, device_str_expected, &error);
g_assert_no_error (error);
@ -3214,6 +3230,7 @@ main (int argc, char **argv)
g_test_add_func ("/fwupd/keyring{gpg}", fu_keyring_gpg_func);
g_test_add_func ("/fwupd/keyring{pkcs7}", fu_keyring_pkcs7_func);
g_test_add_func ("/fwupd/chunk", fu_chunk_func);
g_test_add_func ("/fwupd/common{version-guess-format}", fu_common_version_guess_format_func);
g_test_add_func ("/fwupd/common{guid}", fu_common_guid_func);
g_test_add_func ("/fwupd/common{version}", fu_common_version_func);
g_test_add_func ("/fwupd/common{vercmp}", fu_common_vercmp_func);