skeleton git-lfs special remote

This is a special remote and a git remote at the same time; git can pull
and push to it and git-annex can use it as a special remote.

Remote.Git has to check if it's configured as a git-lfs special remote
and sets it up as one if so.

Object methods not implemented yet.
This commit is contained in:
Joey Hess 2019-08-01 15:11:45 -04:00
parent 9c20a8792d
commit 1cef791cf3
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
6 changed files with 145 additions and 0 deletions

View file

@ -51,6 +51,7 @@ import Remote.Helper.Messages
import Remote.Helper.ExportImport import Remote.Helper.ExportImport
import qualified Remote.Helper.Ssh as Ssh import qualified Remote.Helper.Ssh as Ssh
import qualified Remote.GCrypt import qualified Remote.GCrypt
import qualified Remote.GitLFS
import qualified Remote.P2P import qualified Remote.P2P
import qualified Remote.Helper.P2P as P2PHelper import qualified Remote.Helper.P2P as P2PHelper
import P2P.Address import P2P.Address
@ -144,6 +145,7 @@ configRead autoinit r = do
gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote) gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
gen r u c gc gen r u c gc
| Git.GCrypt.isEncrypted r = Remote.GCrypt.chainGen r u c gc | Git.GCrypt.isEncrypted r = Remote.GCrypt.chainGen r u c gc
| remoteAnnexGitLFS gc = Remote.GitLFS.gen r u c gc
| otherwise = case repoP2PAddress r of | otherwise = case repoP2PAddress r of
Nothing -> do Nothing -> do
st <- mkState r u gc st <- mkState r u gc

130
Remote/GitLFS.hs Normal file
View file

@ -0,0 +1,130 @@
{- Using git-lfs as a remote.
-
- Copyright 2019 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
module Remote.GitLFS (remote, gen) where
import Annex.Common
import Types.Remote
import Annex.Url
import Types.Creds
import qualified Git
import Config
import Config.Cost
import Remote.Helper.Special
import Remote.Helper.ExportImport
import Remote.Helper.Git
import Annex.Ssh
import Annex.UUID
import Utility.SshHost
import qualified Utility.GitLFS as LFS
import Control.Concurrent.STM
import qualified Data.Map as M
remote :: RemoteType
remote = RemoteType
{ typename = "git-lfs"
-- Remote.Git takes care of enumerating git-lfs remotes too,
-- and will call our gen on them.
, enumerate = const (return [])
, generate = gen
, setup = mySetup
, exportSupported = exportUnsupported
, importSupported = importUnsupported
}
type LFSHandle = TVar (String, Maybe LFS.Endpoint)
gen :: Git.Repo -> UUID -> RemoteConfig -> RemoteGitConfig -> Annex (Maybe Remote)
gen r u c gc = do
handle <- liftIO $ newTVarIO (lfsrepo, Nothing)
cst <- remoteCost gc expensiveRemoteCost
return $ Just $ specialRemote' specialcfg c
(simplyPrepare $ store handle)
(simplyPrepare $ retrieve handle)
(simplyPrepare $ remove handle)
(simplyPrepare $ checkKey handle)
(this cst)
where
this cst = Remote
{ uuid = u
, cost = cst
, name = Git.repoDescribe r
, storeKey = storeKeyDummy
, retrieveKeyFile = retreiveKeyFileDummy
, retrieveKeyFileCheap = retrieveCheap
-- content stored on git-lfs is hashed with SHA256
-- no matter what git-annex key it's for, and the hash
-- is checked on download
, retrievalSecurityPolicy = RetrievalAllKeysSecure
, removeKey = removeKeyDummy
, lockContent = Nothing
, checkPresent = checkPresentDummy
, checkPresentCheap = False
, exportActions = exportUnsupported
, importActions = importUnsupported
, whereisKey = Nothing
, remoteFsck = Nothing
, repairRepo = Nothing
, config = c
, getRepo = return r
, gitconfig = gc
, localpath = Nothing
, remotetype = remote
, availability = GloballyAvailable
, readonly = False
-- content cannot be removed from a git-lfs repo
, appendonly = True
, mkUnavailable = return Nothing
, getInfo = gitRepoInfo (this cst)
, claimUrl = Nothing
, checkUrl = Nothing
}
lfsrepo = fromMaybe
(giveup "remote url is not configured")
(M.lookup "url" $ Git.config r)
specialcfg = (specialRemoteCfg c)
-- chunking would not improve git-lfs
{ chunkConfig = NoChunks
}
mySetup :: SetupStage -> Maybe UUID -> Maybe CredPair -> RemoteConfig -> RemoteGitConfig -> Annex (RemoteConfig, UUID)
mySetup _ mu _ c gc = do
u <- maybe (liftIO genUUID) return mu
let repo = fromMaybe (giveup "Specify url=") $
M.lookup "url" c
(c', _encsetup) <- encryptionSetup c gc
-- The repo is not stored in the remote log, because the same
-- git-lfs repo can be accessed using different urls by different
-- people (eg over ssh or http).
--
-- Instead, set up remote.name.url to point to the repo,
-- (so it's also usable by git as a non-special remote),
-- and set remote.name.git-lfs = true
let c'' = M.delete "repo" c'
gitConfigSpecialRemote u c'' [("git-lfs", "true")]
setConfig (ConfigKey ("remote." ++ getRemoteName c ++ ".url")) repo
return (c'', u)
store :: LFSHandle -> Storer
store h = fileStorer $ \k src p -> undefined
retrieve :: LFSHandle -> Retriever
retrieve h = byteRetriever $ \k sink -> undefined
retrieveCheap :: Key -> AssociatedFile -> FilePath -> Annex Bool
retrieveCheap _ _ _ = return False
checkKey :: LFSHandle -> CheckPresent
checkKey h key = undefined
remove :: LFSHandle -> Remover
remove h key = do
warning "git-lfs does not support removing content"
return False

View file

@ -40,6 +40,7 @@ import qualified Remote.Adb
import qualified Remote.Tahoe import qualified Remote.Tahoe
import qualified Remote.Glacier import qualified Remote.Glacier
import qualified Remote.Ddar import qualified Remote.Ddar
import qualified Remote.GitLFS
import qualified Remote.Hook import qualified Remote.Hook
import qualified Remote.External import qualified Remote.External
@ -63,6 +64,7 @@ remoteTypes = map adjustExportImportRemoteType
, Remote.Tahoe.remote , Remote.Tahoe.remote
, Remote.Glacier.remote , Remote.Glacier.remote
, Remote.Ddar.remote , Remote.Ddar.remote
, Remote.GitLFS.remote
, Remote.Hook.remote , Remote.Hook.remote
, Remote.External.remote , Remote.External.remote
] ]

View file

@ -263,6 +263,7 @@ data RemoteGitConfig = RemoteGitConfig
, remoteAnnexAndroidDirectory :: Maybe FilePath , remoteAnnexAndroidDirectory :: Maybe FilePath
, remoteAnnexAndroidSerial :: Maybe String , remoteAnnexAndroidSerial :: Maybe String
, remoteAnnexGCrypt :: Maybe String , remoteAnnexGCrypt :: Maybe String
, remoteAnnexGitLFS :: Bool
, remoteAnnexDdarRepo :: Maybe String , remoteAnnexDdarRepo :: Maybe String
, remoteAnnexHookType :: Maybe String , remoteAnnexHookType :: Maybe String
, remoteAnnexExternalType :: Maybe String , remoteAnnexExternalType :: Maybe String
@ -321,6 +322,7 @@ extractRemoteGitConfig r remotename = do
, remoteAnnexAndroidDirectory = notempty $ getmaybe "androiddirectory" , remoteAnnexAndroidDirectory = notempty $ getmaybe "androiddirectory"
, remoteAnnexAndroidSerial = notempty $ getmaybe "androidserial" , remoteAnnexAndroidSerial = notempty $ getmaybe "androidserial"
, remoteAnnexGCrypt = notempty $ getmaybe "gcrypt" , remoteAnnexGCrypt = notempty $ getmaybe "gcrypt"
, remoteAnnexGitLFS = getbool "git-lfs" False
, remoteAnnexDdarRepo = getmaybe "ddarrepo" , remoteAnnexDdarRepo = getmaybe "ddarrepo"
, remoteAnnexHookType = notempty $ getmaybe "hooktype" , remoteAnnexHookType = notempty $ getmaybe "hooktype"
, remoteAnnexExternalType = notempty $ getmaybe "externaltype" , remoteAnnexExternalType = notempty $ getmaybe "externaltype"

View file

@ -1619,6 +1619,13 @@ Here are all the supported configuration settings.
If the gcrypt remote is accessible over ssh and has git-annex-shell If the gcrypt remote is accessible over ssh and has git-annex-shell
available to manage it, it's set to "shell". available to manage it, it's set to "shell".
* `remote.<name>.annex-git-lfs`
Used to identify git-lfs special remotes.
Normally this is automatically set up by `git annex initremote`.
It is set to "true" if this is a git-lfs remote.
* `remote.<name>.annex-hooktype`, `remote.<name>.annex-externaltype` * `remote.<name>.annex-hooktype`, `remote.<name>.annex-externaltype`
Used by hook special remotes and external special remotes to record Used by hook special remotes and external special remotes to record

View file

@ -931,6 +931,7 @@ Executable git-annex
Remote.External.Types Remote.External.Types
Remote.GCrypt Remote.GCrypt
Remote.Git Remote.Git
Remote.GitLFS
Remote.Glacier Remote.Glacier
Remote.Helper.AWS Remote.Helper.AWS
Remote.Helper.Chunked Remote.Helper.Chunked
@ -1039,6 +1040,7 @@ Executable git-annex
Utility.FileSystemEncoding Utility.FileSystemEncoding
Utility.Format Utility.Format
Utility.FreeDesktop Utility.FreeDesktop
Utility.GitLFS
Utility.Glob Utility.Glob
Utility.Gpg Utility.Gpg
Utility.Hash Utility.Hash