Skip to content

Commit d95114b

Browse files
committed
Sync to/from file
1 parent 4324c53 commit d95114b

File tree

34 files changed

+1533
-28
lines changed

34 files changed

+1533
-28
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dist-newstyle
2727
*.prof.html
2828
*.hp
2929
*.ps
30+
*.profiterole.*
3031
/.direnv/
3132
/.envrc
3233

codebase2/codebase-sqlite/U/Codebase/Sqlite/Branch/Format.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ data BranchLocalIds' t d p c = LocalIds
101101
branchPatchLookup :: Vector p,
102102
branchChildLookup :: Vector c
103103
}
104-
deriving (Show)
104+
deriving (Show, Eq)
105105

106106
-- | Bytes encoding a LocalBranch
107107
newtype LocalBranchBytes = LocalBranchBytes ByteString
@@ -110,6 +110,7 @@ newtype LocalBranchBytes = LocalBranchBytes ByteString
110110
data SyncBranchFormat' parent text defn patch child
111111
= SyncFull (BranchLocalIds' text defn patch child) LocalBranchBytes
112112
| SyncDiff parent (BranchLocalIds' text defn patch child) LocalBranchBytes
113+
deriving (Eq, Show)
113114

114115
type SyncBranchFormat = SyncBranchFormat' BranchObjectId TextId ObjectId PatchObjectId (BranchObjectId, CausalHashId)
115116

codebase2/codebase-sqlite/U/Codebase/Sqlite/Causal.hs

+1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ data SyncCausalFormat' causalHash valueHash = SyncCausalFormat
2222
{ valueHash :: valueHash,
2323
parents :: Vector causalHash
2424
}
25+
deriving stock (Eq, Show)
2526

2627
type SyncCausalFormat = SyncCausalFormat' CausalHashId BranchHashId

codebase2/codebase-sqlite/U/Codebase/Sqlite/Decl/Format.hs

+2
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,11 @@ type SyncDeclFormat =
3636

3737
data SyncDeclFormat' t d
3838
= SyncDecl (SyncLocallyIndexedComponent' t d)
39+
deriving stock (Eq, Show)
3940

4041
newtype SyncLocallyIndexedComponent' t d
4142
= SyncLocallyIndexedComponent (Vector (LocalIds' t d, ByteString))
43+
deriving stock (Eq, Show)
4244

4345
-- [OldDecl] ==map==> [NewDecl] ==number==> [(NewDecl, Int)] ==sort==> [(NewDecl, Int)] ==> permutation is map snd of that
4446

codebase2/codebase-sqlite/U/Codebase/Sqlite/Entity.hs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ data SyncEntity' text hash defn patch branchh branch causal
2424
| N (Namespace.SyncBranchFormat' branch text defn patch (branch, causal))
2525
| P (Patch.SyncPatchFormat' patch text hash defn)
2626
| C (Causal.SyncCausalFormat' causal branchh)
27+
deriving stock (Eq, Show)
2728

2829
entityType :: SyncEntity' text hash defn patch branchh branch causal -> TempEntityType
2930
entityType = \case

codebase2/codebase-sqlite/U/Codebase/Sqlite/LocalIds.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ data LocalIds' t h = LocalIds
1515
{ textLookup :: Vector t,
1616
defnLookup :: Vector h
1717
}
18-
deriving (Functor, Show)
18+
deriving stock (Functor, Show, Eq)
1919

2020
type LocalIds = LocalIds' TextId ObjectId
2121

codebase2/codebase-sqlite/U/Codebase/Sqlite/Patch/Format.hs

+2
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ data PatchLocalIds' t h d = LocalIds
4040
patchHashLookup :: Vector h,
4141
patchDefnLookup :: Vector d
4242
}
43+
deriving stock (Eq, Show)
4344

4445
type SyncPatchFormat = SyncPatchFormat' PatchObjectId TextId HashId ObjectId
4546

4647
data SyncPatchFormat' parent text hash defn
4748
= SyncFull (PatchLocalIds' text hash defn) ByteString
4849
| -- | p is the identity of the thing that the diff is relative to
4950
SyncDiff parent (PatchLocalIds' text hash defn) ByteString
51+
deriving stock (Eq, Show)
5052

5153
-- | Apply a list of patch diffs to a patch, left to right.
5254
applyPatchDiffs :: Patch -> [PatchDiff] -> Patch

codebase2/codebase-sqlite/U/Codebase/Sqlite/Term/Format.hs

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ newtype LocallyIndexedComponent' t d = LocallyIndexedComponent
4949

5050
newtype SyncLocallyIndexedComponent' t d
5151
= SyncLocallyIndexedComponent (Vector (LocalIds' t d, ByteString))
52+
deriving stock (Eq, Show)
5253

5354
{-
5455
message = "hello, world" -> ABT { ... { Term.F.Text "hello, world" } } -> hashes to (#abc, 0)
@@ -127,6 +128,7 @@ data TermFormat' t d = Term (LocallyIndexedComponent' t d)
127128
type SyncTermFormat = SyncTermFormat' TextId ObjectId
128129

129130
data SyncTermFormat' t d = SyncTerm (SyncLocallyIndexedComponent' t d)
131+
deriving stock (Eq, Show)
130132

131133
data WatchResultFormat
132134
= WatchResult WatchLocalIds Term

codebase2/codebase-sqlite/unison-codebase-sqlite.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 1.12
22

3-
-- This file has been generated from package.yaml by hpack version 0.36.0.
3+
-- This file has been generated from package.yaml by hpack version 0.37.0.
44
--
55
-- see: https://github.com/sol/hpack
66

hie.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ cradle:
140140
- path: "unison-share-api/src"
141141
component: "unison-share-api:lib"
142142

143+
- path: "unison-share-api/tests"
144+
component: "unison-share-api:test:unison-share-api-tests"
145+
143146
- path: "unison-share-projects-api/src"
144147
component: "unison-share-projects-api:lib"
145148

lib/unison-sqlite/src/Unison/Sqlite.hs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module Unison.Sqlite
1919
Transaction,
2020
runTransaction,
2121
runTransactionWithRollback,
22+
runTransactionExceptT,
2223
runReadOnlyTransaction,
2324
runWriteTransaction,
2425
cacheTransaction,

lib/unison-sqlite/src/Unison/Sqlite/Transaction.hs

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module Unison.Sqlite.Transaction
33
Transaction,
44
runTransaction,
55
runTransactionWithRollback,
6+
runTransactionExceptT,
67
runReadOnlyTransaction,
78
runWriteTransaction,
89
cacheTransaction,
@@ -44,6 +45,7 @@ where
4445

4546
import Control.Concurrent (threadDelay)
4647
import Control.Exception (Exception (fromException), onException, throwIO)
48+
import Control.Monad.Trans.Except (ExceptT, runExceptT)
4749
import Control.Monad.Trans.Reader (ReaderT (..))
4850
import Data.Text qualified as Text
4951
import Data.Unique (Unique, newUnique)
@@ -130,6 +132,13 @@ runTransactionWithRollback conn transaction = liftIO do
130132
Right x -> pure x
131133
{-# SPECIALIZE runTransactionWithRollback :: Connection -> ((forall void. a -> Transaction void) -> Transaction a) -> IO a #-}
132134

135+
-- | Run a transaction wrapped in an 'ExceptT'. If the ExceptT fails, the transaction is rolled back.
136+
runTransactionExceptT :: (MonadIO m, HasCallStack) => Connection -> ExceptT e Transaction a -> m (Either e a)
137+
runTransactionExceptT conn transaction = runTransactionWithRollback conn \rollback -> do
138+
runExceptT transaction >>= \case
139+
Left e -> rollback (Left e)
140+
Right a -> pure (Right a)
141+
133142
-- | Run a transaction that is known to only perform reads.
134143
--
135144
-- The action is provided a function that peels off the 'Transaction' newtype without sending the corresponding

parser-typechecker/src/Unison/Codebase.hs

+10
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ module Unison.Codebase
9999
-- * Direct codebase access
100100
runTransaction,
101101
runTransactionWithRollback,
102+
runTransactionExceptT,
102103
withConnection,
103104
withConnectionIO,
104105

@@ -112,6 +113,7 @@ module Unison.Codebase
112113
)
113114
where
114115

116+
import Control.Monad.Except (ExceptT)
115117
import Data.Map qualified as Map
116118
import Data.Set qualified as Set
117119
import U.Codebase.Branch qualified as V2Branch
@@ -174,6 +176,14 @@ runTransactionWithRollback ::
174176
runTransactionWithRollback Codebase {withConnection} action =
175177
withConnection \conn -> Sqlite.runTransactionWithRollback conn action
176178

179+
runTransactionExceptT ::
180+
(MonadIO m) =>
181+
Codebase m v a ->
182+
ExceptT e Sqlite.Transaction b ->
183+
m (Either e b)
184+
runTransactionExceptT Codebase {withConnection} action =
185+
withConnection \conn -> Sqlite.runTransactionExceptT conn action
186+
177187
getShallowCausalAtPathFromRootHash ::
178188
-- Causal to start at, if Nothing use the codebase's root branch.
179189
CausalHash ->

unison-cli/package.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ library:
2020
- condition: "!os(windows)"
2121
dependencies: unix
2222
dependencies:
23+
- attoparsec
2324
- Diff
2425
- IntervalMap
2526
- ListLike
@@ -32,7 +33,10 @@ library:
3233
- co-log-core
3334
- code-page
3435
- concurrent-output
36+
- conduit
3537
- containers >= 0.6.3
38+
- conduit
39+
- conduit-extra
3640
- cryptonite
3741
- either
3842
- errors
@@ -65,8 +69,10 @@ library:
6569
- recover-rtti
6670
- regex-tdfa
6771
- semialign
72+
- serialise
6873
- servant
6974
- servant-client
75+
- servant-conduit
7076
- stm
7177
- temporary
7278
- text-ansi

unison-cli/src/Unison/Cli/MonadUtils.hs

+8
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ module Unison.Cli.MonadUtils
4949
stepManyAtM,
5050
updateProjectBranchRoot,
5151
updateProjectBranchRoot_,
52+
setProjectBranchRootToCausalHash,
5253
updateAtM,
5354
updateAt,
5455
updateAndStepAt,
@@ -447,6 +448,13 @@ updateProjectBranchRoot projectBranch reason f = do
447448
Q.setProjectBranchHead reason (projectBranch ^. #projectId) (projectBranch ^. #branchId) causalHashId
448449
pure result
449450

451+
setProjectBranchRootToCausalHash :: ProjectBranch -> Text -> CausalHash -> Cli ()
452+
setProjectBranchRootToCausalHash projectBranch reason targetCH = do
453+
Cli.time "setProjectBranchRootToCausalHash" do
454+
Cli.runTransaction $ do
455+
targetCHID <- Q.expectCausalHashIdByCausalHash targetCH
456+
Q.setProjectBranchHead reason (projectBranch ^. #projectId) (projectBranch ^. #branchId) targetCHID
457+
450458
updateProjectBranchRoot_ :: ProjectBranch -> Text -> (Branch IO -> Branch IO) -> Cli ()
451459
updateProjectBranchRoot_ projectBranch reason f = do
452460
updateProjectBranchRoot projectBranch reason (\b -> pure (f b, ()))

unison-cli/src/Unison/Codebase/Editor/HandleInput.hs

+18-1
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ import Unison.Codebase.Editor.HandleInput.DeleteBranch (handleDeleteBranch)
5959
import Unison.Codebase.Editor.HandleInput.DeleteNamespace (getEndangeredDependents, handleDeleteNamespace)
6060
import Unison.Codebase.Editor.HandleInput.DeleteProject (handleDeleteProject)
6161
import Unison.Codebase.Editor.HandleInput.Dependents (handleDependents)
62-
import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace)
6362
import Unison.Codebase.Editor.HandleInput.EditDependents (handleEditDependents)
63+
import Unison.Codebase.Editor.HandleInput.EditNamespace (handleEditNamespace)
6464
import Unison.Codebase.Editor.HandleInput.FindAndReplace (handleStructuredFindI, handleStructuredFindReplaceI, handleTextFindI)
6565
import Unison.Codebase.Editor.HandleInput.FormatFile qualified as Format
6666
import Unison.Codebase.Editor.HandleInput.Global qualified as Global
@@ -87,6 +87,7 @@ import Unison.Codebase.Editor.HandleInput.ReleaseDraft (handleReleaseDraft)
8787
import Unison.Codebase.Editor.HandleInput.Run (handleRun)
8888
import Unison.Codebase.Editor.HandleInput.RuntimeUtils qualified as RuntimeUtils
8989
import Unison.Codebase.Editor.HandleInput.ShowDefinition (handleShowDefinition)
90+
import Unison.Codebase.Editor.HandleInput.SyncV2 qualified as SyncV2
9091
import Unison.Codebase.Editor.HandleInput.TermResolution (resolveMainRef)
9192
import Unison.Codebase.Editor.HandleInput.Tests qualified as Tests
9293
import Unison.Codebase.Editor.HandleInput.Todo (handleTodo)
@@ -688,6 +689,17 @@ loop e = do
688689
Cli.respond Success
689690
PullI sourceTarget pullMode -> handlePull sourceTarget pullMode
690691
PushRemoteBranchI pushRemoteBranchInput -> handlePushRemoteBranch pushRemoteBranchInput
692+
SyncToFileI syncFileDest projectBranchName -> SyncV2.handleSyncToFile syncFileDest projectBranchName
693+
SyncFromFileI syncFileSrc projectBranchName -> do
694+
description <- inputDescription input
695+
SyncV2.handleSyncFromFile description syncFileSrc projectBranchName
696+
SyncFromCodebaseI srcCodebasePath srcBranch destBranch -> do
697+
description <- inputDescription input
698+
let srcBranch' =
699+
srcBranch & over #project \case
700+
Nothing -> error "todo"
701+
Just proj -> proj
702+
SyncV2.handleSyncFromCodebase description srcCodebasePath srcBranch' destBranch
691703
ListDependentsI hq -> handleDependents hq
692704
ListDependenciesI hq -> handleDependencies hq
693705
NamespaceDependenciesI path -> handleNamespaceDependencies path
@@ -1012,6 +1024,11 @@ inputDescription input =
10121024
ProjectsI -> wat
10131025
PullI {} -> wat
10141026
PushRemoteBranchI {} -> wat
1027+
SyncToFileI {} -> wat
1028+
SyncFromFileI fp pab ->
1029+
pure $ "sync.from-file " <> into @Text fp <> " " <> into @Text pab
1030+
SyncFromCodebaseI fp srcBranch destBranch -> do
1031+
pure $ "sync.from-file " <> into @Text fp <> " " <> into @Text srcBranch <> " " <> into @Text destBranch
10151032
QuitI {} -> wat
10161033
ReleaseDraftI {} -> wat
10171034
ShowDefinitionI {} -> wat
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
module Unison.Codebase.Editor.HandleInput.SyncV2
2+
( handleSyncToFile,
3+
handleSyncFromFile,
4+
handleSyncFromCodebase,
5+
)
6+
where
7+
8+
import Control.Lens
9+
import Control.Monad.Reader (MonadReader (..))
10+
import U.Codebase.Sqlite.Queries qualified as Q
11+
import Unison.Cli.Monad (Cli)
12+
import Unison.Cli.Monad qualified as Cli
13+
import Unison.Cli.MonadUtils qualified as Cli
14+
import Unison.Cli.ProjectUtils qualified as Project
15+
import Unison.Codebase (CodebasePath)
16+
import Unison.Codebase qualified as Codebase
17+
import Unison.Codebase.Editor.Output qualified as Output
18+
import Unison.Codebase.Init qualified as Init
19+
import Unison.Codebase.SqliteCodebase qualified as SqliteCodebase
20+
import Unison.Prelude
21+
import Unison.Project (ProjectAndBranch (..), ProjectBranchName, ProjectName)
22+
import Unison.Share.SyncV2 qualified as SyncV2
23+
import Unison.SyncV2.Types (BranchRef)
24+
25+
handleSyncToFile :: FilePath -> ProjectAndBranch (Maybe ProjectName) (Maybe ProjectBranchName) -> Cli ()
26+
handleSyncToFile destSyncFile branchToSync = do
27+
pp <- Cli.getCurrentProjectPath
28+
projectBranch <- Project.resolveProjectBranchInProject (pp ^. #project) branchToSync
29+
causalHash <- Cli.runTransaction $ Project.getProjectBranchCausalHash (projectBranch ^. #branch)
30+
let branchRef = into @BranchRef $ ProjectAndBranch (projectBranch ^. #project . #name) (projectBranch ^. #branch . #name)
31+
Cli.Env {codebase} <- ask
32+
liftIO (SyncV2.syncToFile codebase causalHash (Just branchRef) destSyncFile) >>= \case
33+
Left err -> Cli.respond (Output.SyncPullError err)
34+
Right _ -> pure ()
35+
36+
handleSyncFromFile :: Text -> FilePath -> ProjectAndBranch (Maybe ProjectName) ProjectBranchName -> Cli ()
37+
handleSyncFromFile description srcSyncFile branchToSync = do
38+
pp <- Cli.getCurrentProjectPath
39+
projectBranch <- Project.resolveProjectBranchInProject (pp ^. #project) (over #branch Just branchToSync)
40+
let shouldValidate = True
41+
SyncV2.syncFromFile shouldValidate srcSyncFile >>= \case
42+
Left err -> Cli.respond (Output.SyncPullError err)
43+
Right causalHash -> do
44+
Cli.setProjectBranchRootToCausalHash (projectBranch ^. #branch) description causalHash
45+
46+
handleSyncFromCodebase :: Text -> CodebasePath -> ProjectAndBranch ProjectName ProjectBranchName -> ProjectAndBranch (Maybe ProjectName) ProjectBranchName -> Cli ()
47+
handleSyncFromCodebase description srcCodebasePath srcBranch destBranch = do
48+
Cli.Env {codebase} <- ask
49+
pp <- Cli.getCurrentProjectPath
50+
projectBranch <- Project.resolveProjectBranchInProject (pp ^. #project) (over #branch Just destBranch)
51+
r <- liftIO $ Init.withOpenCodebase SqliteCodebase.init "sync-src" srcCodebasePath Init.DontLock (Init.MigrateAfterPrompt Init.Backup Init.Vacuum) \srcCodebase -> do
52+
Codebase.withConnection srcCodebase \srcConn -> do
53+
maySrcCausalHash <- Codebase.runTransaction srcCodebase $ do
54+
let ProjectAndBranch srcProjName srcBranchName = srcBranch
55+
runMaybeT do
56+
project <- MaybeT (Q.loadProjectByName srcProjName)
57+
branch <- MaybeT (Q.loadProjectBranchByName (project ^. #projectId) srcBranchName)
58+
lift $ Project.getProjectBranchCausalHash branch
59+
case maySrcCausalHash of
60+
Nothing -> pure $ Left (error "Todo proper error")
61+
Just srcCausalHash -> do
62+
let shouldValidate = True
63+
fmap (const srcCausalHash) <$> liftIO (SyncV2.syncFromCodebase shouldValidate srcConn codebase srcCausalHash)
64+
65+
case r of
66+
Left _err -> pure $ error "Todo proper error"
67+
Right (Left syncErr) -> Cli.respond (Output.SyncPullError syncErr)
68+
Right (Right causalHash) -> do
69+
Cli.setProjectBranchRootToCausalHash (projectBranch ^. #branch) description causalHash

unison-cli/src/Unison/Codebase/Editor/Input.hs

+3
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ data Input
126126
| DiffNamespaceI BranchId2 BranchId2 -- old new
127127
| PullI !PullSourceTarget !PullMode
128128
| PushRemoteBranchI PushRemoteBranchInput
129+
| SyncToFileI FilePath (ProjectAndBranch (Maybe ProjectName) (Maybe ProjectBranchName))
130+
| SyncFromFileI FilePath UnresolvedProjectBranch
131+
| SyncFromCodebaseI FilePath UnresolvedProjectBranch UnresolvedProjectBranch
129132
| ResetI (BranchId2 {- namespace to reset it to -}) (Maybe UnresolvedProjectBranch {- ProjectBranch to reset -})
130133
| -- | used in Welcome module to give directions to user
131134
--

unison-cli/src/Unison/Codebase/Editor/Output.hs

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import Unison.Share.Sync.Types qualified as Sync
8080
import Unison.ShortHash (ShortHash)
8181
import Unison.Symbol (Symbol)
8282
import Unison.Sync.Types qualified as Share (DownloadEntitiesError, UploadEntitiesError)
83+
import Unison.SyncV2.Types qualified as SyncV2
8384
import Unison.Syntax.Parser qualified as Parser
8485
import Unison.Term (Term)
8586
import Unison.Type (Type)
@@ -440,6 +441,7 @@ data Output
440441
| -- | A literal output message. Use this if it's too cumbersome to create a new Output constructor, e.g. for
441442
-- ephemeral progress messages that are just simple strings like "Loading branch..."
442443
Literal !(P.Pretty P.ColorText)
444+
| SyncPullError (Sync.SyncError SyncV2.PullError)
443445

444446
data MoreEntriesThanShown = MoreEntriesThanShown | AllEntriesShown
445447
deriving (Eq, Show)
@@ -678,6 +680,7 @@ isFailure o = case o of
678680
IncoherentDeclDuringMerge {} -> True
679681
IncoherentDeclDuringUpdate {} -> True
680682
Literal _ -> False
683+
SyncPullError {} -> True
681684

682685
isNumberedFailure :: NumberedOutput -> Bool
683686
isNumberedFailure = \case

0 commit comments

Comments
 (0)