summaryrefslogtreecommitdiff
path: root/Command
diff options
context:
space:
mode:
authorGravatar Joey Hess <joeyh@joeyh.name>2017-08-29 14:58:38 -0400
committerGravatar Joey Hess <joeyh@joeyh.name>2017-08-29 15:10:01 -0400
commit44d71938c6535f207932799ea3e231dc78bcb8de (patch)
treed66bea23fe7d0ad4cf34adcc9b4324ba58191e4f /Command
parentb0836c1a8ce6edb0604648c1fcf4396f43ebd998 (diff)
initial export command
Very basic operation works, but of course this is only the beginning. This commit was sponsored by Nick Daly on Patreon.
Diffstat (limited to 'Command')
-rw-r--r--Command/Export.hs103
1 files changed, 103 insertions, 0 deletions
diff --git a/Command/Export.hs b/Command/Export.hs
new file mode 100644
index 000000000..7de143ffb
--- /dev/null
+++ b/Command/Export.hs
@@ -0,0 +1,103 @@
+{- git-annex command
+ -
+ - Copyright 2017 Joey Hess <id@joeyh.name>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+module Command.Export where
+
+import Command
+import qualified Git
+import qualified Git.DiffTree
+import Git.Sha
+import Git.FilePath
+import Types.Key
+import Types.Remote
+import Annex.Content
+import Annex.CatFile
+import Messages.Progress
+import Utility.Tmp
+
+import qualified Data.ByteString.Lazy as L
+
+cmd :: Command
+cmd = command "export" SectionCommon
+ "export content to a remote"
+ paramTreeish (seek <$$> optParser)
+
+data ExportOptions = ExportOptions
+ { exportTreeish :: Git.Ref
+ , exportRemote :: DeferredParse Remote
+ }
+
+optParser :: CmdParamsDesc -> Parser ExportOptions
+optParser _ = ExportOptions
+ <$> (Git.Ref <$> parsetreeish)
+ <*> (parseRemoteOption <$> parseToOption)
+ where
+ parsetreeish = argument str
+ ( metavar paramTreeish
+ )
+
+seek :: ExportOptions -> CommandSeek
+seek o = do
+ r <- getParsed (exportRemote o)
+ let oldtreeish = emptyTree -- XXX temporary
+ (diff, cleanup) <- inRepo $
+ Git.DiffTree.diffTreeRecursive oldtreeish (exportTreeish o)
+ seekActions $ pure $ map (start r) diff
+ void $ liftIO cleanup
+
+start :: Remote -> Git.DiffTree.DiffTreeItem -> CommandStart
+start r diff
+ | Git.DiffTree.dstsha diff == nullSha = do
+ showStart "unexport" f
+ oldk <- either id id <$> exportKey (Git.DiffTree.srcsha diff)
+ next $ performUnexport r oldk loc
+ | otherwise = do
+ showStart "export" f
+ next $ performExport r diff loc
+ where
+ loc = ExportLocation $ toInternalGitPath $
+ getTopFilePath $ Git.DiffTree.file diff
+ f = getTopFilePath $ Git.DiffTree.file diff
+
+performExport :: Remote -> Git.DiffTree.DiffTreeItem -> ExportLocation -> CommandPerform
+performExport r diff loc = case storeExport r of
+ Nothing -> error "remote does not support exporting files"
+ Just storer -> next $ do
+ v <- exportKey (Git.DiffTree.dstsha diff)
+ case v of
+ Right k -> metered Nothing k $ \m ->
+ sendAnnex k
+ (void $ performUnexport r k loc)
+ (\f -> storer f k loc m)
+ -- Sending a non-annexed file.
+ Left sha1k -> metered Nothing sha1k $ \m ->
+ withTmpFile "export" $ \tmp h -> do
+ b <- catObject (Git.DiffTree.dstsha diff)
+ liftIO $ L.hPut h b
+ liftIO $ hClose h
+ storer tmp sha1k loc m
+
+performUnexport :: Remote -> Key -> ExportLocation -> CommandPerform
+performUnexport r k loc = case removeExport r of
+ Nothing -> error "remote does not support removing exported files"
+ Just remover -> next $ remover k loc
+
+-- When the Sha points to an annexed file, get the key as Right.
+-- When the Sha points to a non-annexed file, convert to a SHA1 key,
+-- as Left.
+exportKey :: Git.Sha -> Annex (Either Key Key)
+exportKey sha = mk <$> catKey sha
+ where
+ mk (Just k) = Right k
+ mk Nothing = Left $ Key
+ { keyName = show sha
+ , keyVariety = SHA1Key (HasExt False)
+ , keySize = Nothing
+ , keyMtime = Nothing
+ , keyChunkSize = Nothing
+ , keyChunkNum = Nothing
+ }