Skip to content

v0.10.1

Latest

Choose a tag to compare

@epic-lore-bot epic-lore-bot released this 06 Oct 07:58

The latest release of Lore, Epic Games' next-generation open source version control system.

Quickstart | Design | Documentation | Discord

Quick Install

Windows

irm https://raw.githubusercontent.com/EpicGames/lore/main/scripts/install.ps1 | iex

macOS / Linux

curl -fsSL https://raw.githubusercontent.com/EpicGames/lore/main/scripts/install.sh | bash

Release Notes

Changes since v0.10.0.

Breaking changes

  • lore.thin_client.v1: DiffChange.content_from / content_to and ContentDiffRequest.address_from / address_to / address_base become a lore.model.v1.Address, the form TreeNode.address already carried, and move to field numbers 10 and 11, and 8, 9 and 10; the hash-only bytes fields they replace (5 and 6, and 1 through 3) are reserved. A committed file's content resolves under a context generated per file, so a consumer keying content and metadata lookups on hash-context found nothing for any file in a diff, and had nowhere to put the context when asking ContentDiff for the file's text. A side that does not exist reports the field unset: an ADD has no from side and a DELETE no to side. A link pin change addresses each of its revisions under the linked repository. A consumer built against the old fields reads the new ones as absent rather than as a hash, so rebuild against the new bindings
  • C API: every storage *_ITEM_COMPLETE event replaces error_code with an error detail carrying the failure's own FFI code, message and trace, as Complete already did, and the call's status becomes the dominant item failure's code. Re-check any branch on a per-item code: a missing payload reports PayloadNotFound (81) rather than AddressNotFound (80), a buffer short of the content reports Oversized (118) rather than InvalidArguments (3), and most failures previously reported as Internal now report their own code. The structs grow and are no longer trivially copyable, so copy the detail's strings before the callback returns and rebuild against the new lore.h. The revision-tree per-item events are unchanged: they still carry error_code as a lore_error_code_t, so the five-value folding still applies to them, and moving them to a detail will need a second rebuild in a later release
  • C API: an empty lore_string_t the library emits now carries a NULL string pointer rather than a pointer to a zero-length NUL-terminated buffer, which is what lore_string_t has always documented and what an empty lore_array_t already answers. A consumer that read string without first checking length — strlen(s.string), printf("%s", s.string) — must check length, or treat NULL as the empty string. This applies to every empty string on every event and every verb, not one field
  • C API: lore_revision_sync_args_t appends view, a path to a view filter file, empty to keep the view the instance holds. Rebuild against the new lore.h
  • Build: the C library is built by the new lore-capi package. cargo build -p lore builds only the Rust library; build -p lore-capi for liblore.so and liblore.a (liblore.dylib, or lore.dll and lore.lib on Windows) and lore.h, under the same names and paths as before. Building the CLI no longer compiles and links the C library
  • Build: the build version is no longer compiled in from LORE_BUILD_VERSION_NAME, and a build no longer runs lore revision info to name itself. Every build reports <package version>+local until the new lore-stamp tool writes a build name into the finished binaries and libraries, which then report <package version>+<name> (see CONTRIBUTING.md). A pipeline that sets LORE_BUILD_VERSION_NAME must run lore-stamp --build <name> after the build and before signing instead. A changing build number no longer invalidates the build cache for every crate
  • lore-server: a [server.auth] without [environment.endpoint] auth_url, which authorizes from token claims, refuses to start without [server.auth.oidc], since clients have no other way to log in. Add the table with the provider's public client_id. Tier 2 (resource_claim set) also requires resource_template or scope_template in it, and Tier 1 refuses both

Features

  • C API: lore_revision_cherry_pick and lore_revision_cherry_pick_async cherry-pick a revision onto the current branch, as lore revision cherry-pick does
  • C API: lore_branch_latest_list and lore_branch_latest_list_async list the revisions a branch LATEST has held, most recent first, and relay to the Lore service when one is in use. lore branch latest list takes the same path, so with the service in use it no longer waits indefinitely on the local store the service holds
  • lore sync --view <file> changes the view filter an instance materializes its working files under, carrying the working tree to what the new view holds rather than re-cloning
  • lore-server: the disk space available to the local stores is checked on a timer and a warning is logged once it falls below a threshold. [server.local_store_monitor] carries check_interval_seconds (default 30) and low_space_threshold_bytes (default 10 GiB); an interval of 0 turns the check off. Every local store the server writes at is watched, the immutable store and the mutable store among them, and the reading is taken per volume: stores sharing a filesystem draw one warning naming them all, rather than one warning each. A server whose stores are not local is not checked
  • lore file reset --last-merged-from <branch> takes --mine or --theirs, restoring the version the reset branch held going into that merge or the version the named branch brought in, rather than the version the merge's conflicts were resolved with. A merge revision holds the resolved content, so the side that lost a resolution was otherwise unreachable; where no merge from the branch is found the branch point is restored as before, whichever flag is given. C API: lore_file_reset_to_last_merged_args_t appends a merge_side (0 = resolved, 1 = self, 2 = other) in the struct's tail padding, so its size and its other fields' offsets are unchanged and a zero-initialized struct keeps today's behavior
  • [environment.endpoint] user_url advertises a user directory that's decoupled from the auth service. Clients resolve user IDs to display names using this service's GetUserInfo and GetUserId operations. For backward compatibility, auth_url is used as the user service URL, if user_url is not defined. Client-side, the lookup moves off the Authentication trait onto a UserService trait
  • lore-server: lore repository list answers through a RepositoryCatalog implementation. The implementation is selected based on server configuration. A UrcAuthApi deployment asks LookupUserPermissions as before, a server with no [server.auth] lists everything it holds. A deployment authorizing from token claims uses a catalog implementation based repository_catalog and repository_catalog_url configuration.
  • C API: lore_repository_delete and lore_repository_delete_async delete a remote repository, and are carried out by the Lore service when one is in use. lore repository delete is relayed the same way, where it previously always ran in the calling process
  • lore-proto: introduces lore.user.v1.UserService, the user directory in Lore's own terms: UserGet resolves user IDs to users, UserFind resolves a name to a user, and PartitionList streams the partitions the caller is allowed to see. These take over what GetUserInfo, GetUserId and LookupUserPermissions did in UrcAuthApi. Only the pure OIDC-compliant authn/authz operations are left in UrcAuthApi so that we can use OIDC authorization as a drop-in replacement for the Auth API.
  • lore-server: the new [server.auth.oidc] table configures OIDC info shown to clients, through the new oidc field of lore.environment.v1.Environment
  • lore-server: [server.auth] jwt_typ lists the accepted JWT typ header values, as a string or an array. When set, a token whose header carries no typ, or a typ that doesn't match any of the entries, is rejected. If unset, the token typ value is not checked, as before
  • C API: lore_revision_bisect and lore_revision_bisect_async take one step of a bisect between two revisions, synchronizing the working directory to the revision halfway between them, and relay to the Lore service when one is in use. lore revision bisect takes the same path, so with the service in use it no longer waits indefinitely on the local store the service holds
  • C API: lore_shared_store_list and lore_shared_store_list_async list the registered shared stores and, when asked, the instances using each, as lore shared-store list does

Fixes & Improvements

  • lore link list --staged, and an interactive lore commit listing the links it asks a message for, run in the Lore service when one is in use, as other commands do, rather than opening the repository in the client, where they waited on the lock of a service holding it. C API: lore_link_list_staged and lore_link_list_staged_async expose the listing
  • lore commit stops with the failure of listing the links or layers its per-link and per-layer messages are resolved against, such as a Lore service in use that cannot be reached, where it rejected a --link-message or --layer-message path as matching nothing, or committed without asking for those messages
  • lore repository instance prune no longer removes an SWFS instance when run without the Lore service, where the instance is not mounted and its path is absent or an empty directory. Its external .lore in the global data directory shows it still exists, so lore repository instance list reports it as live and prune keeps its branch and revision anchors
  • Fix resolving another user's name failing against an auth service reached by IP address over http:// or https://
  • A lore_string_t or lore_binary_t a caller passes in with a NULL pointer and a non-zero length reads as empty rather than as undefined behaviour, which is what an empty lore_array_t already did. The library answers NULL for every empty string it emits, so one can come back in an argument struct beside a length the caller kept itself, and the pointer alone decides whether there are bytes to read
  • lore-server: every local store the configuration asks for is reported at startup, composite tiers included. A store the configuration names no path for is reported as unconfigured, wherever the generated fallback points, and a store inside a system temporary directory is reported as ephemeral whether it was configured there or generated there; the two are independent, since either can hold without the other. A local immutable tier naming a path other than the first local tier's is reported as unused instead, every local tier being handed the store the first one creates. The ephemeral report previously fired on a path being absent rather than on where the resolved path pointed, so the shipped local.toml, which sets /tmp/lore-server explicitly, drew nothing
  • lore-server: logs default to warn rather than error, so a server started without RUST_LOG reports the conditions an operator has to act on. RUST_LOG still wins where it is set, and RUST_LOG=error restores the previous output
  • Fix a moved file being deleted when the change that moves it is realized over a working tree that already holds it, which is what re-running an interrupted lore sync does. The rename finds nothing at the source it was already carried from, and the recovery that follows removed the destination and then skipped rewriting it, because whether the content was in place was inferred from the view filter rather than read from the rename. It is now read from the rename, so a move whose source is not there is written from the store, and one the rename carried is left alone
  • Bound how many subtree tasks the walk between two revisions runs at once, which lore sync, lore status and lore diff all drive. It previously ran one task per directory it descends into, all of them live at the same time, so peak memory followed the size of the tree rather than the work in flight; a subtree that finds no room in the budget is now queued for the task that found it to walk, so neither the tasks a walk holds nor the stack it stands on grows with the tree
  • Fix a command carried out by the service being answered without part of its output. A relayed call returned its result while its events were still being delivered to the caller's callback, so lore status could report a repository with no staged changes. The events are now delivered before the call returns
  • A call relayed to a Lore service that cannot be reached now reports its status and error detail on the Complete event, as a failing command does, rather than on a legacy Error event, so a caller of an _async entry point receives it
  • Fix a relative --repository resolving against the Lore service's working directory rather than the caller's for a command carried out by the service. lore repository info, lore repository delete, lore auth info, lore auth login and lore auth logout reported no repository or no remote where the path named one. The service now resolves the path against the directory the command was run in
  • Ignore and view filter files are read as UTF-8, and as UTF-16 of either byte order with a byte-order mark or, where the rules are mostly ASCII, without one. UTF-32, truncated UTF-16, and mark-less UTF-16 that cannot be detected are refused rather than read as UTF-8 into rules carrying NULs, so UTF-16 whose rules lie outside ASCII requires a mark
  • Fix the wrong files being removed when a directory leaves the working tree. Where the directory's node could not be read, the removal was decided from the incoming revision's tree and filter rather than the ones the working tree was materialized under, so it could name files that were never on disk and leave behind files that were
  • A change to a file's executable bit alone is now reported by lore status --scan, taken by lore stage, and recorded on the revision lore commit produces. A chmod moves neither the content, the size nor the modification time, which were all the comparison read, so the change was invisible from the moment it was made
  • lore sync and lore branch merge keep a locally changed executable bit on a file whose content they carry, rather than silently reverting it to the revision's. The bit stands as a local modification and blocks nothing; --reset and --force apply the revision's bit as before
  • Fix lore stage over a large tree failing with grab_node_unused returned INVALID on a freshly-allocated block. A freshly allocated block of node slots was published for every other thread to grab from before the thread that allocated it took its own, so under enough concurrency the block could be emptied out from under it. It takes its slot before it publishes the block
  • lore sync <revision> advances the branch latest to a revision standing ahead of the one the branch holds, the remote answering for it. It was left where it stood, so a sync to the remote's tip drew a lore status reporting the branch behind the remote and a second sync that did not see it was already there. A named revision moves the latest forward only, --local and --dry-run move it not at all, and a divergent branch keeps the one it has
  • Fix a moved file being left behind at the path it came from where the move crosses a mount boundary inside the working tree. No rename carries a file between filesystems, and the recovery read a destination that was not there yet as a failure of its own, so the file was written at its new path from the store and the old one never removed. A move no rename can carry now copies the content and removes the source, and a directory is carried a child at a time
  • Fix a branch that replaced a committed folder with a link being invisible to a merge, which silently deleted the link and dropped its content. A directory paired with a link is the type change it is: lore branch diff reports the replacement, and a merge that changed anything below the mount conflicts at the mount
  • Changes to configuring the Lore service: The service executable field can be left unset if the service was started with lore service run separately. There is no longer a fallback that attempts to use the current binary as the service binary.
  • lore-server: permission checks are refused with PERMISSION_DENIED when access is checked against the grpc auth service, rather than INTERNAL
  • Fix lore push slowing quadratically with the number of entries in a changed directory. The push and its server-side verification pair entries in a single pass over name-sorted lists
  • Fix lore stage staging a delete for a removed file or directory that was never committed, which lore status reported as D and, after lore unstage, as an untracked A. lore sync no longer refuses to run after lore file dirty drops such a file

Release Assets

Important

These can be downloaded under the "Assets" section below.

Installer

  • lore-setup - Lore CLI Windows installer

Binaries

  • lore - Lore CLI
  • loreserver - Lore Server
  • liblore - Lore Shared Library

Headers

  • lore.h - Single header for liblore (packged with liblore)

Supported Platforms

  • Windows x84_64
  • macOS AArch64
  • Linux x86_64
  • Linux AArch64 (for Graviton/Neoverse 512-tvb only)

Lore Desktop Client

Important

Lore Desktop Client is available as binaries only, download the installer for your platform here:

⬇️ Open Source Lore Assets Below ⬇️