diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index b25112db..59d6d9e2 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -158,6 +158,17 @@ typedef enum { * - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name * - a{sv} - Additional metadata, at the current time the following are defined: * - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum + * - key: "ostree.summary.last-modified", value: t, timestamp (seconds since + * the Unix epoch in UTC, big-endian) when the summary was last regenerated + * (similar to the HTTP `Last-Modified` header) + * - key: "ostree.summary.expires", value: t, timestamp (seconds since the + * Unix epoch in UTC, big-endian) after which the summary is considered + * stale and should be re-downloaded if possible (similar to the HTTP + * `Expires` header) + * + * The currently defined keys for the `a{sv}` of additional metadata for each commit are: + * - key: `ostree.commit.timestamp`, value: `t`, timestamp (seconds since the + * Unix epoch in UTC, big-endian) when the commit was committed */ #define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})" #define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING) diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 94330226..87e67a23 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -43,6 +43,14 @@ G_BEGIN_DECLS * */ #define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 16 +/* Well-known keys for the additional metadata field in a summary file. */ +#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified" +#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires" + +/* Well-known keys for the additional metadata field in a commit in a ref entry + * in a summary file. */ +#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp" + typedef enum { OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0) } OstreeRepoTestErrorFlags; diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index e204fd15..fd7aa55d 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -4563,6 +4563,10 @@ ostree_repo_verify_summary (OstreeRepo *self, * An OSTree repository can contain a high level "summary" file that * describes the available branches and other metadata. * + * If the timetable for making commits and updating the summary file is fairly + * regular, setting the `ostree.summary.expires` key in @additional_metadata + * will aid clients in working out when to check for updates. + * * It is regenerated automatically after a commit if * `core/commit-update-summary` is set. */ @@ -4595,6 +4599,9 @@ ostree_repo_regenerate_summary (OstreeRepo *self, const char *commit = g_hash_table_lookup (refs, ref); g_autofree char *remotename = NULL; g_autoptr(GVariant) commit_obj = NULL; + g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; + guint64 commit_timestamp; + g_autoptr(GDateTime) dt = NULL; g_assert (commit); @@ -4608,11 +4615,21 @@ ostree_repo_regenerate_summary (OstreeRepo *self, if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_obj, error)) goto out; - g_variant_builder_add_value (refs_builder, + g_variant_dict_init (&commit_metadata_builder, NULL); + + /* Forward the commit’s timestamp if it’s valid. */ + commit_timestamp = ostree_commit_get_timestamp (commit_obj); + dt = g_date_time_new_from_unix_utc (commit_timestamp); + + if (dt != NULL) + g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP, + g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp))); + + g_variant_builder_add_value (refs_builder, g_variant_new ("(s(t@ay@a{sv}))", ref, (guint64) g_variant_get_size (commit_obj), ostree_checksum_to_bytes_v (commit), - ot_gvariant_new_empty_string_dict ())); + g_variant_dict_end (&commit_metadata_builder))); } @@ -4661,6 +4678,11 @@ ostree_repo_regenerate_summary (OstreeRepo *self, g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder)); } + { + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_LAST_MODIFIED, + g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC))); + } + { g_autoptr(GVariantBuilder) summary_builder = g_variant_builder_new (OSTREE_SUMMARY_GVARIANT_FORMAT);