diff --git a/unison-cli/src/Unison/Cli/DownloadUtils.hs b/unison-cli/src/Unison/Cli/DownloadUtils.hs index 936b2b3fba..31139a0f2a 100644 --- a/unison-cli/src/Unison/Cli/DownloadUtils.hs +++ b/unison-cli/src/Unison/Cli/DownloadUtils.hs @@ -11,10 +11,13 @@ where import Control.Concurrent.STM (atomically) import Control.Concurrent.STM.TVar (modifyTVar', newTVarIO, readTVar, readTVarIO) import Data.List.NonEmpty (pattern (:|)) +import Data.Set qualified as Set import System.Console.Regions qualified as Console.Regions import System.IO.Unsafe (unsafePerformIO) import U.Codebase.HashTags (CausalHash) +import U.Codebase.Sqlite.Queries qualified as Q import U.Codebase.Sqlite.Queries qualified as Queries +import U.Codebase.Sqlite.RemoteProjectBranch qualified as SqliteRPB import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.Share.Projects qualified as Share @@ -77,9 +80,15 @@ downloadProjectBranchFromShare useSquashed branch = Cli.respond (Output.DownloadedEntities numDownloaded) SyncV2 -> do let branchRef = SyncV2.BranchRef (into @Text (ProjectAndBranch branch.projectName remoteProjectBranchName)) - let downloadedCallback = \_ -> pure () let shouldValidate = not $ Codeserver.isCustomCodeserver Codeserver.defaultCodeserver - result <- SyncV2.syncFromCodeserver shouldValidate Share.hardCodedBaseUrl branchRef causalHashJwt downloadedCallback + knownRemoteHash <- fmap (fromMaybe Set.empty) . Cli.runTransaction $ runMaybeT do + lastKnownCausalHashId <- SqliteRPB.lastKnownCausalHash <$> MaybeT (Q.loadRemoteBranch branch.projectId Share.hardCodedUri branch.branchId) + lastKnownCausalHash <- lift $ Q.expectCausalHash lastKnownCausalHashId + -- Check that we actually have this causal saved. + lift (Q.checkBranchExistsForCausalHash lastKnownCausalHash) >>= \case + True -> pure (Set.singleton lastKnownCausalHash) + False -> pure mempty + result <- SyncV2.syncFromCodeserver shouldValidate Share.hardCodedBaseUrl branchRef causalHashJwt knownRemoteHash result & onLeft \err0 -> do done case err0 of Share.SyncError pullErr -> diff --git a/unison-cli/src/Unison/Share/SyncV2.hs b/unison-cli/src/Unison/Share/SyncV2.hs index 14870f208d..7e668782ac 100644 --- a/unison-cli/src/Unison/Share/SyncV2.hs +++ b/unison-cli/src/Unison/Share/SyncV2.hs @@ -155,16 +155,20 @@ syncFromCodeserver :: SyncV2.BranchRef -> -- | The hash to download. Share.HashJWT -> - -- | Callback that's given a number of entities we just downloaded. - (Int -> IO ()) -> + -- | Set of known hashes to avoid downloading. + -- If provided we'll skip the negotiation stage. + Set CausalHash -> Cli (Either (SyncError SyncV2.PullError) ()) -syncFromCodeserver shouldValidate unisonShareUrl branchRef hashJwt _downloadedCallback = do +syncFromCodeserver shouldValidate unisonShareUrl branchRef hashJwt providedKnownHashes = do Cli.Env {authHTTPClient, codebase} <- ask -- Every insert into SQLite checks the temp entity tables, but syncv2 doesn't actually use them, so it's faster -- if we clear them out before starting a sync. Cli.runTransaction Q.clearTempEntityTables runExceptT do - knownHashes <- ExceptT $ negotiateKnownCausals unisonShareUrl branchRef hashJwt + knownHashes <- + if Set.null providedKnownHashes + then ExceptT $ negotiateKnownCausals unisonShareUrl branchRef hashJwt + else pure (Set.map Sync.causalHashToHash32 providedKnownHashes) let hash = Share.hashJWTHash hashJwt ExceptT $ do (Cli.runTransaction (Q.entityLocation hash)) >>= \case