git-annex 3.20110707 → 3.20110819
raw patch · 120 files changed
+1570/−858 lines, 120 filesdep +monad-control
Dependencies added: monad-control
Files
- Annex.hs +14/−4
- AnnexQueue.hs +4/−4
- Backend.hs +6/−7
- Backend/SHA.hs +4/−4
- Backend/URL.hs +28/−0
- Backend/WORM.hs +1/−1
- Branch.hs +28/−12
- CHANGELOG +31/−0
- CmdLine.hs +16/−17
- Command.hs +4/−6
- Command/Add.hs +41/−14
- Command/AddUrl.hs +22/−10
- Command/ConfigList.hs +1/−1
- Command/DropUnused.hs +5/−6
- Command/Fix.hs +1/−1
- Command/FromKey.hs +1/−1
- Command/Fsck.hs +1/−1
- Command/Get.hs +1/−1
- Command/InAnnex.hs +1/−1
- Command/Init.hs +3/−35
- Command/InitRemote.hs +4/−4
- Command/Lock.hs +1/−1
- Command/Map.hs +15/−14
- Command/Migrate.hs +1/−1
- Command/Move.hs +8/−8
- Command/SetKey.hs +3/−3
- Command/Status.hs +8/−8
- Command/Unannex.hs +1/−1
- Command/Uninit.hs +5/−17
- Command/Unlock.hs +1/−1
- Command/Unused.hs +9/−9
- Command/Version.hs +1/−1
- Command/Whereis.hs +3/−3
- Config.hs +16/−8
- Content.hs +35/−36
- Crypto.hs +15/−14
- Git.hs +59/−48
- Git/LsFiles.hs +4/−4
- Git/Queue.hs +11/−8
- Git/UnionMerge.hs +1/−1
- GitAnnex.hs +10/−1
- INSTALL +1/−0
- Init.hs +88/−0
- LocationLog.hs +1/−3
- Locations.hs +3/−3
- Messages.hs +25/−16
- PresenceLog.hs +5/−3
- Remote.hs +4/−3
- Remote/Bup.hs +19/−17
- Remote/Directory.hs +5/−4
- Remote/Encryptable.hs +0/−87
- Remote/Git.hs +53/−27
- Remote/Helper/Encryptable.hs +87/−0
- Remote/Helper/Special.hs +44/−0
- Remote/Helper/Ssh.hs +61/−0
- Remote/Helper/Url.hs +66/−0
- Remote/Hook.hs +13/−11
- Remote/Rsync.hs +16/−14
- Remote/S3real.hs +15/−19
- Remote/Special.hs +0/−44
- Remote/Ssh.hs +0/−61
- Remote/Web.hs +20/−37
- RemoteLog.hs +5/−5
- TestConfig.hs +13/−10
- Touch.hsc +2/−3
- Types/Key.hs +2/−2
- Types/Remote.hs +2/−1
- UUID.hs +2/−2
- Upgrade/V0.hs +2/−2
- Upgrade/V1.hs +45/−29
- Upgrade/V2.hs +15/−10
- Utility.hs +17/−3
- Utility/CopyFile.hs +5/−7
- Utility/DataUnits.hs +3/−3
- Utility/Dot.hs +5/−5
- Utility/RsyncFile.hs +1/−1
- Version.hs +7/−13
- configure.hs +2/−3
- debian/changelog +31/−0
- debian/control +2/−0
- doc/bugs/--git-dir_and_--work-tree_options.mdwn +29/−0
- doc/bugs/Cabal_dependency_monadIO_missing.mdwn +14/−0
- doc/bugs/Cabal_dependency_monadIO_missing/comment_1_14be660aa57fadec0d81b32a8b52c66f._comment +75/−0
- doc/bugs/Cabal_dependency_monadIO_missing/comment_2_4f4d8e1e00a2a4f7e8a8ab082e16adac._comment +8/−0
- doc/bugs/Prevent_accidental_merges.mdwn +14/−0
- doc/bugs/WORM:_Handle_long_filenames_correctly.mdwn +3/−0
- doc/bugs/__39__annex_add__39___fails_to___39__git_add__39___for_parent_relative_path.mdwn +15/−0
- doc/bugs/git_annex_fsck_is_a_no-op_in_bare_repos.mdwn +4/−0
- doc/bugs/git_command_line_constructed_by_unannex_command_has_tons_of_redundant_-a_paramters.mdwn +15/−0
- doc/bugs/making_annex-merge_try_a_fast-forward.mdwn +26/−0
- doc/bugs/support_bare_git_repo__44___with_the_annex_directory_exposed_to_http.mdwn +20/−0
- doc/bugs/unannex_command_doesn__39__t_all_files.mdwn +26/−0
- doc/bugs/wishlist:_more_descriptive_commit_messages_in_git-annex_branch.mdwn +36/−0
- doc/cheatsheet.mdwn +1/−1
- doc/forum/Can_I_store_normal_files_in_the_git-annex_git_repository__63__.mdwn +6/−0
- doc/forum/example_of_massively_disconnected_operation.mdwn +33/−0
- doc/forum/version_3_upgrade.mdwn +9/−0
- doc/forum/version_3_upgrade/comment_1_05fc9c9cad26c520bebb98c852c71e35._comment +13/−0
- doc/git-annex.mdwn +20/−2
- doc/index.mdwn +1/−1
- doc/install.mdwn +1/−0
- doc/install/Debian/comment_1_029486088d098c2d4f1099f2f0e701a9._comment +9/−0
- doc/install/Debian/comment_2_648e3467e260cdf233acdb0b53313ce0._comment +8/−0
- doc/install/Fedora.mdwn +1/−0
- doc/install/OSX.mdwn +7/−2
- doc/internals.mdwn +1/−1
- doc/news/version_0.20110610.mdwn +0/−6
- doc/news/version_3.20110624.mdwn +0/−33
- doc/news/version_3.20110702.mdwn +0/−22
- doc/news/version_3.20110719.mdwn +7/−0
- doc/news/version_3.20110817.mdwn +6/−0
- doc/news/version_3.20110819.mdwn +9/−0
- doc/special_remotes.mdwn +3/−2
- doc/special_remotes/web.mdwn +5/−1
- doc/transferring_data.mdwn +7/−3
- doc/upgrades.mdwn +3/−2
- git-annex-shell.hs +2/−2
- git-annex.cabal +3/−3
- git-union-merge.hs +3/−4
- test.hs +16/−8
Annex.hs view
@@ -5,6 +5,8 @@ - Licensed under the GNU GPL version 3 or higher. -} +{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ module Annex ( Annex, AnnexState(..),@@ -17,6 +19,7 @@ ) where import Control.Monad.State+import Control.Monad.IO.Control import qualified Git import Git.Queue@@ -28,7 +31,14 @@ import Types.UUID -- git-annex's monad-type Annex = StateT AnnexState IO+newtype Annex a = Annex { runAnnex :: StateT AnnexState IO a }+ deriving (+ Functor,+ Monad,+ MonadIO,+ MonadControlIO,+ MonadState AnnexState+ ) -- internal state storage data AnnexState = AnnexState@@ -74,13 +84,13 @@ {- Create and returns an Annex state object for the specified git repo. -} new :: Git.Repo -> IO AnnexState-new gitrepo = newState `liftM` (liftIO . Git.configRead) gitrepo+new gitrepo = newState `liftM` Git.configRead gitrepo {- performs an action in the Annex monad -} run :: AnnexState -> Annex a -> IO (a, AnnexState)-run = flip runStateT+run s a = runStateT (runAnnex a) s eval :: AnnexState -> Annex a -> IO a-eval = flip evalStateT+eval s a = evalStateT (runAnnex a) s {- Gets a value from the internal state, selected by the passed value - constructor. -}
AnnexQueue.hs view
@@ -21,10 +21,10 @@ {- Adds a git command to the queue, possibly running previously queued - actions if enough have accumulated. -}-add :: String -> [CommandParam] -> FilePath -> Annex ()-add command params file = do+add :: String -> [CommandParam] -> [FilePath] -> Annex ()+add command params files = do q <- getState repoqueue- store $ Git.Queue.add q command params file+ store $ Git.Queue.add q command params files {- Runs the queue if it is full. Should be called periodically. -} flushWhenFull :: Annex ()@@ -38,7 +38,7 @@ q <- getState repoqueue unless (0 == Git.Queue.size q) $ do unless silent $- showSideAction "Recording state in git..."+ showSideAction "Recording state in git" g <- gitRepo q' <- liftIO $ Git.Queue.flush g q store q'
Backend.hs view
@@ -19,6 +19,7 @@ import System.IO.Error (try) import System.FilePath import System.Posix.Files+import Data.Maybe import Locations import qualified Git@@ -31,12 +32,10 @@ -- When adding a new backend, import it here and add it to the list. import qualified Backend.WORM import qualified Backend.SHA+import qualified Backend.URL list :: [Backend Annex]-list = concat - [ Backend.WORM.backends- , Backend.SHA.backends- ]+list = Backend.WORM.backends ++ Backend.SHA.backends ++ Backend.URL.backends {- List of backends in the order to try them when storing a new key. -} orderedList :: Annex [Backend Annex]@@ -54,7 +53,7 @@ handle Nothing s = return s handle (Just "") s = return s handle (Just name) s = do- let l' = (lookupBackendName name):s+ let l' = lookupBackendName name : s Annex.changeState $ \state -> state { Annex.backends = l' } return l' getstandard = do@@ -67,7 +66,7 @@ genKey :: FilePath -> Maybe (Backend Annex) -> Annex (Maybe (Key, Backend Annex)) genKey file trybackend = do bs <- orderedList- let bs' = maybe bs (:bs) trybackend+ let bs' = maybe bs (: bs) trybackend genKey' bs' file genKey' :: [Backend Annex] -> FilePath -> Annex (Maybe (Key, Backend Annex)) genKey' [] _ = return Nothing@@ -119,7 +118,7 @@ {- Looks up a backend by name. May fail if unknown. -} lookupBackendName :: String -> Backend Annex-lookupBackendName s = maybe unknown id $ maybeLookupBackendName s+lookupBackendName s = fromMaybe unknown $ maybeLookupBackendName s where unknown = error $ "unknown backend " ++ s maybeLookupBackendName :: String -> Maybe (Backend Annex)
Backend/SHA.hs view
@@ -32,7 +32,7 @@ sizes = [1, 256, 512, 224, 384] backends :: [Backend Annex]--- order is slightly significant; want sha1 first ,and more general+-- order is slightly significant; want sha1 first, and more general -- sizes earlier backends = catMaybes $ map genBackend sizes ++ map genBackendE sizes @@ -72,7 +72,7 @@ shaN :: SHASize -> FilePath -> Annex String shaN size file = do- showNote "checksum..."+ showAction "checksum" liftIO $ pOpen ReadFromPipe command (toCommand [File file]) $ \h -> do line <- hGetLine h let bits = split " " line@@ -107,14 +107,14 @@ then "" -- probably not really an extension else naiveextension --- A key's checksum is checked during fsck.+{- A key's checksum is checked during fsck. -} checkKeyChecksum :: SHASize -> Key -> Annex Bool checkKeyChecksum size key = do g <- Annex.gitRepo fast <- Annex.getState Annex.fast let file = gitAnnexLocation g key present <- liftIO $ doesFileExist file- if (not present || fast)+ if not present || fast then return True else do s <- shaN size file
+ Backend/URL.hs view
@@ -0,0 +1,28 @@+{- git-annex "URL" backend -- keys whose content is available from urls.+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Backend.URL (+ backends,+ fromUrl+) where++import Types.Backend+import Types.Key+import Types++backends :: [Backend Annex]+backends = [backend]++backend :: Backend Annex+backend = Types.Backend.Backend {+ name = "URL",+ getKey = const (return Nothing),+ fsckKey = const (return True)+}++fromUrl :: String -> Key+fromUrl url = stubKey { keyName = url, keyBackendName = "URL" }
Backend/WORM.hs view
@@ -35,7 +35,7 @@ keyValue :: FilePath -> Annex (Maybe Key) keyValue file = do stat <- liftIO $ getFileStatus file- return $ Just $ Key {+ return $ Just Key { keyName = takeFileName file, keyBackendName = name backend, keySize = Just $ fromIntegral $ fileSize stat,
Branch.hs view
@@ -14,6 +14,7 @@ files, refExists, hasOrigin,+ hasSomeBranch, name ) where @@ -87,7 +88,7 @@ e <- liftIO $ doesFileExist f unless e $ do- unless bootstrapping $ create+ unless bootstrapping create liftIO $ createDirectoryIfMissing True $ takeDirectory f liftIO $ unless bootstrapping $ genIndex g @@ -124,7 +125,7 @@ {- Creates the branch, if it does not already exist. -} create :: Annex ()-create = unlessM (refExists fullname) $ do+create = unlessM hasBranch $ do g <- Annex.gitRepo e <- hasOrigin if e@@ -154,19 +155,14 @@ -} staged <- stageJournalFiles - g <- Annex.gitRepo- r <- liftIO $ Git.pipeRead g [Param "show-ref", Param name]- let refs = map (last . words) (lines r)+ refs <- siblingBranches updated <- catMaybes `liftM` mapM updateRef refs+ g <- Annex.gitRepo unless (null updated && not staged) $ liftIO $ Git.commit g "update" fullname (fullname:updated) Annex.changeState $ \s -> s { Annex.branchstate = state { branchUpdated = True } } invalidateCache -{- Does origin/git-annex exist? -}-hasOrigin :: Annex Bool-hasOrigin = refExists originname- {- Checks if a git ref exists. -} refExists :: GitRef -> Annex Bool refExists ref = do@@ -174,6 +170,26 @@ liftIO $ Git.runBool g "show-ref" [Param "--verify", Param "-q", Param ref] +{- Does the main git-annex branch exist? -}+hasBranch :: Annex Bool+hasBranch = refExists fullname++{- Does origin/git-annex exist? -}+hasOrigin :: Annex Bool+hasOrigin = refExists originname++{- Does the git-annex branch or a foo/git-annex branch exist? -}+hasSomeBranch :: Annex Bool+hasSomeBranch = liftM (not . null) siblingBranches++{- List of all git-annex branches, including the main one and any+ - from remotes. -}+siblingBranches :: Annex [String]+siblingBranches = do+ g <- Annex.gitRepo+ r <- liftIO $ Git.pipeRead g [Param "show-ref", Param name]+ return $ map (last . words) (lines r)+ {- Ensures that a given ref has been merged into the index. -} updateRef :: GitRef -> Annex (Maybe String) updateRef ref@@ -187,10 +203,10 @@ Param (name++".."++ref), Params "--oneline -n1" ]- if (null diffs)+ if null diffs then return Nothing else do- showSideAction $ "merging " ++ shortref ref ++ " into " ++ name ++ "..."+ showSideAction $ "merging " ++ shortref ref ++ " into " ++ name -- By passing only one ref, it is actually -- merged into the index, preserving any -- changes that may already be staged.@@ -305,7 +321,7 @@ {- List of journal files. -} getJournalFiles :: Annex [FilePath]-getJournalFiles = getJournalFilesRaw >>= return . map fileJournal+getJournalFiles = fmap (map fileJournal) getJournalFilesRaw getJournalFilesRaw :: Annex [FilePath] getJournalFilesRaw = do
CHANGELOG view
@@ -1,3 +1,34 @@+git-annex (3.20110819) unstable; urgency=low++ * Now "git annex init" only has to be run once, when a git repository+ is first being created. Clones will automatically notice that git-annex+ is in use and automatically perform a basic initalization. It's+ still recommended to run "git annex init" in any clones, to describe them.+ * Added annex-cost-command configuration, which can be used to vary the+ cost of a remote based on the output of a shell command.+ * Fix broken upgrade from V1 repository. Closes: #638584++ -- Joey Hess <joeyh@debian.org> Fri, 19 Aug 2011 20:34:09 -0400++git-annex (3.20110817) unstable; urgency=low++ * Fix shell escaping in rsync special remote.+ * addurl: --fast can be used to avoid immediately downloading the url.+ * Added support for getting content from git remotes using http (and https).+ * Added curl to Debian package dependencies.++ -- Joey Hess <joeyh@debian.org> Wed, 17 Aug 2011 01:29:02 -0400++git-annex (3.20110719) unstable; urgency=low++ * add: Be even more robust to avoid ever leaving the file seemingly deleted.+ Closes: #634233+ * Bugfix: Make add ../ work.+ * Support the standard git -c name=value+ * unannex: Clean up use of git commit -a.++ -- Joey Hess <joeyh@debian.org> Tue, 19 Jul 2011 23:39:53 -0400+ git-annex (3.20110707) unstable; urgency=low * Fix sign bug in disk free space checking.
CmdLine.hs view
@@ -22,10 +22,9 @@ import Content import Types import Command-import Version import Options import Messages-import UUID+import Init {- Runs the passed command line. -} dispatch :: [String] -> [Command] -> [Option] -> String -> Git.Repo -> IO ()@@ -39,14 +38,13 @@ - list of actions to be run in the Annex monad. -} parseCmd :: [String] -> String -> [Command] -> [Option] -> Annex [Annex Bool] parseCmd argv header cmds options = do- (flags, params) <- liftIO $ getopt+ (flags, params) <- liftIO getopt when (null params) $ error $ "missing command" ++ usagemsg case lookupCmd (head params) of [] -> error $ "unknown command" ++ usagemsg [command] -> do _ <- sequence flags- when (cmdusesrepo command) $- checkVersion+ checkCmdEnviron command prepCommand command (drop 1 params) _ -> error "internal error: multiple matching commands" where@@ -58,6 +56,10 @@ lookupCmd cmd = filter (\c -> cmd == cmdname c) cmds usagemsg = "\n\n" ++ usage header cmds options +{- Checks that the command can be run in the current environment. -}+checkCmdEnviron :: Command -> Annex ()+checkCmdEnviron command = when (cmdusesrepo command) ensureInitialized+ {- Usage message with lists of commands and options. -} usage :: String -> [Command] -> [Option] -> String usage header cmds options =@@ -78,9 +80,9 @@ - (but explicitly thrown errors terminate the whole command). -} tryRun :: Annex.AnnexState -> [Annex Bool] -> IO ()-tryRun state actions = tryRun' state 0 actions-tryRun' :: Annex.AnnexState -> Integer -> [Annex Bool] -> IO ()-tryRun' state errnum (a:as) = do+tryRun = tryRun' 0+tryRun' :: Integer -> Annex.AnnexState -> [Annex Bool] -> IO ()+tryRun' errnum state (a:as) = do result <- try $ Annex.run state $ do AnnexQueue.flushWhenFull a@@ -89,21 +91,18 @@ Annex.eval state $ do showEndFail showErr err- tryRun' state (errnum + 1) as- Right (True,state') -> tryRun' state' errnum as- Right (False,state') -> tryRun' state' (errnum + 1) as-tryRun' _ errnum [] = do- when (errnum > 0) $ error $ show errnum ++ " failed"+ tryRun' (errnum + 1) state as+ Right (True,state') -> tryRun' errnum state' as+ Right (False,state') -> tryRun' (errnum + 1) state' as+tryRun' errnum _ [] = when (errnum > 0) $ error $ show errnum ++ " failed" {- Actions to perform each time ran. -} startup :: Annex Bool-startup = do- prepUUID- return True+startup = return True {- Cleanup actions. -} shutdown :: Annex Bool shutdown = do saveState- liftIO $ Git.reap+ liftIO Git.reap return True
Command.hs view
@@ -102,7 +102,7 @@ stage a b = b >>= a success = return True failure = do- showProgress+ showOutput -- avoid clutter around error message showEndFail return False @@ -115,7 +115,7 @@ notBareRepo :: Annex a -> Annex a notBareRepo a = do g <- Annex.gitRepo- when (Git.repoIsLocalBare g) $ do+ when (Git.repoIsLocalBare g) $ error "You cannot run this subcommand in a bare repository." a @@ -175,11 +175,9 @@ unlockedfiles' <- filterFiles unlockedfiles backendPairs a unlockedfiles' withKeys :: CommandSeekKeys-withKeys a params = return $ map a $ map parse params+withKeys a params = return $ map (a . parse) params where- parse p = maybe (error "bad key") id $ readKey p-withTempFile :: CommandSeekStrings-withTempFile a params = return $ map a params+ parse p = fromMaybe (error "bad key") $ readKey p withNothing :: CommandSeekNothing withNothing a [] = return [a] withNothing _ _ = error "This command takes no parameters."
Command/Add.hs view
@@ -8,7 +8,12 @@ module Command.Add where import Control.Monad.State (liftIO)+import Control.Monad (when) import System.Posix.Files+import System.Directory+import Control.Exception.Control (handle)+import Control.Exception.Base (throwIO)+import Control.Exception.Extensible (IOException) import Command import qualified Annex@@ -20,6 +25,7 @@ import Messages import Utility import Touch+import Locations command :: [Command] command = [repoCommand "add" paramPath seek "add files to annex"]@@ -34,7 +40,7 @@ start :: CommandStartBackendFile start pair@(file, _) = notAnnexed file $ do s <- liftIO $ getSymbolicLinkStatus file- if (isSymbolicLink s) || (not $ isRegularFile s)+ if isSymbolicLink s || not (isRegularFile s) then stop else do showStart "add" file@@ -46,23 +52,44 @@ case k of Nothing -> stop Just (key, _) -> do- moveAnnex key file- next $ cleanup file key+ handle (undo file key) $ moveAnnex key file+ next $ cleanup file key True -cleanup :: FilePath -> Key -> CommandCleanup-cleanup file key = do- link <- calcGitLink file key- liftIO $ createSymbolicLink link file+{- On error, put the file back so it doesn't seem to have vanished.+ - This can be called before or after the symlink is in place. -}+undo :: FilePath -> Key -> IOException -> Annex a+undo file key e = do+ unlessM (inAnnex key) rethrow -- no cleanup to do+ liftIO $ whenM (doesFileExist file) $ removeFile file+ handle tryharder $ fromAnnex key file+ logStatus key InfoMissing+ rethrow+ where+ rethrow = liftIO $ throwIO e - logStatus key InfoPresent+ -- fromAnnex could fail if the file ownership is weird+ tryharder :: IOException -> Annex ()+ tryharder _ = do+ g <- Annex.gitRepo+ liftIO $ renameFile (gitAnnexLocation g key) file - -- touch the symlink to have the same mtime as the file it points to- s <- liftIO $ getFileStatus file- let mtime = modificationTime s- liftIO $ touch file (TimeSpec mtime) False+cleanup :: FilePath -> Key -> Bool -> CommandCleanup+cleanup file key hascontent = do+ handle (undo file key) $ do+ link <- calcGitLink file key+ liftIO $ createSymbolicLink link file + when hascontent $ do+ logStatus key InfoPresent+ + -- touch the symlink to have the same mtime as the+ -- file it points to+ s <- liftIO $ getFileStatus file+ let mtime = modificationTime s+ liftIO $ touch file (TimeSpec mtime) False+ force <- Annex.getState Annex.force if force- then AnnexQueue.add "add" [Param "-f", Param "--"] file- else AnnexQueue.add "add" [Param "--"] file+ then AnnexQueue.add "add" [Param "-f", Param "--"] [file]+ else AnnexQueue.add "add" [Param "--"] [file] return True
Command/AddUrl.hs view
@@ -14,13 +14,14 @@ import Command import qualified Backend+import qualified Remote.Helper.Url import qualified Remote.Web import qualified Command.Add import qualified Annex+import qualified Backend.URL import Messages import Content import PresenceLog-import Types.Key import Locations import Utility @@ -42,12 +43,17 @@ perform :: String -> FilePath -> CommandPerform perform url file = do+ fast <- Annex.getState Annex.fast+ if fast then nodownload url file else download url file++download :: String -> FilePath -> CommandPerform+download url file = do g <- Annex.gitRepo- showNote $ "downloading " ++ url- let dummykey = stubKey { keyName = url, keyBackendName = "URL" }+ showAction $ "downloading " ++ url ++ " "+ let dummykey = Backend.URL.fromUrl url let tmp = gitAnnexTmpLocation g dummykey liftIO $ createDirectoryIfMissing True (parentDir tmp)- ok <- Remote.Web.download [url] tmp+ ok <- Remote.Helper.Url.download url tmp if ok then do [(_, backend)] <- Backend.chooseBackends [file]@@ -57,9 +63,16 @@ Just (key, _) -> do moveAnnex key tmp Remote.Web.setUrl key url InfoPresent- next $ Command.Add.cleanup file key+ next $ Command.Add.cleanup file key True else stop +nodownload :: String -> FilePath -> CommandPerform+nodownload url file = do+ let key = Backend.URL.fromUrl url+ Remote.Web.setUrl key url InfoPresent+ + next $ Command.Add.cleanup file key False+ url2file :: URI -> IO FilePath url2file url = do let parts = filter safe $ split "/" $ uriPath url@@ -75,8 +88,7 @@ e <- doesFileExist file when e $ error "already have this url" return file- safe s- | null s = False- | s == "." = False- | s == ".." = False- | otherwise = True+ safe "" = False+ safe "." = False+ safe ".." = False+ safe _ = True
Command/ConfigList.hs view
@@ -14,7 +14,7 @@ import UUID command :: [Command]-command = [standaloneCommand "configlist" paramNothing seek+command = [repoCommand "configlist" paramNothing seek "outputs relevant git configuration"] seek :: [CommandSeek]
Command/DropUnused.hs view
@@ -49,7 +49,7 @@ ] where search [] = stop- search ((m, a):rest) = do+ search ((m, a):rest) = case M.lookup s m of Nothing -> search rest Just key -> do@@ -61,7 +61,7 @@ where dropremote name = do r <- Remote.byName name- showNote $ "from " ++ Remote.name r ++ "..."+ showAction $ "from " ++ Remote.name r next $ Command.Move.fromCleanup r True key droplocal = Command.Drop.perform key (Just 0) -- force drop @@ -78,10 +78,9 @@ let f = gitAnnexUnusedLog prefix g e <- liftIO $ doesFileExist f if e- then do- l <- liftIO $ readFile f- return $ M.fromList $ map parse $ lines l- else return $ M.empty+ then return . M.fromList . map parse . lines+ =<< liftIO (readFile f)+ else return M.empty where parse line = (head ws, fromJust $ readKey $ unwords $ tail ws) where
Command/Fix.hs view
@@ -44,5 +44,5 @@ cleanup :: FilePath -> CommandCleanup cleanup file = do- AnnexQueue.add "add" [Param "--"] file+ AnnexQueue.add "add" [Param "--"] [file] return True
Command/FromKey.hs view
@@ -45,5 +45,5 @@ cleanup :: FilePath -> CommandCleanup cleanup file = do- AnnexQueue.add "add" [Param "--"] file+ AnnexQueue.add "add" [Param "--"] [file] return True
Command/Fsck.hs view
@@ -94,7 +94,7 @@ fsckKey backend key file numcopies = do size_ok <- checkKeySize key copies_ok <- checkKeyNumCopies key file numcopies- backend_ok <-(Types.Backend.fsckKey backend) key+ backend_ok <- (Types.Backend.fsckKey backend) key return $ size_ok && copies_ok && backend_ok {- The size of the data for a key is checked against the size encoded in
Command/Get.hs view
@@ -75,7 +75,7 @@ Left _ -> return False else return True docopy r continue = do- showNote $ "from " ++ Remote.name r ++ "..."+ showAction $ "from " ++ Remote.name r copied <- Remote.retrieveKeyFile r key file if copied then return True
Command/InAnnex.hs view
@@ -25,4 +25,4 @@ present <- inAnnex key if present then stop- else liftIO $ exitFailure+ else liftIO exitFailure
Command/Init.hs view
@@ -7,19 +7,13 @@ module Command.Init where -import Control.Monad.State (liftIO)-import Control.Monad (when, unless)-import System.Directory+import Control.Monad (when) import Command import qualified Annex-import qualified Git-import qualified Branch import UUID-import Version import Messages-import Types-import Utility+import Init command :: [Command] command = [standaloneCommand "init" paramDesc seek@@ -39,34 +33,8 @@ perform :: String -> CommandPerform perform description = do- Branch.create+ initialize g <- Annex.gitRepo u <- getUUID g- setVersion describeUUID u description- unless (Git.repoIsLocalBare g) $- gitPreCommitHookWrite g next $ return True--{- set up a git pre-commit hook, if one is not already present -}-gitPreCommitHookWrite :: Git.Repo -> Annex ()-gitPreCommitHookWrite repo = do- exists <- liftIO $ doesFileExist hook- if exists- then warning $ "pre-commit hook (" ++ hook ++ ") already exists, not configuring"- else liftIO $ do- viaTmp writeFile hook preCommitScript- p <- getPermissions hook- setPermissions hook $ p {executable = True}- where- hook = preCommitHook repo--preCommitHook :: Git.Repo -> FilePath-preCommitHook repo = - Git.workTree repo ++ "/" ++ Git.gitDir repo ++ "/hooks/pre-commit"--preCommitScript :: String-preCommitScript = - "#!/bin/sh\n" ++- "# automatically configured by git-annex\n" ++ - "git annex pre-commit .\n"
Command/InitRemote.hs view
@@ -24,7 +24,7 @@ command :: [Command] command = [repoCommand "initremote" (paramPair paramName $- paramOptional $ paramRepeating $ paramKeyValue) seek+ paramOptional $ paramRepeating paramKeyValue) seek "sets up a special (non-git) remote"] seek :: [CommandSeek]@@ -32,7 +32,7 @@ start :: CommandStartWords start ws = do- when (null ws) $ needname+ when (null ws) needname (u, c) <- findByName name let fullconfig = M.union config c @@ -69,7 +69,7 @@ maybe generate return $ findByName' name m where generate = do- uuid <- liftIO $ genUUID+ uuid <- liftIO genUUID return (uuid, M.insert nameKey name M.empty) findByName' :: String -> M.Map UUID R.RemoteConfig -> Maybe (UUID, R.RemoteConfig)@@ -85,7 +85,7 @@ remoteNames :: Annex [String] remoteNames = do m <- RemoteLog.readRemoteLog- return $ catMaybes $ map ((M.lookup nameKey) . snd) $ M.toList m+ return $ mapMaybe (M.lookup nameKey . snd) $ M.toList m {- find the specified remote type -} findType :: R.RemoteConfig -> Annex (R.RemoteType Annex)
Command/Lock.hs view
@@ -33,5 +33,5 @@ -- Checkout from HEAD to get rid of any changes that might be -- staged in the index, and get back to the previous symlink to -- the content.- AnnexQueue.add "checkout" [Param "HEAD", Param "--"] file+ AnnexQueue.add "checkout" [Param "HEAD", Param "--"] [file] next $ return True -- no cleanup needed
Command/Map.hs view
@@ -12,6 +12,7 @@ import System.Cmd.Utils import qualified Data.Map as M import Data.List.Utils+import Data.Maybe import Command import qualified Annex@@ -21,7 +22,7 @@ import Utility import UUID import Trust-import Remote.Ssh+import Remote.Helper.Ssh import qualified Utility.Dot as Dot -- a link from the first repository to the second (its remote)@@ -43,7 +44,7 @@ liftIO $ writeFile file (drawMap rs umap trusted) showLongNote $ "running: dot -Tx11 " ++ file- showProgress+ showOutput r <- liftIO $ boolSystem "dot" [Param "-Tx11", File file] next $ next $ return r where@@ -58,7 +59,7 @@ - the repositories first, followed by uuids that were not matched - to a repository. -}-drawMap :: [Git.Repo] -> (M.Map UUID String) -> [UUID] -> String+drawMap :: [Git.Repo] -> M.Map UUID String -> [UUID] -> String drawMap rs umap ts = Dot.graph $ repos ++ trusted ++ others where repos = map (node umap rs) rs@@ -78,23 +79,23 @@ {- A name to display for a repo. Uses the name from uuid.log if available, - or the remote name if not. -}-repoName :: (M.Map UUID String) -> Git.Repo -> String+repoName :: M.Map UUID String -> Git.Repo -> String repoName umap r | null repouuid = fallback | otherwise = M.findWithDefault fallback repouuid umap where repouuid = getUncachedUUID r- fallback = maybe "unknown" id $ Git.repoRemoteName r+ fallback = fromMaybe "unknown" $ Git.repoRemoteName r {- A unique id for the node for a repo. Uses the annex.uuid if available. -} nodeId :: Git.Repo -> String nodeId r =- case (getUncachedUUID r) of+ case getUncachedUUID r of "" -> Git.repoLocation r u -> u {- A node representing a repo. -}-node :: (M.Map UUID String) -> [Git.Repo] -> Git.Repo -> String+node :: M.Map UUID String -> [Git.Repo] -> Git.Repo -> String node umap fullinfo r = unlines $ n:edges where n = Dot.subGraph (hostname r) (basehostname r) "lightblue" $@@ -105,14 +106,14 @@ | otherwise = reachable {- An edge between two repos. The second repo is a remote of the first. -}-edge :: (M.Map UUID String) -> [Git.Repo] -> Git.Repo -> Git.Repo -> String +edge :: M.Map UUID String -> [Git.Repo] -> Git.Repo -> Git.Repo -> String edge umap fullinfo from to = Dot.graphEdge (nodeId from) (nodeId fullto) edgename where -- get the full info for the remote, to get its UUID fullto = findfullinfo to findfullinfo n =- case (filter (same n) fullinfo) of+ case filter (same n) fullinfo of [] -> n (n':_) -> n' {- Only name an edge if the name is different than the name@@ -120,7 +121,7 @@ - different from its hostname. (This reduces visual clutter.) -} edgename = maybe Nothing calcname $ Git.repoRemoteName to calcname n- | n == repoName umap fullto || n == hostname fullto = Nothing+ | n `elem` [repoName umap fullto, hostname fullto] = Nothing | otherwise = Just n unreachable :: String -> String@@ -175,7 +176,7 @@ showEndOk return r' Nothing -> do- showProgress+ showOutput showEndFail return r @@ -188,7 +189,7 @@ | otherwise = safely $ Git.configRead r where safely a = do- result <- liftIO (try (a)::IO (Either SomeException Git.Repo))+ result <- liftIO (try a :: IO (Either SomeException Git.Repo)) case result of Left _ -> return Nothing Right r' -> return $ Just r'@@ -223,5 +224,5 @@ ok -> return ok sshnote = do- showNote "sshing..."- showProgress+ showAction "sshing"+ showOutput
Command/Migrate.hs view
@@ -72,7 +72,7 @@ then do -- Update symlink to use the new key. liftIO $ removeFile file- next $ Command.Add.cleanup file newkey+ next $ Command.Add.cleanup file newkey True else stop where cleantmp t = whenM (doesFileExist t) $ removeFile t
Command/Move.hs view
@@ -44,9 +44,9 @@ fromStart src move file (_ , _) -> error "only one of --from or --to can be specified" -showAction :: Bool -> FilePath -> Annex ()-showAction True file = showStart "move" file-showAction False file = showStart "copy" file+showMoveAction :: Bool -> FilePath -> Annex ()+showMoveAction True file = showStart "move" file+showMoveAction False file = showStart "copy" file {- Used to log a change in a remote's having a key. The change is logged - in the local repo, not on the remote. The process of transferring the@@ -77,7 +77,7 @@ if not ishere || u == Remote.uuid dest then stop -- not here, so nothing to do else do- showAction move file+ showMoveAction move file next $ toPerform dest move key toPerform :: Remote.Remote Annex -> Bool -> Key -> CommandPerform toPerform dest move key = do@@ -97,7 +97,7 @@ showNote $ show err stop Right False -> do- showNote $ "to " ++ Remote.name dest ++ "..."+ showAction $ "to " ++ Remote.name dest ok <- Remote.storeKey dest key if ok then next $ toCleanup dest move key@@ -124,10 +124,10 @@ g <- Annex.gitRepo u <- getUUID g remotes <- Remote.keyPossibilities key- if (u == Remote.uuid src) || (null $ filter (== src) remotes)+ if u == Remote.uuid src || not (any (== src) remotes) then stop else do- showAction move file+ showMoveAction move file next $ fromPerform src move key fromPerform :: Remote.Remote Annex -> Bool -> Key -> CommandPerform fromPerform src move key = do@@ -135,7 +135,7 @@ if ishere then next $ fromCleanup src move key else do- showNote $ "from " ++ Remote.name src ++ "..."+ showAction $ "from " ++ Remote.name src ok <- getViaTmp key $ Remote.retrieveKeyFile src key if ok then next $ fromCleanup src move key
Command/SetKey.hs view
@@ -16,11 +16,11 @@ import Messages command :: [Command]-command = [repoCommand "setkey" (paramPath) seek+command = [repoCommand "setkey" paramPath seek "sets annexed content for a key using a temp file"] seek :: [CommandSeek]-seek = [withTempFile start]+seek = [withStrings start] {- Sets cached content for a key. -} start :: CommandStartString@@ -34,7 +34,7 @@ -- the file might be on a different filesystem, so mv is used -- rather than simply calling moveToObjectDir; disk space is also -- checked this way.- ok <- getViaTmp key $ \dest -> do+ ok <- getViaTmp key $ \dest -> if dest /= file then liftIO $ boolSystem "mv" [File file, File dest]
Command/Status.hs view
@@ -32,8 +32,8 @@ -- cached info that multiple Stats may need data StatInfo = StatInfo- { keysPresentCache :: (Maybe (SizeList Key))- , keysReferencedCache :: (Maybe (SizeList Key))+ { keysPresentCache :: Maybe (SizeList Key)+ , keysReferencedCache :: Maybe (SizeList Key) } -- a state monad for running Stats in@@ -84,7 +84,7 @@ stat desc a = return $ Just (desc, a) nostat :: Stat-nostat = return $ Nothing+nostat = return Nothing showStat :: Stat -> StatState () showStat s = calc =<< s@@ -144,7 +144,7 @@ case keysPresentCache s of Just v -> return v Nothing -> do- keys <- lift $ getKeysPresent+ keys <- lift getKeysPresent let v = sizeList keys put s { keysPresentCache = Just v } return v@@ -155,7 +155,7 @@ case keysReferencedCache s of Just v -> return v Nothing -> do- keys <- lift $ Command.Unused.getKeysReferenced+ keys <- lift Command.Unused.getKeysReferenced -- A given key may be referenced repeatedly. -- nub does not seem too slow (yet).. let v = sizeList $ nub keys@@ -164,9 +164,9 @@ keySizeSum :: SizeList Key -> StatState String keySizeSum (keys, len) = do- let knownsize = catMaybes $ map keySize keys- let total = roughSize storageUnits False $ foldl (+) 0 knownsize- let missing = len - genericLength knownsize+ let knownsizes = mapMaybe keySize keys+ let total = roughSize storageUnits False $ sum knownsizes+ let missing = len - genericLength knownsizes return $ total ++ if missing > 0 then aside $ "but " ++ show missing ++ " keys have unknown size"
Command/Unannex.hs view
@@ -78,6 +78,6 @@ -- Commit staged changes at end to avoid confusing the -- pre-commit hook if this file is later added back to -- git as a normal, non-annexed file.- AnnexQueue.add "commit" [Params "-a -m", Param "content removed from git annex"] "-a"+ AnnexQueue.add "commit" [Param "-m", Param "content removed from git annex"] [] return True
Command/Uninit.hs view
@@ -12,13 +12,11 @@ import System.Exit import Command-import Messages-import Types import Utility import qualified Git import qualified Annex import qualified Command.Unannex-import qualified Command.Init+import Init import qualified Branch import Content import Locations@@ -47,21 +45,11 @@ cleanup :: CommandCleanup cleanup = do g <- Annex.gitRepo- gitPreCommitHookUnWrite g+ uninitialize mapM_ removeAnnex =<< getKeysPresent liftIO $ removeDirectoryRecursive (gitAnnexDir g) -- avoid normal shutdown saveState- liftIO $ Git.run g "branch" [Param "-D", Param Branch.name]- liftIO $ exitSuccess--gitPreCommitHookUnWrite :: Git.Repo -> Annex ()-gitPreCommitHookUnWrite repo = do- let hook = Command.Init.preCommitHook repo- whenM (liftIO $ doesFileExist hook) $ do- c <- liftIO $ readFile hook- if c == Command.Init.preCommitScript- then liftIO $ removeFile hook- else warning $ "pre-commit hook (" ++ hook ++ - ") contents modified; not deleting." ++- " Edit it to remove call to git annex."+ liftIO $ do+ Git.run g "branch" [Param "-D", Param Branch.name]+ exitSuccess
Command/Unlock.hs view
@@ -45,7 +45,7 @@ let src = gitAnnexLocation g key let tmpdest = gitAnnexTmpLocation g key liftIO $ createDirectoryIfMissing True (parentDir tmpdest)- showNote "copying..."+ showAction "copying" ok <- liftIO $ copyFile src tmpdest if ok then do
Command/Unused.hs view
@@ -7,7 +7,7 @@ module Command.Unused where -import Control.Monad (filterM, unless, forM_, when)+import Control.Monad (filterM, unless, forM_) import Control.Monad.State (liftIO) import qualified Data.Set as S import Data.Maybe@@ -55,9 +55,9 @@ where list file msg l c = do let unusedlist = number c l- when (not $ null l) $ do+ unless (null l) $ do showLongNote $ msg unusedlist- showLongNote $ "\n"+ showLongNote "\n" writeUnusedFile file unusedlist return $ c + length l @@ -68,7 +68,7 @@ checkRemoteUnused' :: Remote.Remote Annex -> Annex () checkRemoteUnused' r = do- showNote $ "checking for unused data..."+ showAction "checking for unused data" referenced <- getKeysReferenced remotehas <- filterM isthere =<< loggedKeys let remoteunused = remotehas `exclude` referenced@@ -76,7 +76,7 @@ writeUnusedFile "" list unless (null remoteunused) $ do showLongNote $ remoteUnusedMsg r list- showLongNote $ "\n"+ showLongNote "\n" where isthere k = do us <- keyLocations k@@ -90,14 +90,14 @@ unlines $ map (\(n, k) -> show n ++ " " ++ show k) l table :: [(Int, Key)] -> [String]-table l = [" NUMBER KEY"] ++ map cols l+table l = " NUMBER KEY" : map cols l where cols (n,k) = " " ++ pad 6 (show n) ++ " " ++ show k pad n s = s ++ replicate (n - length s) ' ' number :: Int -> [a] -> [(Int, a)] number _ [] = []-number n (x:xs) = (n+1, x):(number (n+1) xs)+number n (x:xs) = (n+1, x) : number (n+1) xs staleTmpMsg :: [(Int, Key)] -> String staleTmpMsg t = unlines $ @@ -152,7 +152,7 @@ bad <- staleKeys gitAnnexBadDir return ([], bad, tmp) else do- showNote "checking for unused data..."+ showAction "checking for unused data" present <- getKeysPresent referenced <- getKeysReferenced let unused = present `exclude` referenced@@ -210,4 +210,4 @@ contents <- liftIO $ getDirectoryContents dir files <- liftIO $ filterM doesFileExist $ map (dir </>) contents- return $ catMaybes $ map (fileKey . takeFileName) files+ return $ mapMaybe (fileKey . takeFileName) files
Command/Version.hs view
@@ -31,4 +31,4 @@ liftIO $ putStrLn $ "upgrade supported from repository versions: " ++ vs upgradableVersions stop where- vs l = join " " l+ vs = join " "
Command/Whereis.hs view
@@ -30,12 +30,12 @@ uuids <- keyLocations key let num = length uuids showNote $ show num ++ " " ++ copiesplural num- if null $ uuids+ if null uuids then stop else do pp <- prettyPrintUUIDs uuids- showLongNote $ pp- showProgress + showLongNote pp+ showOutput next $ return True where copiesplural 1 = "copy"
Config.hs view
@@ -9,6 +9,8 @@ import Data.Maybe import Control.Monad.State (liftIO)+import Control.Monad (liftM)+import System.Cmd.Utils import qualified Git import qualified Annex@@ -37,17 +39,23 @@ remoteConfig :: Git.Repo -> ConfigKey -> String remoteConfig r key = "remote." ++ fromMaybe "" (Git.repoRemoteName r) ++ ".annex-" ++ key -{- Calculates cost for a remote.- -- - The default cost is 100 for local repositories, and 200 for remote- - repositories; it can also be configured by remote.<name>.annex-cost+{- Calculates cost for a remote. Either the default, or as configured + - by remote.<name>.annex-cost, or if remote.<name>.annex-cost-command+ - is set and prints a number, that is used. -} remoteCost :: Git.Repo -> Int -> Annex Int remoteCost r def = do- c <- getConfig r "cost" ""- if not $ null c- then return $ read c- else return def+ cmd <- getConfig r "cost-command" ""+ return . safeparse =<< if not $ null cmd+ then liftM snd $ liftIO $ pipeFrom "sh" ["-c", cmd]+ else getConfig r "cost" ""+ where+ safeparse v+ | null ws || null ps = def+ | otherwise = (fst . head) ps+ where+ ws = words v+ ps = reads $ head ws cheapRemoteCost :: Int cheapRemoteCost = 100
Content.hs view
@@ -57,8 +57,8 @@ calcGitLink :: FilePath -> Key -> Annex FilePath calcGitLink file key = do g <- Annex.gitRepo- cwd <- liftIO $ getCurrentDirectory- let absfile = maybe whoops id $ absNormPath cwd file+ cwd <- liftIO getCurrentDirectory+ let absfile = fromMaybe whoops $ absNormPath cwd file return $ relPathDirToFile (parentDir absfile) (Git.workTree g) </> ".git" </> annexLocation key where@@ -94,15 +94,19 @@ getViaTmpUnchecked key action +prepTmp :: Key -> Annex FilePath+prepTmp key = do+ g <- Annex.gitRepo+ let tmp = gitAnnexTmpLocation g key+ liftIO $ createDirectoryIfMissing True (parentDir tmp)+ return tmp+ {- Like getViaTmp, but does not check that there is enough disk space - for the incoming key. For use when the key content is already on disk - and not being copied into place. -} getViaTmpUnchecked :: Key -> (FilePath -> Annex Bool) -> Annex Bool getViaTmpUnchecked key action = do- g <- Annex.gitRepo- let tmp = gitAnnexTmpLocation g key-- liftIO $ createDirectoryIfMissing True (parentDir tmp)+ tmp <- prepTmp key success <- action tmp if success then do@@ -117,9 +121,7 @@ {- Creates a temp file, runs an action on it, and cleans up the temp file. -} withTmp :: Key -> (FilePath -> Annex a) -> Annex a withTmp key action = do- g <- Annex.gitRepo- let tmp = gitAnnexTmpLocation g key- liftIO $ createDirectoryIfMissing True (parentDir tmp)+ tmp <- prepTmp key res <- action tmp liftIO $ whenM (doesFileExist tmp) $ liftIO $ removeFile tmp return res@@ -133,23 +135,21 @@ checkDiskSpace' adjustment key = do g <- Annex.gitRepo r <- getConfig g "diskreserve" ""- let reserve = maybe megabyte id $ readSize dataUnits r+ let reserve = fromMaybe megabyte $ readSize dataUnits r stats <- liftIO $ getFileSystemStats (gitAnnexDir g) case (stats, keySize key) of (Nothing, _) -> return () (_, Nothing) -> return () (Just (FileSystemStats { fsStatBytesAvailable = have }), Just need) ->- if (need + reserve > have + adjustment)- then needmorespace (need + reserve - have - adjustment)- else return ()+ when (need + reserve > have + adjustment) $+ needmorespace (need + reserve - have - adjustment) where megabyte :: Integer megabyte = 1000000- needmorespace n = do- unlessM (Annex.getState Annex.force) $- error $ "not enough free space, need " ++ - roughSize storageUnits True n ++- " more (use --force to override this check or adjust annex.diskreserve)"+ needmorespace n = unlessM (Annex.getState Annex.force) $+ error $ "not enough free space, need " ++ + roughSize storageUnits True n +++ " more (use --force to override this check or adjust annex.diskreserve)" {- Removes the write bits from a file. -} preventWrite :: FilePath -> IO ()@@ -200,28 +200,27 @@ preventWrite dest preventWrite dir -{- Removes a key's file from .git/annex/objects/ -}-removeAnnex :: Key -> Annex ()-removeAnnex key = do+withObjectLoc :: Key -> ((FilePath, FilePath) -> Annex a) -> Annex a+withObjectLoc key a = do g <- Annex.gitRepo let file = gitAnnexLocation g key let dir = parentDir file- liftIO $ do- allowWrite dir- removeFile file- removeDirectory dir+ a (dir, file) +{- Removes a key's file from .git/annex/objects/ -}+removeAnnex :: Key -> Annex ()+removeAnnex key = withObjectLoc key $ \(dir, file) -> liftIO $ do+ allowWrite dir+ removeFile file+ removeDirectory dir+ {- Moves a key's file out of .git/annex/objects/ -} fromAnnex :: Key -> FilePath -> Annex ()-fromAnnex key dest = do- g <- Annex.gitRepo- let file = gitAnnexLocation g key- let dir = parentDir file- liftIO $ do- allowWrite dir- allowWrite file- renameFile file dest- removeDirectory dir+fromAnnex key dest = withObjectLoc key $ \(dir, file) -> liftIO $ do+ allowWrite dir+ allowWrite file+ renameFile file dest+ removeDirectory dir {- Moves a key out of .git/annex/objects/ into .git/annex/bad, and - returns the file it was moved to. -}@@ -246,7 +245,7 @@ getKeysPresent' :: FilePath -> Annex [Key] getKeysPresent' dir = do exists <- liftIO $ doesDirectoryExist dir- if (not exists)+ if not exists then return [] else liftIO $ do -- 2 levels of hashing@@ -254,7 +253,7 @@ levelb <- mapM dirContents levela contents <- mapM dirContents (concat levelb) files <- filterM present (concat contents)- return $ catMaybes $ map (fileKey . takeFileName) files+ return $ mapMaybe (fileKey . takeFileName) files where present d = do result <- try $
Crypto.hs view
@@ -33,6 +33,7 @@ import System.Cmd.Utils import Data.String.Utils import Data.List+import Data.Maybe import System.IO import System.Posix.IO import System.Posix.Types@@ -125,11 +126,11 @@ return $ EncryptedCipher encipher (KeyIds ks') where encrypt = [ Params "--encrypt" ]- recipients l = - -- Force gpg to only encrypt to the specified- -- recipients, not configured defaults.- [ Params "--no-encrypt-to --no-default-recipient"] ++- (concat $ map (\k -> [Param "--recipient", Param k]) l)+ recipients l = force_recipients :+ concatMap (\k -> [Param "--recipient", Param k]) l+ -- Force gpg to only encrypt to the specified+ -- recipients, not configured defaults.+ force_recipients = Params "--no-encrypt-to --no-default-recipient" {- Decrypting an EncryptedCipher is expensive; the Cipher should be cached. -} decryptCipher :: RemoteConfig -> EncryptedCipher -> IO Cipher@@ -152,24 +153,24 @@ {- Runs an action, passing it a handle from which it can - stream encrypted content. -}-withEncryptedHandle :: Cipher -> (IO L.ByteString) -> (Handle -> IO a) -> IO a+withEncryptedHandle :: Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a withEncryptedHandle = gpgCipherHandle [Params "--symmetric --force-mdc"] {- Runs an action, passing it a handle from which it can - stream decrypted content. -}-withDecryptedHandle :: Cipher -> (IO L.ByteString) -> (Handle -> IO a) -> IO a+withDecryptedHandle :: Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a withDecryptedHandle = gpgCipherHandle [Param "--decrypt"] {- Streams encrypted content to an action. -}-withEncryptedContent :: Cipher -> (IO L.ByteString) -> (L.ByteString -> IO a) -> IO a+withEncryptedContent :: Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a withEncryptedContent = pass withEncryptedHandle {- Streams decrypted content to an action. -}-withDecryptedContent :: Cipher -> (IO L.ByteString) -> (L.ByteString -> IO a) -> IO a+withDecryptedContent :: Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a withDecryptedContent = pass withDecryptedHandle -pass :: (Cipher -> (IO L.ByteString) -> (Handle -> IO a) -> IO a) - -> Cipher -> (IO L.ByteString) -> (L.ByteString -> IO a) -> IO a+pass :: (Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a) + -> Cipher -> IO L.ByteString -> (L.ByteString -> IO a) -> IO a pass to c i a = to c i $ \h -> a =<< L.hGetContents h gpgParams :: [CommandParam] -> IO [String]@@ -202,7 +203,7 @@ - - Note that to avoid deadlock with the cleanup stage, - the action must fully consume gpg's input before returning. -}-gpgCipherHandle :: [CommandParam] -> Cipher -> (IO L.ByteString) -> (Handle -> IO a) -> IO a+gpgCipherHandle :: [CommandParam] -> Cipher -> IO L.ByteString -> (Handle -> IO a) -> IO a gpgCipherHandle params c a b = do -- pipe the passphrase into gpg on a fd (frompipe, topipe) <- createPipe@@ -235,10 +236,10 @@ where parseWithColons s = map keyIdField $ filter pubKey $ lines s pubKey = isPrefixOf "pub:"- keyIdField s = (split ":" s) !! 4+ keyIdField s = split ":" s !! 4 configGet :: RemoteConfig -> String -> String-configGet c key = maybe missing id $ M.lookup key c+configGet c key = fromMaybe missing $ M.lookup key c where missing = error $ "missing " ++ key ++ " in remote config" hmacWithCipher :: Cipher -> String -> String
Git.hs view
@@ -17,6 +17,7 @@ localToUrl, repoIsUrl, repoIsSsh,+ repoIsHttp, repoIsLocalBare, repoDescribe, repoLocation,@@ -69,11 +70,10 @@ import System.Posix.Process import System.Path import System.Cmd.Utils-import IO (bracket_)+import IO (bracket_, try) import Data.String.Utils import System.IO-import IO (try)-import qualified Data.Map as Map hiding (map, split)+import qualified Data.Map as M hiding (map, split) import Network.URI import Data.Maybe import Data.Char@@ -93,7 +93,7 @@ data Repo = Repo { location :: RepoLocation,- config :: Map.Map String String,+ config :: M.Map String String, remotes :: [Repo], -- remoteName holds the name used for this repo in remotes remoteName :: Maybe String @@ -103,7 +103,7 @@ newFrom l = Repo { location = l,- config = Map.empty,+ config = M.empty, remotes = [], remoteName = Nothing }@@ -140,7 +140,7 @@ | startswith "file://" url = repoFromAbsPath $ uriPath u | otherwise = return $ newFrom $ Url u where- u = maybe bad id $ parseURI url+ u = fromMaybe bad $ parseURI url bad = error $ "bad url " ++ url {- Creates a repo that has an unknown location. -}@@ -207,8 +207,15 @@ | otherwise = False repoIsSsh _ = False +repoIsHttp :: Repo -> Bool+repoIsHttp Repo { location = Url url } + | uriScheme url == "http:" = True+ | uriScheme url == "https:" = True+ | otherwise = False+repoIsHttp _ = False+ configAvail ::Repo -> Bool-configAvail Repo { config = c } = c /= Map.empty+configAvail Repo { config = c } = c /= M.empty repoIsLocalBare :: Repo -> Bool repoIsLocalBare r@(Repo { location = Dir _ }) = configAvail r && configBare r@@ -228,7 +235,7 @@ " not supported" configBare :: Repo -> Bool-configBare repo = maybe unknown configTrue $ Map.lookup "core.bare" $ config repo+configBare repo = maybe unknown configTrue $ M.lookup "core.bare" $ config repo where unknown = error $ "it is not known if git repo " ++ repoDescribe repo ++@@ -240,11 +247,11 @@ | configBare repo = workTree repo ++ "/info/.gitattributes" | otherwise = workTree repo ++ "/.gitattributes" -{- Path to a repository's .git directory, relative to its workTree. -}+{- Path to a repository's .git directory. -} gitDir :: Repo -> String gitDir repo- | configBare repo = ""- | otherwise = ".git"+ | configBare repo = workTree repo+ | otherwise = workTree repo </> ".git" {- Path to a repository's --work-tree, that is, its top. -@@ -272,14 +279,14 @@ let file' = absfile cwd unless (inrepo file') $ error $ file ++ " is not located inside git repository " ++ absrepo- if (inrepo $ addTrailingPathSeparator cwd)+ if inrepo $ addTrailingPathSeparator cwd then return $ relPathDirToFile cwd file' else return $ drop (length absrepo) file' where -- normalize both repo and file, so that repo -- will be substring of file absrepo = maybe bad addTrailingPathSeparator $ absNormPath "/" d- absfile c = maybe file id $ secureAbsNormPath c file+ absfile c = fromMaybe file $ secureAbsNormPath c file inrepo f = absrepo `isPrefixOf` f bad = error $ "bad repo" ++ repoDescribe repo workTreeFile repo _ = assertLocal repo $ error "internal"@@ -303,7 +310,7 @@ | rest !! len == ']' = take len rest | otherwise = x where- len = (length rest) - 1+ len = length rest - 1 fixup x = x {- Hostname of an URL repo. -}@@ -338,17 +345,17 @@ {- Constructs a git command line operating on the specified repo. -} gitCommandLine :: Repo -> [CommandParam] -> [CommandParam]-gitCommandLine repo@(Repo { location = Dir d} ) params =+gitCommandLine repo@(Repo { location = Dir _ } ) params = -- force use of specified repo via --git-dir and --work-tree- [ Param ("--git-dir=" ++ d ++ "/" ++ gitDir repo)- , Param ("--work-tree=" ++ d)+ [ Param ("--git-dir=" ++ gitDir repo)+ , Param ("--work-tree=" ++ workTree repo) ] ++ params gitCommandLine repo _ = assertLocal repo $ error "internal" {- Runs git in the specified repo. -} runBool :: Repo -> String -> [CommandParam] -> IO Bool runBool repo subcommand params = assertLocal repo $- boolSystem "git" (gitCommandLine repo ((Param subcommand):params))+ boolSystem "git" $ gitCommandLine repo $ Param subcommand : params {- Runs git in the specified repo, throwing an error if it fails. -} run :: Repo -> String -> [CommandParam] -> IO ()@@ -466,20 +473,31 @@ val <- hGetContentsStrict h configStore repo val -{- Parses a git config and returns a version of the repo using it. -}+{- Stores a git config into a repo, returning the new version of the repo.+ - The git config may be multiple lines, or a single line. Config settings+ - can be updated inrementally. -} configStore :: Repo -> String -> IO Repo configStore repo s = do- rs <- configRemotes r- return $ r { remotes = rs }+ let repo' = repo { config = configParse s `M.union` config repo }+ rs <- configRemotes repo'+ return $ repo' { remotes = rs }++{- Parses git config --list output into a config map. -}+configParse :: String -> M.Map String String+configParse s = M.fromList $ map pair $ lines s where- r = repo { config = configParse s }+ pair l = (key l, val l)+ key l = head $ keyval l+ val l = join sep $ drop 1 $ keyval l+ keyval l = split sep l :: [String]+ sep = "=" {- Calculates a list of a repo's configured remotes, by parsing its config. -} configRemotes :: Repo -> IO [Repo] configRemotes repo = mapM construct remotepairs where- remotepairs = Map.toList $ filterremotes $ config repo- filterremotes = Map.filterWithKey (\k _ -> isremote k)+ remotepairs = M.toList $ filterremotes $ config repo+ filterremotes = M.filterWithKey (\k _ -> isremote k) isremote k = startswith "remote." k && endswith ".url" k construct (k,v) = do r <- gen v@@ -488,39 +506,29 @@ | isURI v = repoFromUrl v | otherwise = repoFromRemotePath v repo -- git remotes can be written scp style -- [user@]host:dir- scpstyle v = ":" `isInfixOf` v && (not $ "//" `isInfixOf` v)+ scpstyle v = ":" `isInfixOf` v && not ("//" `isInfixOf` v) scptourl v = "ssh://" ++ host ++ slash dir where bits = split ":" v- host = bits !! 0+ host = head bits dir = join ":" $ drop 1 bits slash d | d == "" = "/~/" ++ dir- | d !! 0 == '/' = dir- | d !! 0 == '~' = '/':dir+ | head d == '/' = dir+ | head d == '~' = '/':dir | otherwise = "/~/" ++ dir {- Checks if a string from git config is a true value. -} configTrue :: String -> Bool configTrue s = map toLower s == "true" -{- Parses git config --list output into a config map. -}-configParse :: String -> Map.Map String String-configParse s = Map.fromList $ map pair $ lines s- where- pair l = (key l, val l)- key l = head $ keyval l- val l = join sep $ drop 1 $ keyval l- keyval l = split sep l :: [String]- sep = "="- {- Returns a single git config setting, or a default value if not set. -} configGet :: Repo -> String -> String -> String configGet repo key defaultValue = - Map.findWithDefault defaultValue key (config repo)+ M.findWithDefault defaultValue key (config repo) {- Access to raw config Map -}-configMap :: Repo -> Map.Map String String-configMap repo = config repo+configMap :: Repo -> M.Map String String+configMap = config {- Efficiently looks up a gitattributes value for each file in a list. -} checkAttr :: Repo -> String -> [FilePath] -> IO [(FilePath, String)]@@ -530,6 +538,7 @@ -- directory. Convert to absolute, and then convert the filenames -- in its output back to relative. cwd <- getCurrentDirectory+ let top = workTree repo let absfiles = map (absPathFrom cwd) files (_, fromh, toh) <- hPipeBoth "git" (toCommand params) _ <- forkProcess $ do@@ -539,19 +548,21 @@ exitSuccess hClose toh s <- hGetContents fromh- return $ map (topair $ cwd++"/") $ lines s+ return $ map (topair cwd top) $ lines s where params = gitCommandLine repo [Param "check-attr", Param attr, Params "-z --stdin"]- topair cwd l = (relfile, value)+ topair cwd top l = (relfile, value) where - relfile - | startswith cwd file = drop (length cwd) file- | otherwise = file+ relfile+ | startswith cwd' file = drop (length cwd') file+ | otherwise = relPathDirToFile top' file file = decodeGitFile $ join sep $ take end bits value = bits !! end end = length bits - 1 bits = split sep l sep = ": " ++ attr ++ ": "+ cwd' = cwd ++ "/"+ top' = top ++ "/" {- Some git commands output encoded filenames. Decode that (annoyingly - complex) encoding. -}@@ -676,8 +687,8 @@ seekUp want dir = do ok <- want dir if ok- then return (Just dir)- else case (parentDir dir) of+ then return $ Just dir+ else case parentDir dir of "" -> return Nothing d -> seekUp want d
Git/LsFiles.hs view
@@ -21,7 +21,7 @@ {- Scans for files that are checked into git at the specified locations. -} inRepo :: Repo -> [FilePath] -> IO [FilePath] inRepo repo l = pipeNullSplit repo $- [Params "ls-files --cached -z --"] ++ map File l+ Params "ls-files --cached -z --" : map File l {- Scans for files at the specified locations that are not checked into - git. -}@@ -44,12 +44,12 @@ staged' repo l middle = pipeNullSplit repo $ start ++ middle ++ end where start = [Params "diff --cached --name-only -z"]- end = [Param "--"] ++ map File l+ end = Param "--" : map File l {- Returns a list of files that have unstaged changes. -} changedUnstaged :: Repo -> [FilePath] -> IO [FilePath] changedUnstaged repo l = pipeNullSplit repo $- [Params "diff --name-only -z --"] ++ map File l+ Params "diff --name-only -z --" : map File l {- Returns a list of the files in the specified locations that are staged - for commit, and whose type has changed. -}@@ -65,4 +65,4 @@ typeChanged' repo l middle = pipeNullSplit repo $ start ++ middle ++ end where start = [Params "diff --name-only --diff-filter=T -z"]- end = [Param "--"] ++ map File l+ end = Param "--" : map File l
Git/Queue.hs view
@@ -18,7 +18,7 @@ import System.IO import System.Cmd.Utils import Data.String.Utils-import Control.Monad (unless, forM_)+import Control.Monad (forM_) import Utility import Git@@ -53,15 +53,15 @@ empty = Queue 0 M.empty {- Adds an action to a queue. -}-add :: Queue -> String -> [CommandParam] -> FilePath -> Queue-add (Queue n m) subcommand params file = Queue (n + 1) m'+add :: Queue -> String -> [CommandParam] -> [FilePath] -> Queue+add (Queue n m) subcommand params files = Queue (n + 1) m' where action = Action subcommand params -- There are probably few items in the map, but there -- can be a lot of files per item. So, optimise adding -- files.- m' = M.insertWith' const action files m- files = file:(M.findWithDefault [] action m)+ m' = M.insertWith' const action fs m+ fs = files ++ M.findWithDefault [] action m {- Number of items in a queue. -} size :: Queue -> Int@@ -79,11 +79,14 @@ {- Runs an Action on a list of files in a git repository. -- - Complicated by commandline length limits. -}+ - Complicated by commandline length limits.+ -+ - Intentionally runs the command even if the list of files is empty;+ - this allows queueing commands that do not need a list of files. -} runAction :: Repo -> Action -> [FilePath] -> IO ()-runAction repo action files = unless (null files) runxargs+runAction repo action files =+ pOpen WriteToPipe "xargs" ("-0":"git":params) feedxargs where- runxargs = pOpen WriteToPipe "xargs" ("-0":"git":params) feedxargs params = toCommand $ gitCommandLine repo (Param (getSubcommand action):getParams action) feedxargs h = hPutStr h $ join "\0" files
Git/UnionMerge.hs view
@@ -91,5 +91,5 @@ return $ Just $ update_index_line sha file where [_colonamode, _bmode, asha, bsha, _status] = words info- nullsha = take shaSize $ repeat '0'+ nullsha = replicate shaSize '0' unionmerge = unlines . nub . lines
GitAnnex.hs view
@@ -8,12 +8,14 @@ module GitAnnex where import System.Console.GetOpt+import Control.Monad.State (liftIO) import qualified Git import CmdLine import Command import Options import Utility+import Types import Types.TrustLevel import qualified Annex import qualified Remote@@ -102,9 +104,11 @@ , Option [] ["trust"] (ReqArg (Remote.forceTrust Trusted) paramRemote) "override trust setting" , Option [] ["semitrust"] (ReqArg (Remote.forceTrust SemiTrusted) paramRemote)- "override trust setting back to default value"+ "override trust setting back to default" , Option [] ["untrust"] (ReqArg (Remote.forceTrust UnTrusted) paramRemote) "override trust setting to untrusted"+ , Option ['c'] ["config"] (ReqArg setgitconfig "NAME=VALUE")+ "override git configuration setting" ] where setto v = Annex.changeState $ \s -> s { Annex.toremote = Just v }@@ -112,6 +116,11 @@ addexclude v = Annex.changeState $ \s -> s { Annex.exclude = v:Annex.exclude s } setnumcopies v = Annex.changeState $ \s -> s {Annex.forcenumcopies = readMaybe v } setkey v = Annex.changeState $ \s -> s { Annex.defaultkey = Just v }+ setgitconfig :: String -> Annex ()+ setgitconfig v = do+ g <- Annex.gitRepo+ g' <- liftIO $ Git.configStore g v+ Annex.changeState $ \s -> s { Annex.repo = g' } header :: String header = "Usage: git-annex command [option ..]"
INSTALL view
@@ -23,6 +23,7 @@ * [utf8-string](http://hackage.haskell.org/package/utf8-string) * [SHA](http://hackage.haskell.org/package/SHA) * [dataenc](http://hackage.haskell.org/package/dataenc)+ * [monad-control](http://hackage.haskell.org/package/monad-control) * [TestPack](http://hackage.haskell.org/cgi-bin/hackage-scripts/package/testpack) * [QuickCheck 2](http://hackage.haskell.org/package/QuickCheck) * [HTTP](http://hackage.haskell.org/package/HTTP)
+ Init.hs view
@@ -0,0 +1,88 @@+{- git-annex repository initialization+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Init (+ ensureInitialized,+ initialize,+ uninitialize+) where++import Control.Monad.State (liftIO)+import Control.Monad (unless)+import System.Directory++import qualified Annex+import qualified Git+import qualified Branch+import Version+import Messages+import Types+import Utility+import UUID++initialize :: Annex ()+initialize = do+ prepUUID+ Branch.create+ setVersion+ gitPreCommitHookWrite++uninitialize :: Annex ()+uninitialize = do+ gitPreCommitHookUnWrite++{- Will automatically initialize if there is already a git-annex+ branch from somewhere. Otherwise, require a manual init+ to avoid git-annex accidentially being run in git+ repos that did not intend to use it. -}+ensureInitialized :: Annex ()+ensureInitialized = getVersion >>= maybe needsinit checkVersion+ where+ needsinit = do+ annexed <- Branch.hasSomeBranch+ if annexed+ then initialize+ else error "First run: git-annex init"++{- set up a git pre-commit hook, if one is not already present -}+gitPreCommitHookWrite :: Annex ()+gitPreCommitHookWrite = unlessBare $ do+ hook <- preCommitHook+ exists <- liftIO $ doesFileExist hook+ if exists+ then warning $ "pre-commit hook (" ++ hook ++ ") already exists, not configuring"+ else liftIO $ do+ viaTmp writeFile hook preCommitScript+ p <- getPermissions hook+ setPermissions hook $ p {executable = True}++gitPreCommitHookUnWrite :: Annex ()+gitPreCommitHookUnWrite = unlessBare $ do+ hook <- preCommitHook+ whenM (liftIO $ doesFileExist hook) $ do+ c <- liftIO $ readFile hook+ if c == preCommitScript+ then liftIO $ removeFile hook+ else warning $ "pre-commit hook (" ++ hook ++ + ") contents modified; not deleting." +++ " Edit it to remove call to git annex."++unlessBare :: Annex () -> Annex ()+unlessBare a = do+ g <- Annex.gitRepo+ unless (Git.repoIsLocalBare g) a++preCommitHook :: Annex FilePath+preCommitHook = do+ g <- Annex.gitRepo+ return $ Git.gitDir g ++ "/hooks/pre-commit"++preCommitScript :: String+preCommitScript = + "#!/bin/sh\n" +++ "# automatically configured by git-annex\n" ++ + "git annex pre-commit .\n"
LocationLog.hs view
@@ -30,7 +30,6 @@ import qualified Branch import UUID import Types-import Types.Key import Locations import PresenceLog @@ -50,8 +49,7 @@ {- Finds all keys that have location log information. - (There may be duplicate keys in the list.) -} loggedKeys :: Annex [Key]-loggedKeys =- return . catMaybes . map (logFileKey . takeFileName) =<< Branch.files+loggedKeys = return . mapMaybe (logFileKey . takeFileName) =<< Branch.files {- The filename of the log file for a given key. -} logFile :: Key -> String
Locations.hs view
@@ -52,7 +52,7 @@ {- The directory git annex uses for local state, relative to the .git - directory -} annexDir :: FilePath-annexDir = addTrailingPathSeparator $ "annex"+annexDir = addTrailingPathSeparator "annex" {- The directory git annex uses for locally available object content, - relative to the .git directory -}@@ -167,8 +167,8 @@ -- a real word, use letters that appear less frequently. chars = ['0'..'9'] ++ "zqjxkmvwgpfZQJXKMVWGPF" cs = map (\x -> getc $ (shiftR w (6*x)) .&. 31) [0..7]- getc n = chars !! (fromIntegral n)+ getc n = chars !! fromIntegral n swap_pairs (x1:x2:xs) = x2:x1:swap_pairs xs swap_pairs _ = [] -- Last 2 will always be 00, so omit.- trim s = take 6 s+ trim = take 6
Messages.hs view
@@ -20,24 +20,32 @@ q <- Annex.getState Annex.quiet unless q a -showSideAction :: String -> Annex ()-showSideAction s = verbose $ liftIO $ putStrLn $ "(" ++ s ++ ")"- showStart :: String -> String -> Annex ()-showStart command file = verbose $ do- liftIO $ putStr $ command ++ " " ++ file ++ " "- liftIO $ hFlush stdout+showStart command file = verbose $ liftIO $ do+ putStr $ command ++ " " ++ file ++ " "+ hFlush stdout showNote :: String -> Annex ()-showNote s = verbose $ do- liftIO $ putStr $ "(" ++ s ++ ") "- liftIO $ hFlush stdout+showNote s = verbose $ liftIO $ do+ putStr $ "(" ++ s ++ ") "+ hFlush stdout +showAction :: String -> Annex ()+showAction s = showNote $ s ++ "..."+ showProgress :: Annex ()-showProgress = verbose $ liftIO $ putStr "\n"+showProgress = verbose $ liftIO $ do+ putStr "."+ hFlush stdout +showSideAction :: String -> Annex ()+showSideAction s = verbose $ liftIO $ putStrLn $ "(" ++ s ++ "...)"++showOutput :: Annex ()+showOutput = verbose $ liftIO $ putStr "\n"+ showLongNote :: String -> Annex ()-showLongNote s = verbose $ liftIO $ putStr $ "\n" ++ indent s+showLongNote s = verbose $ liftIO $ putStr $ '\n' : indent s showEndOk :: Annex () showEndOk = verbose $ liftIO $ putStrLn "ok"@@ -50,15 +58,16 @@ showEndResult False = showEndFail showErr :: (Show a) => a -> Annex ()-showErr e = do- liftIO $ hFlush stdout- liftIO $ hPutStrLn stderr $ "git-annex: " ++ show e+showErr e = liftIO $ do+ hFlush stdout+ hPutStrLn stderr $ "git-annex: " ++ show e warning :: String -> Annex () warning w = do verbose $ liftIO $ putStr "\n"- liftIO $ hFlush stdout- liftIO $ hPutStrLn stderr $ indent w+ liftIO $ do+ hFlush stdout+ hPutStrLn stderr $ indent w indent :: String -> String indent s = join "\n" $ map (\l -> " " ++ l) $ lines s
PresenceLog.hs view
@@ -15,10 +15,12 @@ LogStatus(..), addLog, readLog,+ parseLog, writeLog, logNow, compactLog,- currentLog+ currentLog,+ LogLine ) where import Data.Time.Clock.POSIX@@ -94,7 +96,7 @@ {- Generates a new LogLine with the current date. -} logNow :: LogStatus -> String -> Annex LogLine logNow s i = do- now <- liftIO $ getPOSIXTime+ now <- liftIO getPOSIXTime return $ LogLine now s i {- Reads a log and returns only the info that is still in effect. -}@@ -112,7 +114,7 @@ {- Compacts a set of logs, returning a subset that contains the current - status. -} compactLog :: [LogLine] -> [LogLine]-compactLog ls = compactLog' Map.empty ls+compactLog = compactLog' Map.empty compactLog' :: LogMap -> [LogLine] -> [LogLine] compactLog' m [] = Map.elems m compactLog' m (l:ls) = compactLog' (mapLog m l) ls
Remote.hs view
@@ -33,6 +33,7 @@ import Data.List import qualified Data.Map as M import Data.String.Utils+import Data.Maybe import Types import Types.Remote@@ -97,7 +98,7 @@ byName' n = do allremotes <- genList let match = filter matching allremotes- if (null match)+ if null match then return $ Left $ "there is no git remote named \"" ++ n ++ "\"" else return $ Right $ head match where@@ -110,7 +111,7 @@ nameToUUID n = do res <- byName' n case res of- Left e -> return . (maybe (error e) id) =<< byDescription+ Left e -> return . fromMaybe (error e) =<< byDescription Right r -> return $ uuid r where byDescription = return . M.lookup n . invertMap =<< uuidMap@@ -122,7 +123,7 @@ prettyPrintUUIDs uuids = do here <- getUUID =<< Annex.gitRepo -- Show descriptions from the uuid log, falling back to remote names,- -- as some remotes may not be in the uuid log.+ -- as some remotes may not be in the uuid log m <- liftM2 M.union uuidMap $ return . M.fromList . map (\r -> (uuid r, name r)) =<< genList return $ unwords $ map (\u -> "\t" ++ prettify m u here ++ "\n") uuids
Remote/Bup.hs view
@@ -8,7 +8,8 @@ module Remote.Bup (remote) where import qualified Data.ByteString.Lazy.Char8 as L-import IO+import System.IO+import System.IO.Error import Control.Exception.Extensible (IOException) import qualified Data.Map as M import Control.Monad (when)@@ -16,6 +17,7 @@ import System.Process import System.Exit import System.FilePath+import Data.Maybe import Data.List.Utils import System.Cmd.Utils @@ -28,9 +30,9 @@ import Config import Utility import Messages-import Remote.Ssh-import Remote.Special-import Remote.Encryptable+import Remote.Helper.Ssh+import Remote.Helper.Special+import Remote.Helper.Encryptable import Crypto type BupRepo = String@@ -68,13 +70,13 @@ bupSetup :: UUID -> RemoteConfig -> Annex RemoteConfig bupSetup u c = do -- verify configuration is sane- let buprepo = maybe (error "Specify buprepo=") id $+ let buprepo = fromMaybe (error "Specify buprepo=") $ M.lookup "buprepo" c c' <- encryptionSetup c -- bup init will create the repository. -- (If the repository already exists, bup init again appears safe.)- showNote "bup init"+ showAction "bup init" bup "init" buprepo [] >>! error "bup init failed" storeBupUUID u buprepo@@ -87,11 +89,11 @@ bupParams :: String -> BupRepo -> [CommandParam] -> [CommandParam] bupParams command buprepo params = - (Param command) : [Param "-r", Param buprepo] ++ params+ Param command : [Param "-r", Param buprepo] ++ params bup :: String -> BupRepo -> [CommandParam] -> Annex Bool bup command buprepo params = do- showProgress -- make way for bup output+ showOutput -- make way for bup output liftIO $ boolSystem "bup" $ bupParams command buprepo params pipeBup :: [CommandParam] -> Maybe Handle -> Maybe Handle -> IO Bool@@ -107,7 +109,7 @@ bupSplitParams r buprepo k src = do o <- getConfig r "bup-split-options" "" let os = map Param $ words o- showProgress -- make way for bup output+ showOutput -- make way for bup output return $ bupParams "split" buprepo (os ++ [Param "-n", Param (show k), src]) @@ -123,8 +125,8 @@ g <- Annex.gitRepo let src = gitAnnexLocation g k params <- bupSplitParams r buprepo enck (Param "-")- liftIO $ catchBool $ do- withEncryptedHandle cipher (L.readFile src) $ \h -> do+ liftIO $ catchBool $+ withEncryptedHandle cipher (L.readFile src) $ \h -> pipeBup params (Just h) Nothing retrieve :: BupRepo -> Key -> FilePath -> Annex Bool@@ -155,7 +157,7 @@ checkPresent :: Git.Repo -> Git.Repo -> Key -> Annex (Either IOException Bool) checkPresent r bupr k | Git.repoIsUrl bupr = do- showNote ("checking " ++ Git.repoDescribe r ++ "...")+ showAction $ "checking " ++ Git.repoDescribe r ok <- onBupRemote bupr boolSystem "git" params return $ Right ok | otherwise = liftIO $ try $ boolSystem "git" $ Git.gitCommandLine bupr params@@ -170,7 +172,7 @@ r <- liftIO $ bup2GitRemote buprepo if Git.repoIsUrl r then do- showNote "storing uuid"+ showAction "storing uuid" onBupRemote r boolSystem "git" [Params $ "config annex.uuid " ++ u] >>! error "ssh failed"@@ -184,7 +186,7 @@ onBupRemote r a command params = do let dir = shellEscape (Git.workTree r) sshparams <- sshToRepo r [Param $- "cd " ++ dir ++ " && " ++ (unwords $ command : toCommand params)]+ "cd " ++ dir ++ " && " ++ unwords (command : toCommand params)] liftIO $ a "ssh" sshparams {- Allow for bup repositories on removable media by checking@@ -215,20 +217,20 @@ Git.repoFromAbsPath $ h </> ".bup" bup2GitRemote r | bupLocal r = - if r !! 0 == '/'+ if head r == '/' then Git.repoFromAbsPath r else error "please specify an absolute path" | otherwise = Git.repoFromUrl $ "ssh://" ++ host ++ slash dir where bits = split ":" r- host = bits !! 0+ host = head bits dir = join ":" $ drop 1 bits -- "host:~user/dir" is not supported specially by bup; -- "host:dir" is relative to the home directory; -- "host:" goes in ~/.bup slash d | d == "" = "/~/.bup"- | d !! 0 == '/' = d+ | head d == '/' = d | otherwise = "/~/" ++ d bupLocal :: BupRepo -> Bool
Remote/Directory.hs view
@@ -8,13 +8,14 @@ module Remote.Directory (remote) where import qualified Data.ByteString.Lazy.Char8 as L-import IO+import System.IO.Error import Control.Exception.Extensible (IOException) import qualified Data.Map as M import Control.Monad (when) import Control.Monad.State (liftIO) import System.Directory hiding (copyFile) import System.FilePath+import Data.Maybe import Types import Types.Remote@@ -26,8 +27,8 @@ import Config import Content import Utility-import Remote.Special-import Remote.Encryptable+import Remote.Helper.Special+import Remote.Helper.Encryptable import Crypto remote :: RemoteType Annex@@ -60,7 +61,7 @@ directorySetup :: UUID -> RemoteConfig -> Annex RemoteConfig directorySetup u c = do -- verify configuration is sane- let dir = maybe (error "Specify directory=") id $+ let dir = fromMaybe (error "Specify directory=") $ M.lookup "directory" c liftIO $ doesDirectoryExist dir >>! error $ "Directory does not exist: " ++ dir
− Remote/Encryptable.hs
@@ -1,87 +0,0 @@-{- common functions for encryptable remotes- -- - Copyright 2011 Joey Hess <joey@kitenet.net>- -- - Licensed under the GNU GPL version 3 or higher.- -}--module Remote.Encryptable where--import qualified Data.Map as M-import Control.Monad.State (liftIO)--import Types-import Types.Remote-import Crypto-import qualified Annex-import Messages-import Config--{- Encryption setup for a remote. The user must specify whether to use- - an encryption key, or not encrypt. An encrypted cipher is created, or is- - updated to be accessible to an additional encryption key. -}-encryptionSetup :: RemoteConfig -> Annex RemoteConfig-encryptionSetup c =- case (M.lookup "encryption" c, extractCipher c) of- (Nothing, Nothing) -> error "Specify encryption=key or encryption=none"- (Just "none", Nothing) -> return c- (Just "none", Just _) -> error "Cannot change encryption type of existing remote."- (Nothing, Just _) -> return c- (Just _, Nothing) -> use "encryption setup" $ genCipher c- (Just _, Just v) -> use "encryption updated" $ updateCipher c v- where- use m a = do- cipher <- liftIO a- showNote $ m ++ " " ++ describeCipher cipher- return $ M.delete "encryption" $ storeCipher c cipher--{- Modifies a Remote to support encryption.- -- - Two additional functions must be provided by the remote,- - to support storing and retrieving encrypted content. -}-encryptableRemote- :: Maybe RemoteConfig- -> ((Cipher, Key) -> Key -> Annex Bool)- -> ((Cipher, Key) -> FilePath -> Annex Bool)- -> Remote Annex - -> Remote Annex-encryptableRemote c storeKeyEncrypted retrieveKeyFileEncrypted r = - r {- storeKey = store,- retrieveKeyFile = retrieve,- removeKey = withkey $ removeKey r,- hasKey = withkey $ hasKey r,- cost = cost r + encryptedRemoteCostAdj- }- where- store k = cip k >>= maybe- (storeKey r k)- (\x -> storeKeyEncrypted x k)- retrieve k f = cip k >>= maybe- (retrieveKeyFile r k f)- (\x -> retrieveKeyFileEncrypted x f)- withkey a k = cip k >>= maybe (a k) (a . snd)- cip = cipherKey c--{- Gets encryption Cipher. The decrypted Cipher is cached in the Annex- - state. -}-remoteCipher :: RemoteConfig -> Annex (Maybe Cipher)-remoteCipher c = maybe expensive cached =<< Annex.getState Annex.cipher- where- cached cipher = return $ Just cipher- expensive = case extractCipher c of- Nothing -> return Nothing- Just encipher -> do- showNote "gpg"- cipher <- liftIO $ decryptCipher c encipher- Annex.changeState (\s -> s { Annex.cipher = Just cipher })- return $ Just cipher--{- Gets encryption Cipher, and encrypted version of Key. -}-cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key))-cipherKey Nothing _ = return Nothing-cipherKey (Just c) k = remoteCipher c >>= maybe (return Nothing) encrypt- where- encrypt ciphertext = do- k' <- liftIO $ encryptKey ciphertext k- return $ Just (ciphertext, k')
Remote/Git.hs view
@@ -12,6 +12,7 @@ import qualified Data.Map as M import System.Cmd.Utils import System.Posix.Files+import System.IO import Types import Types.Remote@@ -24,8 +25,10 @@ import Messages import Utility.CopyFile import Utility.RsyncFile-import Remote.Ssh+import Remote.Helper.Ssh+import qualified Remote.Helper.Url as Url import Config+import Init remote :: RemoteType Annex remote = RemoteType {@@ -57,7 +60,7 @@ let defcst = if cheap then cheapRemoteCost else expensiveRemoteCost cst <- remoteCost r' defcst - return $ Remote {+ return Remote { uuid = u', cost = cst, name = Git.repoDescribe r',@@ -75,19 +78,32 @@ tryGitConfigRead r | not $ M.null $ Git.configMap r = return r -- already read | Git.repoIsSsh r = store $ onRemote r (pipedconfig, r) "configlist" []+ | Git.repoIsHttp r = store $ safely $ geturlconfig | Git.repoIsUrl r = return r- | otherwise = store $ safely $ Git.configRead r+ | otherwise = store $ safely $ do+ onLocal r ensureInitialized+ Git.configRead r where -- Reading config can fail due to IO error or -- for other reasons; catch all possible exceptions. safely a = do- result <- liftIO (try (a)::IO (Either SomeException Git.Repo))+ result <- liftIO (try a :: IO (Either SomeException Git.Repo)) case result of Left _ -> return r Right r' -> return r'+ pipedconfig cmd params = safely $ pOpen ReadFromPipe cmd (toCommand params) $ Git.hConfigRead r++ geturlconfig = do+ s <- Url.get (Git.repoLocation r ++ "/config")+ withTempFile "git-annex.tmp" $ \tmpfile -> \h -> do+ hPutStr h s+ hClose h+ pOpen ReadFromPipe "git" ["config", "--list", "--file", tmpfile] $+ Git.hConfigRead r+ store a = do r' <- a g <- Annex.gitRepo@@ -95,6 +111,7 @@ let g' = Git.remotesAdd g $ exchange l r' Annex.changeState $ \s -> s { Annex.repo = g' } return r'+ exchange [] _ = [] exchange (old:ls) new = if Git.repoRemoteName old == Git.repoRemoteName new@@ -105,24 +122,34 @@ - If the remote cannot be accessed, returns a Left error. -} inAnnex :: Git.Repo -> Key -> Annex (Either IOException Bool)-inAnnex r key = if Git.repoIsUrl r- then checkremote- else liftIO (try checklocal ::IO (Either IOException Bool))+inAnnex r key+ | Git.repoIsHttp r = safely checkhttp+ | Git.repoIsUrl r = checkremote+ | otherwise = safely checklocal where- checklocal = do- -- run a local check inexpensively,- -- by making an Annex monad using the remote- a <- Annex.new r- Annex.eval a (Content.inAnnex key)+ checklocal = onLocal r (Content.inAnnex key) checkremote = do- showNote ("checking " ++ Git.repoDescribe r ++ "...")+ showAction $ "checking " ++ Git.repoDescribe r inannex <- onRemote r (boolSystem, False) "inannex" [Param (show key)] return $ Right inannex- + checkhttp = Url.exists $ keyUrl r key+ safely a = liftIO (try a ::IO (Either IOException Bool))++{- Runs an action on a local repository inexpensively, by making an annex+ - monad using that repository. -}+onLocal :: Git.Repo -> Annex a -> IO a+onLocal r a = do+ annex <- Annex.new r+ Annex.eval annex a++keyUrl :: Git.Repo -> Key -> String+keyUrl r key = Git.repoLocation r ++ "/" ++ annexLocation key+ dropKey :: Git.Repo -> Key -> Annex Bool-dropKey r key = - onRemote r (boolSystem, False) "dropkey"+dropKey r key+ | Git.repoIsHttp r = error "dropping from http repo not supported"+ | otherwise = onRemote r (boolSystem, False) "dropkey" [ Params "--quiet --force" , Param $ show key ]@@ -132,8 +159,9 @@ copyFromRemote r key file | not $ Git.repoIsUrl r = rsyncOrCopyFile r (gitAnnexLocation r key) file | Git.repoIsSsh r = rsyncHelper =<< rsyncParamsRemote r True key file- | otherwise = error "copying from non-ssh repo not supported"- + | Git.repoIsHttp r = Url.download (keyUrl r key) file+ | otherwise = error "copying from non-ssh, non-http repo not supported"+ {- Tries to copy a key's content to a remote's annex. -} copyToRemote :: Git.Repo -> Key -> Annex Bool copyToRemote r key@@ -141,22 +169,20 @@ g <- Annex.gitRepo let keysrc = gitAnnexLocation g key -- run copy from perspective of remote- liftIO $ do- a <- Annex.new r- Annex.eval a $ do- ok <- Content.getViaTmp key $- rsyncOrCopyFile r keysrc- Content.saveState- return ok+ liftIO $ onLocal r $ do+ ok <- Content.getViaTmp key $+ rsyncOrCopyFile r keysrc+ Content.saveState+ return ok | Git.repoIsSsh r = do g <- Annex.gitRepo let keysrc = gitAnnexLocation g key rsyncHelper =<< rsyncParamsRemote r False key keysrc | otherwise = error "copying to non-ssh repo not supported" -rsyncHelper :: [CommandParam] -> Annex (Bool)+rsyncHelper :: [CommandParam] -> Annex Bool rsyncHelper p = do- showProgress -- make way for progress bar+ showOutput -- make way for progress bar res <- liftIO $ rsync p if res then return res
+ Remote/Helper/Encryptable.hs view
@@ -0,0 +1,87 @@+{- common functions for encryptable remotes+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Remote.Helper.Encryptable where++import qualified Data.Map as M+import Control.Monad.State (liftIO)++import Types+import Types.Remote+import Crypto+import qualified Annex+import Messages+import Config++{- Encryption setup for a remote. The user must specify whether to use+ - an encryption key, or not encrypt. An encrypted cipher is created, or is+ - updated to be accessible to an additional encryption key. -}+encryptionSetup :: RemoteConfig -> Annex RemoteConfig+encryptionSetup c =+ case (M.lookup "encryption" c, extractCipher c) of+ (Nothing, Nothing) -> error "Specify encryption=key or encryption=none"+ (Just "none", Nothing) -> return c+ (Just "none", Just _) -> error "Cannot change encryption type of existing remote."+ (Nothing, Just _) -> return c+ (Just _, Nothing) -> use "encryption setup" $ genCipher c+ (Just _, Just v) -> use "encryption updated" $ updateCipher c v+ where+ use m a = do+ cipher <- liftIO a+ showNote $ m ++ " " ++ describeCipher cipher+ return $ M.delete "encryption" $ storeCipher c cipher++{- Modifies a Remote to support encryption.+ -+ - Two additional functions must be provided by the remote,+ - to support storing and retrieving encrypted content. -}+encryptableRemote+ :: Maybe RemoteConfig+ -> ((Cipher, Key) -> Key -> Annex Bool)+ -> ((Cipher, Key) -> FilePath -> Annex Bool)+ -> Remote Annex + -> Remote Annex+encryptableRemote c storeKeyEncrypted retrieveKeyFileEncrypted r = + r {+ storeKey = store,+ retrieveKeyFile = retrieve,+ removeKey = withkey $ removeKey r,+ hasKey = withkey $ hasKey r,+ cost = cost r + encryptedRemoteCostAdj+ }+ where+ store k = cip k >>= maybe+ (storeKey r k)+ (`storeKeyEncrypted` k)+ retrieve k f = cip k >>= maybe+ (retrieveKeyFile r k f)+ (`retrieveKeyFileEncrypted` f)+ withkey a k = cip k >>= maybe (a k) (a . snd)+ cip = cipherKey c++{- Gets encryption Cipher. The decrypted Cipher is cached in the Annex+ - state. -}+remoteCipher :: RemoteConfig -> Annex (Maybe Cipher)+remoteCipher c = maybe expensive cached =<< Annex.getState Annex.cipher+ where+ cached cipher = return $ Just cipher+ expensive = case extractCipher c of+ Nothing -> return Nothing+ Just encipher -> do+ showNote "gpg"+ cipher <- liftIO $ decryptCipher c encipher+ Annex.changeState (\s -> s { Annex.cipher = Just cipher })+ return $ Just cipher++{- Gets encryption Cipher, and encrypted version of Key. -}+cipherKey :: Maybe RemoteConfig -> Key -> Annex (Maybe (Cipher, Key))+cipherKey Nothing _ = return Nothing+cipherKey (Just c) k = remoteCipher c >>= maybe (return Nothing) encrypt+ where+ encrypt ciphertext = do+ k' <- liftIO $ encryptKey ciphertext k+ return $ Just (ciphertext, k')
+ Remote/Helper/Special.hs view
@@ -0,0 +1,44 @@+{- common functions for special remotes+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Remote.Helper.Special where++import qualified Data.Map as M+import Data.Maybe+import Data.String.Utils+import Control.Monad.State (liftIO)++import Types+import Types.Remote+import qualified Git+import qualified Annex+import UUID+import Utility++{- Special remotes don't have a configured url, so Git.Repo does not+ - automatically generate remotes for them. This looks for a different+ - configuration key instead.+ -}+findSpecialRemotes :: String -> Annex [Git.Repo]+findSpecialRemotes s = do+ g <- Annex.gitRepo+ return $ map construct $ remotepairs g+ where+ remotepairs r = M.toList $ M.filterWithKey match $ Git.configMap r+ construct (k,_) = Git.repoRemoteNameSet Git.repoFromUnknown k+ match k _ = startswith "remote." k && endswith (".annex-"++s) k++{- Sets up configuration for a special remote in .git/config. -}+gitConfigSpecialRemote :: UUID -> RemoteConfig -> String -> String -> Annex ()+gitConfigSpecialRemote u c k v = do+ g <- Annex.gitRepo+ liftIO $ do+ Git.run g "config" [Param (configsetting $ "annex-"++k), Param v]+ Git.run g "config" [Param (configsetting "annex-uuid"), Param u]+ where+ remotename = fromJust (M.lookup "name" c)+ configsetting s = "remote." ++ remotename ++ "." ++ s
+ Remote/Helper/Ssh.hs view
@@ -0,0 +1,61 @@+{- git-annex remote access with ssh+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Remote.Helper.Ssh where++import Control.Monad.State (liftIO)++import qualified Git+import Utility+import Types+import Config++{- Generates parameters to ssh to a repository's host and run a command.+ - Caller is responsible for doing any neccessary shellEscaping of the+ - passed command. -}+sshToRepo :: Git.Repo -> [CommandParam] -> Annex [CommandParam]+sshToRepo repo sshcmd = do+ s <- getConfig repo "ssh-options" ""+ let sshoptions = map Param (words s)+ let sshport = case Git.urlPort repo of+ Nothing -> []+ Just p -> [Param "-p", Param (show p)]+ let sshhost = Param $ Git.urlHostUser repo+ return $ sshoptions ++ sshport ++ [sshhost] ++ sshcmd++{- Generates parameters to run a git-annex-shell command on a remote+ - repository. -}+git_annex_shell :: Git.Repo -> String -> [CommandParam] -> Annex (Maybe (FilePath, [CommandParam]))+git_annex_shell r command params+ | not $ Git.repoIsUrl r = return $ Just (shellcmd, shellopts)+ | Git.repoIsSsh r = do+ sshparams <- sshToRepo r [Param sshcmd]+ return $ Just ("ssh", sshparams)+ | otherwise = return Nothing+ where+ dir = Git.workTree r+ shellcmd = "git-annex-shell"+ shellopts = Param command : File dir : params+ sshcmd = shellcmd ++ " " ++ + unwords (map shellEscape $ toCommand shellopts)++{- Uses a supplied function (such as boolSystem) to run a git-annex-shell+ - command on a remote.+ -+ - Or, if the remote does not support running remote commands, returns+ - a specified error value. -}+onRemote + :: Git.Repo+ -> (FilePath -> [CommandParam] -> IO a, a)+ -> String+ -> [CommandParam]+ -> Annex a+onRemote r (with, errorval) command params = do+ s <- git_annex_shell r command params+ case s of+ Just (c, ps) -> liftIO $ with c ps+ Nothing -> return errorval
+ Remote/Helper/Url.hs view
@@ -0,0 +1,66 @@+{- Url downloading for remotes.+ -+ - Copyright 2011 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Remote.Helper.Url (+ exists,+ download,+ get+) where++import Control.Monad (liftM)+import Control.Monad.State (liftIO)+import qualified Network.Browser as Browser+import Network.HTTP+import Network.URI++import Types+import Messages+import Utility++type URLString = String++{- Checks that an url exists and could be successfully downloaded. -}+exists :: URLString -> IO Bool+exists url =+ case parseURI url of+ Nothing -> return False+ Just u -> do+ r <- request u HEAD+ case rspCode r of+ (2,_,_) -> return True+ _ -> return False++{- Used to download large files, such as the contents of keys.+ - Uses curl program for its progress bar. -}+download :: URLString -> FilePath -> Annex Bool+download url file = do+ showOutput -- make way for curl progress bar+ liftIO $ boolSystem "curl" [Params "-L -C - -# -o", File file, File url]++{- Downloads a small file. -}+get :: URLString -> IO String+get url =+ case parseURI url of+ Nothing -> error "url parse error"+ Just u -> do+ r <- request u GET+ case rspCode r of+ (2,_,_) -> return $ rspBody r+ _ -> error $ rspReason r++{- Makes a http request of an url. For example, HEAD can be used to+ - check if the url exists, or GET used to get the url content (best for+ - small urls). -}+request :: URI -> RequestMethod -> IO (Response String)+request url requesttype = Browser.browse $ do+ Browser.setErrHandler ignore+ Browser.setOutHandler ignore+ Browser.setAllowRedirects True+ liftM snd $ Browser.request+ (mkRequest requesttype url :: Request_String)+ where+ ignore = const $ return ()
Remote/Hook.hs view
@@ -17,6 +17,7 @@ import System.IO import System.IO.Error (try) import System.Exit+import Data.Maybe import Types import Types.Remote@@ -27,8 +28,8 @@ import Config import Content import Utility-import Remote.Special-import Remote.Encryptable+import Remote.Helper.Special+import Remote.Helper.Encryptable import Crypto import Messages @@ -61,7 +62,7 @@ hookSetup :: UUID -> RemoteConfig -> Annex RemoteConfig hookSetup u c = do- let hooktype = maybe (error "Specify hooktype=") id $+ let hooktype = fromMaybe (error "Specify hooktype=") $ M.lookup "hooktype" c c' <- encryptionSetup c gitConfigSpecialRemote u c' "hooktype" hooktype@@ -73,12 +74,13 @@ env s v = ("ANNEX_" ++ s, v) keyenv = [ env "KEY" (show k)- , env "HASH_1" (hashbits !! 0)- , env "HASH_2" (hashbits !! 1)+ , env "HASH_1" hash_1+ , env "HASH_2" hash_2 ] fileenv Nothing = [] fileenv (Just file) = [env "FILE" file]- hashbits = map takeDirectory $ splitPath $ hashDirMixed k+ [hash_1, hash_2, _rest] =+ map takeDirectory $ splitPath $ hashDirMixed k lookupHook :: String -> String -> Annex (Maybe String) lookupHook hooktype hook =do@@ -96,7 +98,7 @@ runHook hooktype hook k f a = maybe (return False) run =<< lookupHook hooktype hook where run command = do- showProgress -- make way for hook output+ showOutput -- make way for hook output res <- liftIO $ boolSystemEnv "sh" [Param "-c", Param command] $ hookEnv k f if res@@ -127,15 +129,15 @@ return True remove :: String -> Key -> Annex Bool-remove h k = runHook h "remove" k Nothing $ do return True+remove h k = runHook h "remove" k Nothing $ return True checkPresent :: Git.Repo -> String -> Key -> Annex (Either IOException Bool) checkPresent r h k = do- showNote ("checking " ++ Git.repoDescribe r ++ "...")+ showAction $ "checking " ++ Git.repoDescribe r v <- lookupHook h "checkpresent" liftIO (try (check v) ::IO (Either IOException Bool)) where- findkey s = (show k) `elem` (lines s)+ findkey s = show k `elem` lines s env = hookEnv k Nothing check Nothing = error "checkpresent hook misconfigured" check (Just hook) = do@@ -150,5 +152,5 @@ hClose fromh s <- getProcessStatus True False pid case s of- Just (Exited (ExitSuccess)) -> return $ findkey reply+ Just (Exited ExitSuccess) -> return $ findkey reply _ -> error "checkpresent hook failed"
Remote/Rsync.hs view
@@ -15,6 +15,7 @@ import System.Directory import System.Posix.Files import System.Posix.Process+import Data.Maybe import Types import Types.Remote@@ -25,8 +26,8 @@ import Config import Content import Utility-import Remote.Special-import Remote.Encryptable+import Remote.Helper.Special+import Remote.Helper.Encryptable import Crypto import Messages import Utility.RsyncFile@@ -82,7 +83,7 @@ rsyncSetup :: UUID -> RemoteConfig -> Annex RemoteConfig rsyncSetup u c = do -- verify configuration is sane- let url = maybe (error "Specify rsyncurl=") id $+ let url = fromMaybe (error "Specify rsyncurl=") $ M.lookup "rsyncurl" c c' <- encryptionSetup c @@ -92,10 +93,13 @@ return c' rsyncKey :: RsyncOpts -> Key -> String-rsyncKey o k = rsyncUrl o </> hashDirMixed k </> f </> f+rsyncKey o k = rsyncUrl o </> hashDirMixed k </> shellEscape (f </> f) where f = keyFile k +rsyncKeyDir :: RsyncOpts -> Key -> String+rsyncKeyDir o k = rsyncUrl o </> hashDirMixed k </> shellEscape (keyFile k)+ store :: RsyncOpts -> Key -> Annex Bool store o k = do g <- Annex.gitRepo@@ -135,19 +139,18 @@ [ Params "--delete --recursive" , partialParams , Param $ addTrailingPathSeparator dummy- , Param $ parentDir $ rsyncKey o k+ , Param $ rsyncKeyDir o k ] checkPresent :: Git.Repo -> RsyncOpts -> Key -> Annex (Either IOException Bool) checkPresent r o k = do- showNote ("checking " ++ Git.repoDescribe r ++ "...")+ showAction $ "checking " ++ Git.repoDescribe r -- note: Does not currently differnetiate between rsync failing -- to connect, and the file not being present. res <- liftIO $ boolSystem "sh" [Param "-c", Param cmd] return $ Right res where- cmd = "rsync --quiet " ++ testfile ++ " 2>/dev/null"- testfile = shellEscape $ rsyncKey o k+ cmd = "rsync --quiet " ++ shellEscape (rsyncKey o k) ++ " 2>/dev/null" {- Rsync params to enable resumes of sending files safely, - ensure that files are only moved into place once complete@@ -160,10 +163,10 @@ withRsyncScratchDir :: (FilePath -> Annex Bool) -> Annex Bool withRsyncScratchDir a = do g <- Annex.gitRepo- pid <- liftIO $ getProcessID+ pid <- liftIO getProcessID let tmp = gitAnnexTmpDir g </> "rsynctmp" </> show pid nuke tmp- liftIO $ createDirectoryIfMissing True $ tmp+ liftIO $ createDirectoryIfMissing True tmp res <- a tmp nuke tmp return res@@ -173,7 +176,7 @@ rsyncRemote :: RsyncOpts -> [CommandParam] -> Annex Bool rsyncRemote o params = do- showProgress -- make way for progress bar+ showOutput -- make way for progress bar res <- liftIO $ rsync $ rsyncOptions o ++ defaultParams ++ params if res then return res@@ -189,15 +192,14 @@ rsyncSend :: RsyncOpts -> Key -> FilePath -> Annex Bool rsyncSend o k src = withRsyncScratchDir $ \tmp -> do let dest = tmp </> hashDirMixed k </> f </> f- liftIO $ createDirectoryIfMissing True $ parentDir $ dest+ liftIO $ createDirectoryIfMissing True $ parentDir dest liftIO $ createLink src dest- res <- rsyncRemote o+ rsyncRemote o [ Param "--recursive" , partialParams -- tmp/ to send contents of tmp dir , Param $ addTrailingPathSeparator tmp , Param $ rsyncUrl o ]- return res where f = keyFile k
Remote/S3real.hs view
@@ -33,8 +33,8 @@ import Messages import Locations import Config-import Remote.Special-import Remote.Encryptable+import Remote.Helper.Special+import Remote.Helper.Encryptable import Crypto import Content import Utility.Base64@@ -52,7 +52,7 @@ cst <- remoteCost r expensiveRemoteCost return $ gen' r u c cst gen' :: Git.Repo -> UUID -> Maybe RemoteConfig -> Int -> Remote Annex-gen' r u c cst = do+gen' r u c cst = encryptableRemote c (storeEncrypted this) (retrieveEncrypted this)@@ -85,7 +85,7 @@ handlehost Nothing = defaulthost handlehost (Just h)- | ".archive.org" `isSuffixOf` (map toLower h) = archiveorg+ | ".archive.org" `isSuffixOf` map toLower h = archiveorg | otherwise = defaulthost use fullconfig = do@@ -99,7 +99,7 @@ use fullconfig archiveorg = do- showNote $ "Internet Archive mode"+ showNote "Internet Archive mode" maybe (error "specify bucket=") (const $ return ()) $ M.lookup "bucket" archiveconfig use archiveconfig@@ -185,7 +185,7 @@ checkPresent :: Remote Annex -> Key -> Annex (Either IOException Bool) checkPresent r k = s3Action r noconn $ \(conn, bucket) -> do- showNote ("checking " ++ name r ++ "...")+ showAction $ "checking " ++ name r res <- liftIO $ getObjectInfo conn $ bucketKey r bucket k case res of Right _ -> return $ Right True@@ -203,10 +203,8 @@ s3Error e = error $ prettyReqError e s3Bool :: AWSResult () -> Annex Bool-s3Bool res = do- case res of- Right _ -> return True- Left e -> s3Warning e+s3Bool (Right _) = return True+s3Bool (Left e) = s3Warning e s3Action :: Remote Annex -> a -> ((AWSConnection, String) -> Annex a) -> Annex a s3Action r noconn action = do@@ -219,7 +217,7 @@ _ -> return noconn bucketFile :: Remote Annex -> Key -> FilePath-bucketFile r k = (munge $ show k)+bucketFile r = munge . show where munge s = case M.lookup "mungekeys" $ fromJust $ config r of Just "ia" -> iaMunge s@@ -243,13 +241,13 @@ genBucket :: RemoteConfig -> Annex () genBucket c = do conn <- s3ConnectionRequired c- showNote "checking bucket"+ showAction "checking bucket" loc <- liftIO $ getBucketLocation conn bucket case loc of Right _ -> return () Left err@(NetworkError _) -> s3Error err Left (AWSError _ _) -> do- showNote $ "creating bucket in " ++ datacenter+ showAction $ "creating bucket in " ++ datacenter res <- liftIO $ createBucketIn conn bucket datacenter case res of Right _ -> return ()@@ -271,8 +269,8 @@ warning $ "Set both " ++ s3AccessKey ++ " and " ++ s3SecretKey ++ " to use S3" return Nothing where- host = fromJust $ (M.lookup "host" c)- port = let s = fromJust $ (M.lookup "port" c) in+ host = fromJust $ M.lookup "host" c+ port = let s = fromJust $ M.lookup "port" c in case reads s of [(p, _)] -> p _ -> error $ "bad S3 port value: " ++ s@@ -283,7 +281,7 @@ s3GetCreds c = do ak <- getEnvKey s3AccessKey sk <- getEnvKey s3SecretKey- if (null ak || null sk)+ if null ak || null sk then do mcipher <- remoteCipher c case (M.lookup "s3creds" c, mcipher) of@@ -291,9 +289,7 @@ s <- liftIO $ withDecryptedContent cipher (return $ L.pack $ fromB64 encrypted) (return . L.unpack)- let line = lines s- let ak' = line !! 0- let sk' = line !! 1+ let [ak', sk', _rest] = lines s liftIO $ do setEnv s3AccessKey ak True setEnv s3SecretKey sk True
− Remote/Special.hs
@@ -1,44 +0,0 @@-{- common functions for special remotes- -- - Copyright 2011 Joey Hess <joey@kitenet.net>- -- - Licensed under the GNU GPL version 3 or higher.- -}--module Remote.Special where--import qualified Data.Map as M-import Data.Maybe-import Data.String.Utils-import Control.Monad.State (liftIO)--import Types-import Types.Remote-import qualified Git-import qualified Annex-import UUID-import Utility--{- Special remotes don't have a configured url, so Git.Repo does not- - automatically generate remotes for them. This looks for a different- - configuration key instead.- -}-findSpecialRemotes :: String -> Annex [Git.Repo]-findSpecialRemotes s = do- g <- Annex.gitRepo- return $ map construct $ remotepairs g- where- remotepairs r = M.toList $ M.filterWithKey match $ Git.configMap r- construct (k,_) = Git.repoRemoteNameSet Git.repoFromUnknown k- match k _ = startswith "remote." k && endswith (".annex-"++s) k--{- Sets up configuration for a special remote in .git/config. -}-gitConfigSpecialRemote :: UUID -> RemoteConfig -> String -> String -> Annex ()-gitConfigSpecialRemote u c k v = do- g <- Annex.gitRepo- liftIO $ do- Git.run g "config" [Param (configsetting $ "annex-"++k), Param v]- Git.run g "config" [Param (configsetting $ "annex-uuid"), Param u]- where- remotename = fromJust (M.lookup "name" c)- configsetting s = "remote." ++ remotename ++ "." ++ s
− Remote/Ssh.hs
@@ -1,61 +0,0 @@-{- git-annex remote access with ssh- -- - Copyright 2011 Joey Hess <joey@kitenet.net>- -- - Licensed under the GNU GPL version 3 or higher.- -}--module Remote.Ssh where--import Control.Monad.State (liftIO)--import qualified Git-import Utility-import Types-import Config--{- Generates parameters to ssh to a repository's host and run a command.- - Caller is responsible for doing any neccessary shellEscaping of the- - passed command. -}-sshToRepo :: Git.Repo -> [CommandParam] -> Annex [CommandParam]-sshToRepo repo sshcmd = do- s <- getConfig repo "ssh-options" ""- let sshoptions = map Param (words s)- let sshport = case Git.urlPort repo of- Nothing -> []- Just p -> [Param "-p", Param (show p)]- let sshhost = Param $ Git.urlHostUser repo- return $ sshoptions ++ sshport ++ [sshhost] ++ sshcmd--{- Generates parameters to run a git-annex-shell command on a remote- - repository. -}-git_annex_shell :: Git.Repo -> String -> [CommandParam] -> Annex (Maybe (FilePath, [CommandParam]))-git_annex_shell r command params- | not $ Git.repoIsUrl r = return $ Just (shellcmd, shellopts)- | Git.repoIsSsh r = do- sshparams <- sshToRepo r [Param sshcmd]- return $ Just ("ssh", sshparams)- | otherwise = return Nothing- where- dir = Git.workTree r- shellcmd = "git-annex-shell"- shellopts = (Param command):(File dir):params- sshcmd = shellcmd ++ " " ++ - unwords (map shellEscape $ toCommand shellopts)--{- Uses a supplied function (such as boolSystem) to run a git-annex-shell- - command on a remote.- -- - Or, if the remote does not support running remote commands, returns- - a specified error value. -}-onRemote - :: Git.Repo- -> (FilePath -> [CommandParam] -> IO a, a)- -> String- -> [CommandParam]- -> Annex a-onRemote r (with, errorval) command params = do- s <- git_annex_shell r command params- case s of- Just (c, ps) -> liftIO $ with c ps- Nothing -> return errorval
Remote/Web.hs view
@@ -7,28 +7,24 @@ module Remote.Web ( remote,- setUrl,- download+ setUrl ) where import Control.Monad.State (liftIO) import Control.Exception import System.FilePath-import Network.Browser-import Network.HTTP-import Network.URI import Types import Types.Remote import qualified Git import qualified Annex import Messages-import Utility import UUID import Config import PresenceLog import LocationLog import Locations+import qualified Remote.Helper.Url as Url type URLString = String @@ -52,7 +48,7 @@ gen :: Git.Repo -> UUID -> Maybe RemoteConfig -> Annex (Remote Annex) gen r _ _ = - return $ Remote {+ return Remote { uuid = webUUID, cost = expensiveRemoteCost, name = Git.repoDescribe r,@@ -67,10 +63,17 @@ {- The urls for a key are stored in remote/web/hash/key.log - in the git-annex branch. -} urlLog :: Key -> FilePath-urlLog key = "remote/web" </> hashDirLower key </> show key ++ ".log"+urlLog key = "remote/web" </> hashDirLower key </> keyFile key ++ ".log"+oldurlLog :: Key -> FilePath+{- A bug used to store the urls elsewhere. -}+oldurlLog key = "remote/web" </> hashDirLower key </> show key ++ ".log" getUrls :: Key -> Annex [URLString]-getUrls key = currentLog (urlLog key)+getUrls key = do+ us <- currentLog (urlLog key)+ if null us+ then currentLog (oldurlLog key)+ else return us {- Records a change in an url for a key. -} setUrl :: Key -> URLString -> LogStatus -> Annex ()@@ -83,9 +86,12 @@ logChange g key webUUID (if null us then InfoMissing else InfoPresent) downloadKey :: Key -> FilePath -> Annex Bool-downloadKey key file = do- us <- getUrls key- download us file+downloadKey key file = iter =<< getUrls key+ where+ iter [] = return False+ iter (url:urls) = do+ ok <- Url.download url file+ if ok then return ok else iter urls uploadKey :: Key -> Annex Bool uploadKey _ = do@@ -106,29 +112,6 @@ checkKey' :: [URLString] -> Annex Bool checkKey' [] = return False checkKey' (u:us) = do- showNote ("checking " ++ u)- e <- liftIO $ urlexists u+ showAction $ "checking " ++ u+ e <- liftIO $ Url.exists u if e then return e else checkKey' us--urlexists :: URLString -> IO Bool-urlexists url = do- case parseURI url of- Nothing -> return False- Just u -> do- (_, r) <- Network.Browser.browse $ do- setErrHandler ignore- setOutHandler ignore- setAllowRedirects True- request (mkRequest HEAD u :: Request_String)- case rspCode r of- (2,_,_) -> return True- _ -> return False- where- ignore = const $ return ()--download :: [URLString] -> FilePath -> Annex Bool-download [] _ = return False-download (url:us) file = do- showProgress -- make way for curl progress bar- ok <- liftIO $ boolSystem "curl" [Params "-L -C - -# -o", File file, File url]- if ok then return ok else download us file
RemoteLog.hs view
@@ -36,7 +36,7 @@ Branch.change remoteLog $ unlines $ sort $ map toline $ M.toList $ M.insert u c m where- toline (u', c') = u' ++ " " ++ (unwords $ configToKeyVal c')+ toline (u', c') = u' ++ " " ++ unwords (configToKeyVal c') {- Map of remotes by uuid containing key/value config maps. -} readRemoteLog :: Annex (M.Map UUID RemoteConfig)@@ -44,14 +44,14 @@ remoteLogParse :: String -> M.Map UUID RemoteConfig remoteLogParse s =- M.fromList $ catMaybes $ map parseline $ filter (not . null) $ lines s+ M.fromList $ mapMaybe parseline $ filter (not . null) $ lines s where parseline l | length w > 2 = Just (u, c) | otherwise = Nothing where w = words l- u = w !! 0+ u = head w c = keyValToConfig $ tail w {- Given Strings like "key=value", generates a RemoteConfig. -}@@ -90,8 +90,8 @@ r = drop (length num) s rest = drop 1 r ok = not (null num) && - not (null r) && r !! 0 == ';'+ not (null r) && head r == ';' {- for quickcheck -} prop_idempotent_configEscape :: String -> Bool-prop_idempotent_configEscape s = s == (configUnEscape $ configEscape s)+prop_idempotent_configEscape s = s == (configUnEscape . configEscape) s
TestConfig.hs view
@@ -45,7 +45,7 @@ runTests :: [TestCase] -> IO [Config] runTests [] = return []-runTests ((TestCase tname t):ts) = do+runTests (TestCase tname t : ts) = do testStart tname c <- t testEnd c@@ -62,7 +62,7 @@ handle r = do testEnd r error $ "** the " ++ c ++ " command is required"- c = (words cmdline) !! 0+ c = head $ words cmdline {- Checks if a command is available by running a command line. -} testCmd :: ConfigKey -> String -> Test@@ -74,7 +74,7 @@ - turn. The Config is set to the first one found. -} selectCmd :: ConfigKey -> [String] -> String -> Test selectCmd k = searchCmd- (\match -> return $ Config k $ StringConfig match)+ (return . Config k . StringConfig) (\cmds -> do testEnd $ Config k $ BoolConfig False error $ "* need one of these commands, but none are available: " ++ show cmds@@ -82,7 +82,7 @@ maybeSelectCmd :: ConfigKey -> [String] -> String -> Test maybeSelectCmd k = searchCmd- (\match -> return $ Config k $ MaybeStringConfig $ Just match)+ (return . Config k . MaybeStringConfig . Just) (\_ -> return $ Config k $ MaybeStringConfig Nothing) searchCmd :: (String -> Test) -> ([String] -> Test) -> [String] -> String -> Test@@ -91,7 +91,7 @@ search [] = failure cmds search (c:cs) = do ret <- system $ quiet c ++ " " ++ param- if (ret == ExitSuccess)+ if ret == ExitSuccess then success c else search cs @@ -104,8 +104,11 @@ hFlush stdout testEnd :: Config -> IO ()-testEnd (Config _ (BoolConfig True)) = putStrLn $ " yes"-testEnd (Config _ (BoolConfig False)) = putStrLn $ " no"-testEnd (Config _ (StringConfig s)) = putStrLn $ " " ++ s-testEnd (Config _ (MaybeStringConfig (Just s))) = putStrLn $ " " ++ s-testEnd (Config _ (MaybeStringConfig Nothing)) = putStrLn $ " not available"+testEnd (Config _ (BoolConfig True)) = status "yes"+testEnd (Config _ (BoolConfig False)) = status "no"+testEnd (Config _ (StringConfig s)) = status s+testEnd (Config _ (MaybeStringConfig (Just s))) = status s+testEnd (Config _ (MaybeStringConfig Nothing)) = status "not available"++status :: String -> IO ()+status s = putStrLn $ ' ':s
Touch.hsc view
@@ -15,6 +15,7 @@ import Foreign import Foreign.C+import Control.Monad (when) newtype TimeSpec = TimeSpec CTime @@ -66,9 +67,7 @@ withCString file $ \f -> do pokeArray ptr [atime, mtime] r <- c_utimensat at_fdcwd f ptr flags- if (r /= 0)- then throwErrno "touchBoth"- else return ()+ when (r /= 0) $ throwErrno "touchBoth" where flags = if follow then 0
Types/Key.hs view
@@ -48,7 +48,7 @@ "" +++ y = y x +++ "" = x x +++ y = x ++ fieldSep:y- c ?: (Just v) = c:(show v)+ c ?: (Just v) = c : show v _ ?: _ = "" readKey :: String -> Maybe Key@@ -73,4 +73,4 @@ addfield _ _ _ = Nothing prop_idempotent_key_read_show :: Key -> Bool-prop_idempotent_key_read_show k = Just k == (readKey $ show k)+prop_idempotent_key_read_show k = Just k == (readKey . show) k
Types/Remote.hs view
@@ -11,6 +11,7 @@ import Control.Exception import Data.Map as M+import Data.Ord import qualified Git import Types.Key@@ -62,4 +63,4 @@ -- order remotes by cost instance Ord (Remote a) where- compare x y = compare (cost x) (cost y)+ compare = comparing cost
UUID.hs view
@@ -49,7 +49,7 @@ genUUID = liftIO $ pOpen ReadFromPipe command params $ \h -> hGetLine h where command = SysConfig.uuid- params = if (command == "uuid")+ params = if command == "uuid" -- request a random uuid be generated then ["-m"] -- uuidgen generates random uuid by default@@ -82,7 +82,7 @@ prepUUID = do u <- getUUID =<< Annex.gitRepo when ("" == u) $ do- uuid <- liftIO $ genUUID+ uuid <- liftIO genUUID setConfig configkey uuid {- Records a description for a uuid in the uuidLog. -}
Upgrade/V0.hs view
@@ -23,7 +23,7 @@ upgrade :: Annex Bool upgrade = do- showNote "v0 to v1..."+ showAction "v0 to v1" g <- Annex.gitRepo -- do the reorganisation of the key files@@ -48,7 +48,7 @@ getKeysPresent0 :: FilePath -> Annex [Key] getKeysPresent0 dir = do exists <- liftIO $ doesDirectoryExist dir- if (not exists)+ if not exists then return [] else do contents <- liftIO $ getDirectoryContents dir
Upgrade/V1.hs view
@@ -22,7 +22,7 @@ import Content import Types import Locations-import LocationLog+import PresenceLog import qualified Annex import qualified AnnexQueue import qualified Git@@ -58,7 +58,7 @@ upgrade :: Annex Bool upgrade = do- showNote "v1 to v2"+ showAction "v1 to v2" g <- Annex.gitRepo if Git.repoIsLocalBare g@@ -77,7 +77,7 @@ moveContent :: Annex () moveContent = do- showNote "moving content..."+ showAction "moving content" files <- getKeyFilesPresent1 forM_ files move where@@ -91,10 +91,10 @@ updateSymlinks :: Annex () updateSymlinks = do- showNote "updating symlinks..."+ showAction "updating symlinks" g <- Annex.gitRepo files <- liftIO $ LsFiles.inRepo g [Git.workTree g]- forM_ files $ fixlink+ forM_ files fixlink where fixlink f = do r <- lookupFile1 f@@ -104,11 +104,11 @@ link <- calcGitLink f k liftIO $ removeFile f liftIO $ createSymbolicLink link f- AnnexQueue.add "add" [Param "--"] f+ AnnexQueue.add "add" [Param "--"] [f] moveLocationLogs :: Annex () moveLocationLogs = do- showNote "moving location logs..."+ showAction "moving location logs" logkeys <- oldlocationlogs forM_ logkeys move where@@ -119,11 +119,11 @@ if exists then do contents <- liftIO $ getDirectoryContents dir- return $ catMaybes $ map oldlog2key contents+ return $ mapMaybe oldlog2key contents else return [] move (l, k) = do g <- Annex.gitRepo- let dest = logFile k+ let dest = logFile2 g k let dir = Upgrade.V2.gitStateDir g let f = dir </> l liftIO $ createDirectoryIfMissing True (parentDir dest)@@ -131,12 +131,12 @@ -- log files that are not checked into git, -- as well as merging with already upgraded -- logs that have been pulled from elsewhere- old <- readLog f- new <- readLog dest- writeLog dest (old++new)- AnnexQueue.add "add" [Param "--"] dest- AnnexQueue.add "add" [Param "--"] f- AnnexQueue.add "rm" [Param "--quiet", Param "-f", Param "--"] f+ old <- liftIO $ readLog1 f+ new <- liftIO $ readLog1 dest+ liftIO $ writeLog1 dest (old++new)+ AnnexQueue.add "add" [Param "--"] [dest]+ AnnexQueue.add "add" [Param "--"] [f]+ AnnexQueue.add "rm" [Param "--quiet", Param "-f", Param "--"] [f] oldlog2key :: FilePath -> Maybe (FilePath, Key) oldlog2key l = @@ -186,9 +186,12 @@ fileKey1 file = readKey1 $ replace "&a" "&" $ replace "&s" "%" $ replace "%" "/" file -logFile1 :: Git.Repo -> Key -> String-logFile1 repo key = Upgrade.V2.gitStateDir repo ++ keyFile1 key ++ ".log"+writeLog1 :: FilePath -> [LogLine] -> IO ()+writeLog1 file ls = viaTmp writeFile file (unlines $ map show ls) +readLog1 :: FilePath -> IO [LogLine]+readLog1 file = catch (return . parseLog =<< readFileStrict file) (const $ return [])+ lookupFile1 :: FilePath -> Annex (Maybe (Key, Backend Annex)) lookupFile1 file = do tl <- liftIO $ try getsymlink@@ -196,17 +199,14 @@ Left _ -> return Nothing Right l -> makekey l where- getsymlink = do- l <- readSymbolicLink file- return $ takeFileName l- makekey l = do- case maybeLookupBackendName bname of- Nothing -> do- unless (null kname || null bname ||- not (isLinkToAnnex l)) $- warning skip- return Nothing- Just backend -> return $ Just (k, backend)+ getsymlink = return . takeFileName =<< readSymbolicLink file+ makekey l = case maybeLookupBackendName bname of+ Nothing -> do+ unless (null kname || null bname ||+ not (isLinkToAnnex l)) $+ warning skip+ return Nothing+ Just backend -> return $ Just (k, backend) where k = fileKey1 l bname = keyBackendName k@@ -221,7 +221,7 @@ getKeyFilesPresent1' :: FilePath -> Annex [FilePath] getKeyFilesPresent1' dir = do exists <- liftIO $ doesDirectoryExist dir- if (not exists)+ if not exists then return [] else do dirs <- liftIO $ getDirectoryContents dir@@ -233,3 +233,19 @@ case result of Right s -> return $ isRegularFile s Left _ -> return False++logFile1 :: Git.Repo -> Key -> String+logFile1 repo key = Upgrade.V2.gitStateDir repo ++ keyFile1 key ++ ".log"++logFile2 :: Git.Repo -> Key -> String+logFile2 = logFile' hashDirLower++logFile' :: (Key -> FilePath) -> Git.Repo -> Key -> String+logFile' hasher repo key =+ gitStateDir repo ++ hasher key ++ keyFile key ++ ".log"++stateDir :: FilePath+stateDir = addTrailingPathSeparator $ ".git-annex"++gitStateDir :: Git.Repo -> FilePath+gitStateDir repo = addTrailingPathSeparator $ Git.workTree repo </> stateDir
Upgrade/V2.hs view
@@ -10,7 +10,7 @@ import System.Directory import System.FilePath import Control.Monad.State (unless, when, liftIO)-import List+import Data.List import Data.Maybe import Types.Key@@ -45,23 +45,27 @@ -} upgrade :: Annex Bool upgrade = do- showNote "v2 to v3"+ showAction "v2 to v3" g <- Annex.gitRepo let bare = Git.repoIsLocalBare g Branch.create+ showProgress+ e <- liftIO $ doesDirectoryExist (olddir g) when e $ do mapM_ (\(k, f) -> inject f $ logFile k) =<< locationLogs g mapM_ (\f -> inject f f) =<< logFiles (olddir g) saveState+ showProgress when e $ liftIO $ do Git.run g "rm" [Param "-r", Param "-f", Param "-q", File (olddir g)] unless bare $ gitAttributesUnWrite g+ showProgress - unless bare $ push+ unless bare push return True @@ -70,11 +74,11 @@ levela <- dirContents dir levelb <- mapM tryDirContents levela files <- mapM tryDirContents (concat levelb)- return $ catMaybes $ map islogfile (concat files)+ return $ mapMaybe islogfile (concat files) where tryDirContents d = catch (dirContents d) (return . const []) dir = gitStateDir repo- islogfile f = maybe Nothing (\k -> Just $ (k, f)) $+ islogfile f = maybe Nothing (\k -> Just (k, f)) $ logFileKey $ takeFileName f inject :: FilePath -> FilePath -> Annex ()@@ -83,6 +87,7 @@ new <- liftIO (readFile $ olddir g </> source) prev <- Branch.get dest Branch.change dest $ unlines $ nub $ lines prev ++ lines new+ showProgress logFiles :: FilePath -> Annex [FilePath] logFiles dir = return . filter (".log" `isSuffixOf`)@@ -105,8 +110,8 @@ -- "git push" will from then on -- automatically push it Branch.update -- just in case- showNote "pushing new git-annex branch to origin"- showProgress+ showAction "pushing new git-annex branch to origin"+ showOutput g <- Annex.gitRepo liftIO $ Git.run g "push" [Param "origin", Param Branch.name] _ -> do@@ -116,7 +121,7 @@ showLongNote $ "git-annex branch created\n" ++ "Be sure to push this branch when pushing to remotes.\n"- showProgress+ showOutput {- Old .gitattributes contents, not needed anymore. -} attrLines :: [String]@@ -131,10 +136,10 @@ whenM (doesFileExist attributes) $ do c <- readFileStrict attributes liftIO $ viaTmp writeFile attributes $ unlines $- filter (\l -> not $ l `elem` attrLines) $ lines c+ filter (`notElem` attrLines) $ lines c Git.run repo "add" [File attributes] stateDir :: FilePath-stateDir = addTrailingPathSeparator $ ".git-annex"+stateDir = addTrailingPathSeparator ".git-annex" gitStateDir :: Git.Repo -> FilePath gitStateDir repo = addTrailingPathSeparator $ Git.workTree repo </> stateDir
Utility.hs view
@@ -23,6 +23,7 @@ unsetFileMode, readMaybe, viaTmp,+ withTempFile, dirContains, dirContents, myHomeDir,@@ -38,6 +39,7 @@ prop_relPathDirToFile_basics ) where +import IO (bracket) import System.IO import System.Exit import qualified System.Posix.Process@@ -141,9 +143,9 @@ {- For quickcheck. -} prop_idempotent_shellEscape :: String -> Bool-prop_idempotent_shellEscape s = [s] == (shellUnEscape $ shellEscape s)+prop_idempotent_shellEscape s = [s] == (shellUnEscape . shellEscape) s prop_idempotent_shellEscape_multiword :: [String] -> Bool-prop_idempotent_shellEscape_multiword s = s == (shellUnEscape $ unwords $ map shellEscape s)+prop_idempotent_shellEscape_multiword s = s == (shellUnEscape . unwords . map shellEscape) s {- A version of hgetContents that is not lazy. Ensures file is - all read before it gets closed. -}@@ -253,6 +255,18 @@ a tmpfile content renameFile tmpfile file +{- Runs an action with a temp file, then removes the file. -}+withTempFile :: String -> (FilePath -> Handle -> IO a) -> IO a+withTempFile template action = bracket create remove use+ where+ create = do+ tmpdir <- catch getTemporaryDirectory (const $ return ".")+ openTempFile tmpdir template+ remove (name, handle) = do+ hClose handle+ catchBool (removeFile name >> return True)+ use (name, handle) = action name handle+ {- Lists the contents of a directory. - Unlike getDirectoryContents, paths are not relative to the directory. -} dirContents :: FilePath -> IO [FilePath]@@ -288,6 +302,6 @@ (>>!) :: Monad m => m Bool -> m () -> m () (>>!) = unlessM --- low fixity allows eg, foo bar <|> error $ "failed " ++ meep+-- low fixity allows eg, foo bar >>! error $ "failed " ++ meep infixr 0 >>? infixr 0 >>!
Utility/CopyFile.hs view
@@ -20,10 +20,8 @@ removeFile dest boolSystem "cp" [params, File src, File dest] where- params = if SysConfig.cp_reflink_auto- then Params "--reflink=auto"- else if SysConfig.cp_a- then Params "-a"- else if SysConfig.cp_p- then Params "-p"- else Params ""+ params+ | SysConfig.cp_reflink_auto = Params "--reflink=auto"+ | SysConfig.cp_a = Params "-a"+ | SysConfig.cp_p = Params "-p"+ | otherwise = Params ""
Utility/DataUnits.hs view
@@ -106,7 +106,7 @@ {- approximate display of a particular number of bytes -} roughSize :: [Unit] -> Bool -> ByteSize -> String roughSize units abbrev i- | i < 0 = "-" ++ findUnit units' (negate i)+ | i < 0 = '-' : findUnit units' (negate i) | otherwise = findUnit units' i where units' = reverse $ sort units -- largest first@@ -139,10 +139,10 @@ readSize units input | null parsednum = Nothing | null parsedunit = Nothing- | otherwise = Just $ round $ number * (fromIntegral multiplier)+ | otherwise = Just $ round $ number * fromIntegral multiplier where (number, rest) = head parsednum- multiplier = head $ parsedunit+ multiplier = head parsedunit unitname = takeWhile isAlpha $ dropWhile isSpace rest parsednum = reads input :: [(Double, String)]
Utility/Dot.hs view
@@ -20,13 +20,13 @@ {- an edge between two nodes -} graphEdge :: String -> String -> Maybe String -> String-graphEdge fromid toid desc = indent $ maybe edge (\d -> label d edge) desc+graphEdge fromid toid desc = indent $ maybe edge (`label` edge) desc where edge = quote fromid ++ " -> " ++ quote toid {- adds a label to a node or edge -} label :: String -> String -> String-label l s = attr "label" l s+label = attr "label" {- adds an attribute to a node or edge - (can be called multiple times for multiple attributes) -}@@ -35,7 +35,7 @@ {- fills a node with a color -} fillColor :: String -> String -> String-fillColor color s = attr "fillcolor" color $ attr "style" "filled" $ s+fillColor color s = attr "fillcolor" color $ attr "style" "filled" s {- apply to graphNode to put the node in a labeled box -} subGraph :: String -> String -> String -> String -> String@@ -52,10 +52,10 @@ setlabel = "label=" ++ quote l setfilled = "style=" ++ quote "filled" setcolor = "fillcolor=" ++ quote color- ii x = (indent $ indent x) ++ "\n"+ ii x = indent (indent x) ++ "\n" indent ::String -> String-indent s = "\t" ++ s+indent s = '\t' : s quote :: String -> String quote s = "\"" ++ s' ++ "\""
Utility/RsyncFile.hs view
@@ -19,7 +19,7 @@ {- rsync requires some weird, non-shell like quoting in - here. A doubled single quote inside the single quoted - string is a single quote. -}- escape s = "'" ++ (join "''" $ split "'" s) ++ "'"+ escape s = "'" ++ join "''" (split "'" s) ++ "'" {- Runs rsync in server mode to send a file, and exits. -} rsyncServerSend :: FilePath -> IO ()
Version.hs view
@@ -7,8 +7,6 @@ module Version where -import Control.Monad (unless)- import Types import qualified Annex import qualified Git@@ -39,15 +37,11 @@ setVersion :: Annex () setVersion = setConfig versionField defaultVersion -checkVersion :: Annex ()-checkVersion = getVersion >>= handle+checkVersion :: Version -> Annex ()+checkVersion v+ | v `elem` supportedVersions = return ()+ | v `elem` upgradableVersions = err "Upgrade this repository: git-annex upgrade"+ | otherwise = err "Upgrade git-annex." where- handle Nothing = error "First run: git-annex init"- handle (Just v) = do- unless (v `elem` supportedVersions) $ do- error $ "Repository version " ++ v ++ - " is not supported. " ++- msg v- msg v- | v `elem` upgradableVersions = "Upgrade this repository: git-annex upgrade"- | otherwise = "Upgrade git-annex."+ err msg = error $ "Repository version " ++ v +++ " is not supported. " ++ msg
configure.hs view
@@ -7,7 +7,7 @@ tests :: [TestCase] tests =- [ TestCase "version" $ getVersion+ [ TestCase "version" getVersion , testCp "cp_a" "-a" , testCp "cp_p" "-p" , testCp "cp_reflink_auto" "--reflink=auto"@@ -77,8 +77,7 @@ writeFile testFile "test file contents" cleanup :: IO ()-cleanup = do- removeDirectoryRecursive tmpDir+cleanup = removeDirectoryRecursive tmpDir main :: IO () main = do
debian/changelog view
@@ -1,3 +1,34 @@+git-annex (3.20110819) unstable; urgency=low++ * Now "git annex init" only has to be run once, when a git repository+ is first being created. Clones will automatically notice that git-annex+ is in use and automatically perform a basic initalization. It's+ still recommended to run "git annex init" in any clones, to describe them.+ * Added annex-cost-command configuration, which can be used to vary the+ cost of a remote based on the output of a shell command.+ * Fix broken upgrade from V1 repository. Closes: #638584++ -- Joey Hess <joeyh@debian.org> Fri, 19 Aug 2011 20:34:09 -0400++git-annex (3.20110817) unstable; urgency=low++ * Fix shell escaping in rsync special remote.+ * addurl: --fast can be used to avoid immediately downloading the url.+ * Added support for getting content from git remotes using http (and https).+ * Added curl to Debian package dependencies.++ -- Joey Hess <joeyh@debian.org> Wed, 17 Aug 2011 01:29:02 -0400++git-annex (3.20110719) unstable; urgency=low++ * add: Be even more robust to avoid ever leaving the file seemingly deleted.+ Closes: #634233+ * Bugfix: Make add ../ work.+ * Support the standard git -c name=value+ * unannex: Clean up use of git commit -a.++ -- Joey Hess <joeyh@debian.org> Tue, 19 Jul 2011 23:39:53 -0400+ git-annex (3.20110707) unstable; urgency=low * Fix sign bug in disk free space checking.
debian/control view
@@ -13,6 +13,7 @@ libghc-utf8-string-dev, libghc-hs3-dev (>= 0.5.6), libghc-testpack-dev [any-i386 any-amd64],+ libghc-monad-control-dev, ikiwiki, perlmagick, git | git-core,@@ -30,6 +31,7 @@ git | git-core, uuid, rsync,+ curl, openssh-client Suggests: graphviz, bup, gnupg Description: manage files with git, without checking their contents into git
+ doc/bugs/--git-dir_and_--work-tree_options.mdwn view
@@ -0,0 +1,29 @@+git-annex does not take into account the --git-dir and --work-tree command line options (while they can be useful when scripting).++ > mkdir /tmp/test+ > cd /tmp/test+ > git init+ Initialized empty Git repository in /tmp/test/.git/+ > git annex init test+ init test ok+ > touch foo+ > cd+ > git --git-dir=/tmp/test/.git --work-tree=/tmp/test annex add foo+ git-annex: Not in a git repository.++regular git add works:++ > git --git-dir=/tmp/test/.git --work-tree=/tmp/test add foo+ > git --git-dir=/tmp/test/.git --work-tree=/tmp/test status + # On branch master+ #+ # Initial commit+ #+ # Changes to be committed:+ # (use "git rm --cached <file>..." to unstage)+ #+ # new file: foo+ #++git-annex version: 3.20110702+
+ doc/bugs/Cabal_dependency_monadIO_missing.mdwn view
@@ -0,0 +1,14 @@+Just issuing the command `cabal install` results in the following error message.++ Command/Add.hs:54:3:+ No instance for (Control.Monad.IO.Control.MonadControlIO+ (Control.Monad.State.Lazy.StateT Annex.AnnexState IO))+ arising from a use of `handle' at Command/Add.hs:54:3-24++Adding the dependency for `monadIO` to `git-annex.cabal` should fix this? +-- Thomas++> No, it's already satisfied by `monad-control` being listed as a+> dependency in the cabal file. Your system might be old/new/or broken,+> perhaps it's time to provide some details about the version of haskell+> and of `monad-control` you have installed? --[[Joey]]
+ doc/bugs/Cabal_dependency_monadIO_missing/comment_1_14be660aa57fadec0d81b32a8b52c66f._comment view
@@ -0,0 +1,75 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmFgsNxmnGznb5bbmcoWhoQOoxZZ-io61s"+ nickname="Thomas"+ subject="comment 1"+ date="2011-08-08T09:04:20Z"+ content="""+I use Debian Squeeze, I have the Debian package cabal-install 0.8.0-1 installed.++ $ git clone git://git-annex.branchable.com/+ $ cd git-annex.branchable.com+ $ cabal update+ $ cabal install cabal-install++This installed: Cabal-1.10.2.0, zlib-0.5.3.1, cabal-install 0.10.2.+No version of monad-control or monadIO installed.++ $ ~/.cabal/bin/cabal install+ Registering QuickCheck-2.4.1.1...+ Registering Crypto-4.2.3...+ Registering base-unicode-symbols-0.2.2.1...+ Registering deepseq-1.1.0.2...+ Registering hxt-charproperties-9.1.0...+ Registering hxt-regex-xmlschema-9.0.0...+ Registering hxt-unicode-9.0.1...+ Registering hxt-9.1.2...+ Registering stm-2.2.0.1...+ Registering hS3-0.5.6...+ Registering transformers-0.2.2.0...+ Registering monad-control-0.2.0.1...+ [1 of 1] Compiling Main ( Setup.hs, dist/setup/Main.o )+ Linking ./dist/setup/setup ...+ ghc -O2 -Wall -ignore-package monads-fd -fspec-constr-count=5 --make configure+ [1 of 2] Compiling TestConfig ( TestConfig.hs, TestConfig.o )+ [2 of 2] Compiling Main ( configure.hs, configure.o )+ Linking configure ...+ ./configure+ checking version... 3.20110720+ checking cp -a... yes+ checking cp -p... yes+ checking cp --reflink=auto... yes+ checking uuid generator... uuid+ checking xargs -0... yes+ checking rsync... yes+ checking curl... yes+ checking bup... yes+ checking gpg... yes+ checking sha1... sha1sum+ checking sha256... sha256sum+ checking sha512... sha512sum+ checking sha224... sha224sum+ checking sha384... sha384sum++ ...++ Command/Add.hs:54:3:+ No instance for (Control.Monad.IO.Control.MonadControlIO+ (Control.Monad.State.Lazy.StateT Annex.AnnexState IO))+ arising from a use of `handle' at Command/Add.hs:54:3-24+ Possible fix:+ add an instance declaration for+ (Control.Monad.IO.Control.MonadControlIO+ (Control.Monad.State.Lazy.StateT Annex.AnnexState IO))+ In the first argument of `($)', namely `handle (undo file key)'+ In a stmt of a 'do' expression:+ handle (undo file key) $ moveAnnex key file+ In the expression:+ do { handle (undo file key) $ moveAnnex key file;+ next $ cleanup file key }+ cabal: Error: some packages failed to install:+ git-annex-3.20110719 failed during the building phase. The exception was:+ ExitFailure 1++After I added a depencency for monadIO to the git-annex.cabal file, it installed correctly. +-- Thomas+"""]]
+ doc/bugs/Cabal_dependency_monadIO_missing/comment_2_4f4d8e1e00a2a4f7e8a8ab082e16adac._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 2"+ date="2011-08-17T04:56:30Z"+ content="""+Finally got a chance to try to reproduce this. I followed your recipe exactly in a clean squeeze chroot. monadIO was not installed, but git-annex built ok, using monad-control.+"""]]
+ doc/bugs/Prevent_accidental_merges.mdwn view
@@ -0,0 +1,14 @@+With the storage layout v3, pulling the git-annex branch into the master branch is... less than ideal.++The fact that the two branches contain totally different data make an accidental merge worse, arguably.++Adding a tiny binary file called .gitnomerge to both branches would solve that without any noticeable overhead.++Yes, there is an argument to be made that this is too much hand-holding, but I still think it's worth it.++-- Richard++> It should be as easy to undo such an accidential merge+> as it is to undo any other git commit, right? I quite like that git-annex +> no longer adds any clutter to the master branch, and would be reluctant+> to change that. --[[Joey]]
doc/bugs/WORM:_Handle_long_filenames_correctly.mdwn view
@@ -1,1 +1,4 @@ I have files with very long filenames on an xfs at home. On my laptop the annex should have been checked out on an encfs, but there filenames can't be as long as on the xfs. So perhaps it would be good to limit the keysize to a sane substring of the filename e.g. use only the first 120 characters.++> Since there seems no strong argument for a WORM100, and better options+> exist, closing. [[done]] --[[Joey]]
+ doc/bugs/__39__annex_add__39___fails_to___39__git_add__39___for_parent_relative_path.mdwn view
@@ -0,0 +1,15 @@+The following commands show the failure:++$ mkdir d && touch d/f++$ mkdir g && cd g && git annex add ../d/f ++add ... ok++error: Invalid path '.git/annex/objects/Jx/...++...++Then it seems it is enough to 'git add ../d/f' to complete the operation.++> Thanks for reporting, [[fixed|done]] --[[Joey]]
doc/bugs/git_annex_fsck_is_a_no-op_in_bare_repos.mdwn view
@@ -13,3 +13,7 @@ >> Even if there is nothing it can _do_, knowing that the data is intact, >> or not, is valuable in and as of itself. -- RichiH++>>> While storing the data is no longer an issue in bare repos, fsck would+>>> need a special mode that examines all the location logs, since it+>>> cannot run thru the checked out files. --[[Joey]]
+ doc/bugs/git_command_line_constructed_by_unannex_command_has_tons_of_redundant_-a_paramters.mdwn view
@@ -0,0 +1,15 @@+This doesn't look right:++ simons 11148 0.0 0.0 15572 1268 pts/1 SN+ 04:00 0:00 | \_ git annex unannex stuff+ simons 11150 0.5 0.0 130504 11212 pts/1 SN+ 04:00 3:40 | | \_ git-annex unannex stuff+ simons 11152 0.0 0.1 39536 23932 pts/1 SN+ 04:00 0:00 | | \_ git --git-dir=/home/simons/annex/.git --work-tree=/home/simons/annex ls-files --cached -z -- stuff+ simons 11288 0.0 0.0 0 0 pts/1 ZN+ 04:01 0:00 | | \_ [git] <defunct>+ simons 11339 0.0 0.0 0 0 pts/1 ZN+ 04:02 0:00 | | \_ [git-annex] <defunct>+ simons 11442 0.0 0.0 0 0 pts/1 ZN+ 04:06 0:00 | | \_ [git] <defunct>+ simons 11443 0.0 0.0 0 0 pts/1 ZN+ 04:06 0:05 | | \_ [git] <defunct>+ simons 16541 0.0 0.0 0 0 pts/1 ZN+ 04:14 0:00 | | \_ [git] <defunct>+ simons 16543 0.3 0.0 15644 1744 pts/1 SN+ 04:14 2:13 | | \_ git --git-dir=/home/simons/annex/.git --work-tree=/home/simons/annex cat-file --batch+ simons 14224 0.0 0.0 100744 796 pts/1 SN+ 14:10 0:00 | | \_ xargs -0 git --git-dir=/home/simons/annex/.git --work-tree=/home/simons/annex commit -a -m content removed from git annex+ simons 14225 0.4 0.1 32684 18652 pts/1 DN+ 14:10 0:00 | | \_ git --git-dir=/home/simons/annex/.git --work-tree=/home/simons/annex commit -a -m content removed from git annex -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a -a++> [[Fixed|done]] --[[Joey]]
doc/bugs/making_annex-merge_try_a_fast-forward.mdwn view
@@ -1,3 +1,29 @@ While merging the git-annex branch, annex-merge does not end up in a fast-forward even when it would be possible. But as sometimes annex-merge takes time, it would probably be worth it (but maybe I miss something with my workflow...).++> I don't think a fast-forward will make things much faster.+> +> git-annex needs its index file to be updated to reflect the merge.+> With the union merge it does now, this can be accomplished by using+> `git-diff-index` to efficiently get a list of files that have changed,+> and only merge those changes into the index with `git-update-index`.+> Then the index gets committed, generating the merge.+> +> To fast-forward, it would just reset the git-annex branch to the new+> head of the remote it's merging to. But then the index needs to be+> updated to reflect this new head too. To do that needs the same method+> described above, essentially (with the difference that it can replace+> files in the index with the version from the git-annex branch, rather+> than merging in the changes... but only if the index is known to be+> already committed and have no other changes, which would require both+> an attempt to commit it first, and+> locking). +> +> So will take basically the same amount of time, except+> it would not need to commit the index at the end of the merge. The+> most expensive work is the `git-diff-index` and `git-update-index`,+> which are not avoided.+> +> Although, perhaps fast-forward merge would use slightly+> less space. --[[Joey]]
+ doc/bugs/support_bare_git_repo__44___with_the_annex_directory_exposed_to_http.mdwn view
@@ -0,0 +1,20 @@+Let's say that http://people.collabora.com/~alsuren/git/fate-suite.git/ is a bare git repo. It has been 'git update-server-info'd so that it can be served on a dumb http server.++The repo is also a git annex remote, created using the following commands:++* git remote add alsuren git+ssh://people.collabora.co.uk/user/alsuren/public_html/fate-suite.git+* git push alsuren --all+* git annex copy --to=alsuren++so http://people.collabora.com/~alsuren/git/fate-suite.git/annex is a valid git annex (though listing dirs is forbidden, so you need to know the filenames ahead of time).++I would like to be able to use the following commands to get a clone of the repo:++* git clone http://people.collabora.com/~alsuren/git/fate-suite.git/+* cd fate-suite+* git annex get++This would allow contributors to quickly get a copy of our upstream repo and start contributing with minimal bandwidth/effort.++> This is now supported.. I look forward to seeing your project using it!+> --[[Joey]] [[!tag done]]
+ doc/bugs/unannex_command_doesn__39__t_all_files.mdwn view
@@ -0,0 +1,26 @@+ $ git init ; git annex init test ; dd if=/dev/urandom of=file1 count=128 ; cp file1 file2 ; git annex add --backend=SHA1 file? ; git commit -m init ; git annex unannex ; ls -l+ Initialized empty Git repository in /tmp/annex/.git/+ init test ok+ 128+0 records in+ 128+0 records out+ 65536 bytes (66 kB) copied, 0.007173 s, 9.1 MB/s+ add file1 (checksum...) ok+ add file2 (checksum...) ok+ (Recording state in git...)+ [master (root-commit) 2177b10] init+ 2 files changed, 2 insertions(+), 0 deletions(-)+ create mode 120000 file1+ create mode 120000 file2+ unannex file1 ok+ (Recording state in git...)+ [master bef78b1] content removed from git annex+ 1 files changed, 0 insertions(+), 1 deletions(-)+ delete mode 120000 file1+ total 72+ -rw-r--r-- 1 simons users 65536 Jul 15 17:29 file1+ lrwxrwxrwx 1 simons users 132 Jul 15 17:29 file2 -> .git/annex/objects/jp/Fk/SHA1-s65536--795b58cc4e5190b02e7026fd9e94a10c98c6475f/SHA1-s65536--795b58cc4e5190b02e7026fd9e94a10c98c6475f++> This was recently discussed in+> [[annex_unannex__47__uninit_should_handle_copies]] and `unannex --fast`+> added to leave contents behind in the annex, which allows handling+> copies. But needs manual cleanup later with dropunused. --[[Joey]]
+ doc/bugs/wishlist:_more_descriptive_commit_messages_in_git-annex_branch.mdwn view
@@ -0,0 +1,36 @@+as of git-annex version 3.20110719, all git-annex commits only contain the word "update" as a commit message. given that the contents of the commit are pretty non-descriptive (SHA1 hashes for file names, uuids for repository names), i suggest to have more descriptive commit messages, as shown here:++ /mnt/usb_disk/photos/2011$ git annex get+ /mnt/usb_disk/photos/2011$ git show git-annex+ [...]+ usb-disk-photos: get 2011+ + * 10 files retrieved from 2 sources (9 from local-harddisk, 1 from my-server)+ * 120 files were already present+ * 2 files could not be retrieved+ /mnt/usb_disk/photos/2011$ cd ~/photos/2011/07+ ~/photos/2011/07$ git copy --to my-server+ ~/photos/2011/07$ git show git-annex+ [...]+ local-harddisk: copy 2011/07 to my-server+ + * 20 files pushed+ ~/photos/2011/07$++in my opinion, the messages should at least contain++* what command was used+* in which repository they were executed+* which files or directories they affected (not necessarily all files, but what was given on command line or implicitly from the working directory)++--[[chrysn]]++> The implementation of the git-annex branch precludes more descriptive+> commit messages, since a single commit can include changes that were+> previously staged to the branch's index file, or spooled to its journal+> by other git-annex commands (either concurrently running or+> interrupted commands, or even changes needed to automatically merge+> other git-annex branches).+> +> It would be possible to make it *less* verbose, with an empty commit+> message. :) --[[Joey]]
doc/cheatsheet.mdwn view
@@ -1,4 +1,4 @@-A suppliment to the [[walkthrough]].+A supplement to the [[walkthrough]]. [[!toc]]
+ doc/forum/Can_I_store_normal_files_in_the_git-annex_git_repository__63__.mdwn view
@@ -0,0 +1,6 @@+Is it possible to story ordinary files in the git repository, or is this going to confuse git-annex? In other words, can I safely run++ git add .gitattributes+ git commit -m 'remember attributes' .gitattributes++..., or do I have to use `git-annex add` all time?
+ doc/forum/example_of_massively_disconnected_operation.mdwn view
@@ -0,0 +1,33 @@+I found this archival drive that had been offline since October 26th 2010. Since I released git-annex 0.02 on October 27th, this must have been made using the very first release of git-annex, ever.++So, I synced it back up! :) --[[Joey]]++<pre>+commit 4151f4595fe6205d4aed653617ab23eb3335130a+Author: Joey Hess <joey@kitenet.net>+Date: Tue Oct 26 02:18:03 2010 -0400++joey> git pull+remote: Counting objects: 428782, done.+remote: Compressing objects: 100% (280714/280714), done.+remote: Total 416692 (delta 150923), reused 389593 (delta 125143)+Receiving objects: 100% (416692/416692), 44.71 MiB | 495 KiB/s, done.+Resolving deltas: 100% (150923/150923), completed with 818 local objects.+ * [new branch] git-annex -> origin/git-annex+ 1893f9c..9ebcc0e master -> origin/master+Updating 1893f9c..9ebcc0e+Checking out files: 100% (76884/76884), done.+joey> git annex version+git-annex version: 3.20110611+local repository version: unknown+default repository version: 3+supported repository versions: 3+upgrade supported from repository versions: 0 1 2+joey> git config annex.version 0+joey> git annex upgrade+upgrade . (v0 to v1...) (v1 to v2) (moving content...) (updating symlinks...) (moving location logs...) (v2 to v3) (merging origin/git-annex into git-annex...)++ git-annex branch created+ Be sure to push this branch when pushing to remotes.+ok+</pre>
+ doc/forum/version_3_upgrade.mdwn view
@@ -0,0 +1,9 @@+after upgrading to git-annex 3, i'm stuck with diverging git-annex branches -- i didn't manage to follow this line in the directions:++> After this upgrade, you should make sure you include the git-annex branch when git pushing and pulling.++could you explain how to do that in a littel more detail? git pull seems to only merge master, although i have these ``.git/config`` settings:++ [branch "git-annex"]+ remote = origin+ merge = git-annex
+ doc/forum/version_3_upgrade/comment_1_05fc9c9cad26c520bebb98c852c71e35._comment view
@@ -0,0 +1,13 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 1"+ date="2011-08-17T01:33:08Z"+ content="""+It's ok that `git pull` does not merge the git-annex branch. You can merge it with `git annex merge`, or it will be done+automatically when you use other git-annex commands.++If you use `git pull` and `git push` without any options, the defaults will make git pull and push the git-annex branch automatically.++But if you're in the habit of doing `git push origin master`, that won't cause the git-annex branch to be pushed (use `git push origin git-annex` to manually push it then). Similarly, `git pull origin master` won't pull it. And also, the `remote.origin.fetch` setting in `.git/config` can be modified in ways that make `git pull` not automatically pull the git-annex branch. So those are the things to avoid after upgrade to v3, basically.+"""]]
doc/git-annex.mdwn view
@@ -121,9 +121,15 @@ * init description - Initializes git-annex with a description of the git repository,- and sets up `.gitattributes` and the pre-commit hook.+ Initializes git-annex with a description of the git repository. + Until a repository (or one of its remotes) has been initialized,+ git-annex will refuse to operate on it, to avoid accidentially+ using it in a repository that was not intended to have an annex.++ It's useful, but not mandatory, to initialize each new clone+ of a repository with its own description.+ * describe repository description Changes the description of a repository.@@ -282,6 +288,8 @@ Downloads each url to a file, which is added to the annex. + To avoid immediately downloading the url, specify --fast+ * fromkey file This plumbing-level command can be used to manually set up a file@@ -387,6 +395,10 @@ Specifies a key to operate on. +* -c name=value++ Used to override git configuration settings. May be specified multiple times.+ # CONFIGURATION Like other git commands, git-annex is configured via `.git/config`.@@ -411,6 +423,12 @@ transfer annexed files from or to, ones with lower costs are preferred. The default cost is 100 for local repositories, and 200 for remote repositories.++* `remote.<name>.annex-cost-command`++ If set, the command is run, and the number it outputs is used as the cost.+ This allows varying the cost based on eg, the current network. The+ cost-command can be any shell command line. * `remote.<name>.annex-ignore`
doc/index.mdwn view
@@ -12,7 +12,7 @@ * [[forum]] * [[comments]] * [[contact]]-* <a href="http://flattr.com/thing/84843/git-annex"><img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" /></a>+* <a href="http://flattr.com/thing/84843/git-annex"><img src="https://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" /></a> [[News]]:
doc/install.mdwn view
@@ -23,6 +23,7 @@ * [utf8-string](http://hackage.haskell.org/package/utf8-string) * [SHA](http://hackage.haskell.org/package/SHA) * [dataenc](http://hackage.haskell.org/package/dataenc)+ * [monad-control](http://hackage.haskell.org/package/monad-control) * [TestPack](http://hackage.haskell.org/cgi-bin/hackage-scripts/package/testpack) * [QuickCheck 2](http://hackage.haskell.org/package/QuickCheck) * [HTTP](http://hackage.haskell.org/package/HTTP)
+ doc/install/Debian/comment_1_029486088d098c2d4f1099f2f0e701a9._comment view
@@ -0,0 +1,9 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawla7u6eLKNYZ09Z7xwBffqLaXquMQC07fU"+ nickname="Matthias"+ subject="squeeze-backports update?"+ date="2011-08-17T12:34:46Z"+ content="""+Is there going to be an update of git-annex in debian squeeze-backports to a version that supports repository version 3?+Thx+"""]]
+ doc/install/Debian/comment_2_648e3467e260cdf233acdb0b53313ce0._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="Re: squeeze-backports update?"+ date="2011-08-17T15:34:29Z"+ content="""+Yes, I uploaded it last night.+"""]]
doc/install/Fedora.mdwn view
@@ -9,6 +9,7 @@ sudo cabal install quickcheck sudo cabal install SHA sudo cabal install dataenc+sudo cabal install monad-control sudo cabal install HTTP sudo cabal install hS3
doc/install/OSX.mdwn view
@@ -1,5 +1,9 @@+Install Haskel Platform from [[http://hackage.haskell.org/platform/mac.html]]. The version provided by Macports is too old to work with current versions of git-annex. Then execute+ <pre>-sudo port install haskell-platform git-core ossp-uuid md5sha1sum coreutils pcre+sudo port install git-core ossp-uuid md5sha1sum coreutils pcre++sudo ln -s /opt/local/include/pcre.h /usr/include/pcre.h # This is hack that allows pcre-light to find pcre sudo cabal update sudo cabal install missingh sudo cabal install utf8-string@@ -7,6 +11,7 @@ sudo cabal install quickcheck sudo cabal install SHA sudo cabal install dataenc+sudo cabal install monad-control sudo cabal install HTTP sudo cabal install hS3 # optional @@ -20,7 +25,7 @@ sudo make install </pre> -Originally posted by Jon at <https://gist.github.com/671785> --[[Joey]]+Originally posted by Jon at <https://gist.github.com/671785> --[[Joey]], modified by [[kristianrumberg]] See also:
doc/internals.mdwn view
@@ -22,7 +22,7 @@ This branch is managed by git-annex, with the contents listed below. The file `.git/annex/index` is a separate git index file it uses-to accumlate changes for the git-annex. Also, `.git/annex/journal/` is used+to accumulate changes for the git-annex. Also, `.git/annex/journal/` is used to record changes before they are added to git. Note that for speed reasons, git-annex assumes only it will modify this
− doc/news/version_0.20110610.mdwn
@@ -1,6 +0,0 @@-git-annex 0.20110610 released with [[!toggle text="these changes"]]-[[!toggleable text="""- * Add --numcopies option.- * Add --trust, --untrust, and --semitrust options.- * get --from is the same as copy --from- * Bugfix: Fix fsck to not think all SHAnE keys are bad."""]]
− doc/news/version_3.20110624.mdwn
@@ -1,33 +0,0 @@-News for git-annex 3.20110624:--There has been another change to the git-annex data store.-Use `git annex upgrade` to migrate your repositories to the new-layout. See [[upgrades]].--The significant change this time is that the .git-annex/ directory-is gone; instead there is a git-annex branch that is automatically-maintained by git-annex, and encapsulates all its state nicely out-of your way.--You should make sure you include the git-annex branch when-git pushing and pulling.--git-annex 3.20110624 released with [[!toggle text="these changes"]]-[[!toggleable text="""- * New repository format, annex.version=3. Use `git annex upgrade` to migrate.- * git-annex now stores its logs in a git-annex branch.- * merge: New subcommand. Auto-merges the new git-annex branch.- * Improved handling of bare git repos with annexes. Many more commands will- work in them.- * git-annex is now more robust; it will never leave state files- uncommitted when some other git process comes along and locks the index- at an inconvenient time.- * rsync is now used when copying files from repos on other filesystems.- cp is still used when copying file from repos on the same filesystem,- since --reflink=auto can make it significantly faster on filesystems- such as btrfs.- * Allow --trust etc to specify a repository by name, for temporarily- trusting repositories that are not configured remotes.- * unlock: Made atomic.- * git-union-merge: New git subcommand, that does a generic union merge- operation, and operates efficiently without touching the working tree."""]]
− doc/news/version_3.20110702.mdwn
@@ -1,22 +0,0 @@-News for git-annex 3.20110702:--The URL backend has been removed. Instead the new web remote can be used.--git-annex 3.20110702 released with [[!toggle text="these changes"]]-[[!toggleable text="""- * Now the web can be used as a special remote.- This feature replaces the old URL backend.- * addurl: New command to download an url and store it in the annex.- * Sped back up fsck, copy --from, and other commands that often- have to read a lot of information from the git-annex branch. Such- commands are now faster than they were before introduction of the- git-annex branch.- * Always ensure git-annex branch exists.- * Modify location log parser to allow future expansion.- * --force will cause add, etc, to operate on ignored files.- * Avoid mangling encoding when storing the description of repository- and other content.- * cabal can now be used to build git-annex. This is substantially- slower than using make, does not build or install documentation,- does not run the test suite, and is not particularly recommended,- but could be useful to some."""]]
+ doc/news/version_3.20110719.mdwn view
@@ -0,0 +1,7 @@+git-annex 3.20110719 released with [[!toggle text="these changes"]]+[[!toggleable text="""+ * add: Be even more robust to avoid ever leaving the file seemingly deleted.+ Closes: #[634233](http://bugs.debian.org/634233)+ * Bugfix: Make add ../ work.+ * Support the standard git -c name=value+ * unannex: Clean up use of git commit -a."""]]
+ doc/news/version_3.20110817.mdwn view
@@ -0,0 +1,6 @@+git-annex 3.20110817 released with [[!toggle text="these changes"]]+[[!toggleable text="""+ * Fix shell escaping in rsync special remote.+ * addurl: --fast can be used to avoid immediately downloading the url.+ * Added support for getting content from git remotes using http (and https).+ * Added curl to Debian package dependencies."""]]
+ doc/news/version_3.20110819.mdwn view
@@ -0,0 +1,9 @@+git-annex 3.20110819 released with [[!toggle text="these changes"]]+[[!toggleable text="""+ * Now "git annex init" only has to be run once, when a git repository+ is first being created. Clones will automatically notice that git-annex+ is in use and automatically perform a basic initalization. It's+ still recommended to run "git annex init" in any clones, to describe them.+ * Added annex-cost-command configuration, which can be used to vary the+ cost of a remote based on the output of a shell command.+ * Fix broken upgrade from V1 repository. Closes: #[638584](http://bugs.debian.org/638584)"""]]
doc/special_remotes.mdwn view
@@ -1,6 +1,7 @@ Most [[backends]] can transfer data to and from configured git remotes.-Normally those remotes are normal git repositories (bare and non-bare),-that store the file contents in their own git annex directory.+Normally those remotes are normal git repositories (bare and non-bare;+local and remote), that store the file contents in their own git annex+directory. But, git-annex also extends git's concept of remotes, with these special types of remotes. These can be used just like any normal remote by git-annex.
doc/special_remotes/web.mdwn view
@@ -1,7 +1,11 @@ git-annex can use the WWW as a special remote, downloading urls to files.-See [[walkthrough/using_web_web]] for usage examples.+See [[walkthrough/using_the_web]] for usage examples. ## notes Currently git-annex only supports downloading content from the web; it cannot upload to it or remove content.++This special remote uses arbitrary urls on the web as the source for content.+git-annex can also download content from a normal git remote, accessible by+http.
doc/transferring_data.mdwn view
@@ -1,8 +1,12 @@ git-annex can transfer data to or from any of a repository's git remotes. Depending on where the remote is, the data transfer is done using rsync-(over ssh, with automatic resume), or plain cp (with copy-on-write-optimisations on supported filesystems). Some [[special_remotes]]-are also supported that are not traditional git remotes.+(over ssh or locally), or plain cp (with copy-on-write+optimisations on supported filesystems), or using curl (for repositories+on the web). Some [[special_remotes]] are also supported that are not+traditional git remotes.++If a data transfer is interrupted, git-annex retains the partial transfer+to allow it to be automatically resumed later. It's equally easy to transfer a single file to or from a repository, or to launch a retrievel of a massive pile of files from whatever
doc/upgrades.mdwn view
@@ -88,5 +88,6 @@ Handled more or less transparently, although git-annex was just 2 weeks old at the time, and had few users other than Joey. -This upgrade is believed to still be supported, but has not been tested-lately.+Before doing this upgrade, set annex.version:++ git config annex.version 0
git-annex-shell.hs view
@@ -58,10 +58,10 @@ builtin :: String -> String -> [String] -> IO () builtin cmd dir params = Git.repoAbsPath dir >>= Git.repoFromAbsPath >>=- dispatch (cmd:(filterparams params)) cmds commonOptions header+ dispatch (cmd : filterparams params) cmds commonOptions header external :: [String] -> IO ()-external params = do+external params = unlessM (boolSystem "git-shell" $ map Param $ "-c":filterparams params) $ error "git-shell failed"
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 3.20110707+Version: 3.20110819 Cabal-Version: >= 1.6 License: GPL Maintainer: Joey Hess <joey@kitenet.net>@@ -7,7 +7,7 @@ Stability: Stable Copyright: 2010-2011 Joey Hess License-File: GPL-Extra-Source-Files: ./debian/NEWS ./debian/control ./debian/rules ./debian/manpages ./debian/changelog ./debian/doc-base ./debian/copyright ./debian/compat ./AnnexQueue.hs ./configure.hs ./Annex.hs ./PresenceLog.hs ./Version.hs ./Crypto.hs ./RemoteLog.hs ./README ./Command/Merge.hs ./Command/AddUrl.hs ./Command/Whereis.hs ./Command/Unlock.hs ./Command/Version.hs ./Command/FromKey.hs ./Command/PreCommit.hs ./Command/Map.hs ./Command/Unused.hs ./Command/Uninit.hs ./Command/Migrate.hs ./Command/Init.hs ./Command/ConfigList.hs ./Command/Trust.hs ./Command/Lock.hs ./Command/SendKey.hs ./Command/RecvKey.hs ./Command/Add.hs ./Command/Fix.hs ./Command/Untrust.hs ./Command/InitRemote.hs ./Command/Semitrust.hs ./Command/Fsck.hs ./Command/Move.hs ./Command/DropUnused.hs ./Command/Get.hs ./Command/Upgrade.hs ./Command/Describe.hs ./Command/Drop.hs ./Command/DropKey.hs ./Command/InAnnex.hs ./Command/Find.hs ./Command/Unannex.hs ./Command/Status.hs ./Command/Copy.hs ./Command/SetKey.hs ./Types.hs ./Trust.hs ./StatFS.hsc ./Makefile ./git-annex.cabal ./Upgrade/V1.hs ./Upgrade/V2.hs ./Upgrade/V0.hs ./LocationLog.hs ./CHANGELOG ./Git/LsFiles.hs ./Git/UnionMerge.hs ./Git/Queue.hs ./Branch.hs ./doc/upgrades.mdwn ./doc/forum/wishlist:_define_remotes_that_must_have_all_files.mdwn ./doc/forum/Will_git_annex_work_on_a_FAT32_formatted_key__63__.mdwn ./doc/forum/wishlist:_command_options_changes/comment_2_f6a637c78c989382e3c22d41b7fb4cc2._comment ./doc/forum/wishlist:_command_options_changes/comment_3_bf1114533d2895804e531e76eb6b8095._comment ./doc/forum/wishlist:_command_options_changes/comment_1_bfba72a696789bf21b2435dea15f967a._comment ./doc/forum/wishlist:_git-annex_replicate/comment_3_c13f4f9c3d5884fc6255fd04feadc2b1._comment ./doc/forum/wishlist:_git-annex_replicate/comment_1_9926132ec6052760cdf28518a24e2358._comment ./doc/forum/wishlist:_git-annex_replicate/comment_2_c43932f4194aba8fb2470b18e0817599._comment ./doc/forum/Behaviour_of_fsck/comment_4_e4911dc6793f98fb81151daacbe49968._comment ./doc/forum/Behaviour_of_fsck/comment_3_97848f9a3db89c0427cfb671ba13300e._comment ./doc/forum/Behaviour_of_fsck/comment_2_ead36a23c3e6efa1c41e4555f93e014e._comment ./doc/forum/Behaviour_of_fsck/comment_1_0e40f158b3f4ccdcaab1408d858b68b8._comment ./doc/forum/incompatible_versions__63__/comment_1_629f28258746d413e452cbd42a1a43f4._comment ./doc/forum/migration_to_git-annex_and_rsync.mdwn ./doc/forum/hashing_objects_directories.mdwn ./doc/forum/hashing_objects_directories/comment_5_ef6cfd49d24c180c2d0a062e5bd3a0be._comment ./doc/forum/hashing_objects_directories/comment_1_c55c56076be4f54251b0b7f79f28a607._comment ./doc/forum/hashing_objects_directories/comment_2_504c96959c779176f991f4125ea22009._comment ./doc/forum/hashing_objects_directories/comment_3_9134bde0a13aac0b6a4e5ebabd7f22e8._comment ./doc/forum/hashing_objects_directories/comment_4_0de9170e429cbfea66f5afa8980d45ac._comment ./doc/forum/wishlist:_support_for_more_ssh_urls_.mdwn ./doc/forum/Wishlist:_Ways_of_selecting_files_based_on_meta-information.mdwn ./doc/forum/git-annex_on_OSX.mdwn ./doc/forum/git-annex_communication_channels/comment_2_c7aeefa6ef9a2e75d8667b479ade1b7f._comment ./doc/forum/git-annex_communication_channels/comment_5_404b723a681eb93fee015cea8024b6bc._comment ./doc/forum/git-annex_communication_channels/comment_1_198325d2e9337c90f026396de89eec0e._comment ./doc/forum/git-annex_communication_channels/comment_4_1ba6ddf54843c17c7d19a9996f2ab712._comment ./doc/forum/git-annex_communication_channels/comment_6_0d87d0e26461494b1d7f8a701a924729._comment ./doc/forum/git-annex_communication_channels/comment_3_1ff08a3e0e63fa0e560cbc9602245caa._comment ./doc/forum/git-annex_communication_channels/comment_7_2c87c7a0648fe87c2bf6b4391f1cc468._comment ./doc/forum/wishlist:_git-annex_replicate.mdwn ./doc/forum/performance_improvement:_git_on_ssd__44___annex_on_spindle_disk.mdwn ./doc/forum/Behaviour_of_fsck.mdwn ./doc/forum/working_without_git-annex_commits.mdwn ./doc/forum/migrate_existing_git_repository_to_git-annex.mdwn ./doc/forum/__34__git_annex_lock__34___very_slow_for_big_repo.mdwn ./doc/forum/wishlist:_traffic_accounting_for_git-annex.mdwn ./doc/forum/rsync_over_ssh__63__.mdwn ./doc/forum/unannex_alternatives/comment_3_b1687fc8f9e7744327bbeb6f0635d1cd._comment ./doc/forum/unannex_alternatives/comment_1_dcd4cd41280b41512bbdffafaf307993._comment ./doc/forum/unannex_alternatives/comment_2_58a72a9fe0f58c7af0b4d7927a2dd21d._comment ./doc/forum/wishlist:_git_annex_status/comment_4_9aeeb83d202dc8fb33ff364b0705ad94._comment ./doc/forum/wishlist:_git_annex_status/comment_3_d1fd70c67243971c96d59e1ffb7ef6e7._comment ./doc/forum/wishlist:_git_annex_status/comment_2_c2b0ce025805b774dc77ce264a222824._comment ./doc/forum/wishlist:_git_annex_status/comment_1_994bfd12c5d82e08040d6116915c5090._comment ./doc/forum/wishlist:_command_options_changes.mdwn ./doc/forum/new_microfeatures/comment_2_41ad904c68e89c85e1fc49c9e9106969._comment ./doc/forum/new_microfeatures/comment_1_058bd517c6fffaf3446b1f5d5be63623._comment ./doc/forum/new_microfeatures/comment_3_a1a9347b5bc517f2a89a8b292c3f8517._comment ./doc/forum/new_microfeatures/comment_7_94045b9078b1fff877933b012d1b49e2._comment ./doc/forum/new_microfeatures/comment_5_3c627d275586ff499d928a8f8136babf._comment ./doc/forum/new_microfeatures/comment_4_5a6786dc52382fff5cc42fdb05770196._comment ./doc/forum/new_microfeatures/comment_6_31ea08c008500560c0b96c6601bc6362._comment ./doc/forum/Error_while_adding_a_file___34__createSymbolicLink:_already_exists__34__.mdwn ./doc/forum/wishlist:_git_annex_put_--_same_as_get__44___but_for_defaults.mdwn ./doc/forum/OSX__39__s_default_sshd_behaviour_has_limited_paths_set.mdwn ./doc/forum/bainstorming:_git_annex_push___38___pull.mdwn ./doc/forum/sparse_git_checkouts_with_annex.mdwn ./doc/forum/Need_new_build_instructions_for_Debian_stable.mdwn ./doc/forum/batch_check_on_remote_when_using_copy.mdwn ./doc/forum/tips:_special__95__remotes__47__hook_with_tahoe-lafs.mdwn ./doc/forum/wishlist:alias_system.mdwn ./doc/forum/incompatible_versions__63__.mdwn ./doc/forum/wishlist:_git_backend_for_git-annex.mdwn ./doc/forum/seems_to_build_fine_on_haskell_platform_2011.mdwn ./doc/forum/rsync_over_ssh__63__/comment_1_ee21f32e90303e20339e0a568321bbbe._comment ./doc/forum/rsync_over_ssh__63__/comment_2_aa690da6ecfb2b30fc5080ad76dc77b1._comment ./doc/forum/wishlist:_special_remote_for_sftp_or_rsync.mdwn ./doc/forum/OSX__39__s_haskell-platform_statically_links_things.mdwn ./doc/forum/unannex_alternatives.mdwn ./doc/forum/can_git-annex_replace_ddm__63__.mdwn ./doc/forum/sparse_git_checkouts_with_annex/comment_2_e357db3ccc4079f07a291843975535eb._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_1_c7dc199c5740a0e7ba606dfb5e3e579a._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_3_fcfafca994194d57dccf5319c7c9e646._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_4_04dc14880f31eee2b6d767d4d4258c5a._comment ./doc/forum/git-annex_communication_channels.mdwn ./doc/forum/can_git-annex_replace_ddm__63__/comment_3_4c69097fe2ee81359655e59a03a9bb8d._comment ./doc/forum/can_git-annex_replace_ddm__63__/comment_2_008554306dd082d7f543baf283510e92._comment ./doc/forum/can_git-annex_replace_ddm__63__/comment_1_aa05008dfe800474ff76678a400099e1._comment ./doc/forum/relying_on_git_for_numcopies/comment_3_43d8e1513eb9947f8a503f094c03f307._comment ./doc/forum/relying_on_git_for_numcopies/comment_2_be6acbc26008a9cb54e7b8f498f2c2a2._comment ./doc/forum/relying_on_git_for_numcopies/comment_1_8ad3cccd7f66f6423341d71241ba89fc._comment ./doc/forum/relying_on_git_for_numcopies.mdwn ./doc/forum/wishlist:_do_round_robin_downloading_of_data.mdwn ./doc/forum/wishlist:_git_annex_status.mdwn ./doc/forum/getting_git_annex_to_do_a_force_copy_to_a_remote.mdwn ./doc/forum/Problems_with_large_numbers_of_files.mdwn ./doc/forum/Is_an_automagic_upgrade_of_the_object_directory_safe__63__.mdwn ./doc/forum/wishlist:_push_to_cia.vc_from_the_website__39__s_repo__44___not_your_personal_one.mdwn ./doc/forum/new_microfeatures.mdwn ./doc/backends.mdwn ./doc/bugs/softlink_mtime.mdwn ./doc/bugs/ordering.mdwn ./doc/bugs/dropping_files_with_a_URL_backend_fails.mdwn ./doc/bugs/fsck__47__fix_should_check__47__fix_the_permissions_of_.git__47__annex.mdwn ./doc/bugs/git_annex_get_choke_when_remote_is_an_ssh_url_with_a_port.mdwn ./doc/bugs/unannex_and_uninit_do_not_work_when_git_index_is_broken.mdwn ./doc/bugs/git_annex_migrate_leaves_old_backend_versions_around.mdwn ./doc/bugs/git_annex_unused_failes_on_empty_repository.mdwn ./doc/bugs/git_annex_add_eats_files_when_filename_is_too_long.mdwn ./doc/bugs/S3_bucket_uses_the_same_key_for_encryption_and_hashing.mdwn ./doc/bugs/problem_with_upgrade_v2_-__62___v3.mdwn ./doc/bugs/git_annex_copy_--fast_does_not_copy_files.mdwn ./doc/bugs/dotdot_problem.mdwn ./doc/bugs/Problems_running_make_on_osx.mdwn ./doc/bugs/free_space_checking/comment_2_8a65f6d3dcf5baa3f7f2dbe1346e2615._comment ./doc/bugs/free_space_checking/comment_3_0fc6ff79a357b1619d13018ccacc7c10._comment ./doc/bugs/free_space_checking/comment_1_a868e805be43c5a7c19c41f1af8e41e6._comment ./doc/bugs/done.mdwn ./doc/bugs/git_annex_copy_-f_REMOTE_._doesn__39__t_work_as_expected.mdwn ./doc/bugs/Displayed_copy_speed_is_wrong/comment_2_8b240de1d5ae9229fa2d77d1cc15a552._comment ./doc/bugs/Displayed_copy_speed_is_wrong/comment_1_74de3091e8bfd7acd6795e61f39f07c6._comment ./doc/bugs/bare_git_repos.mdwn ./doc/bugs/fat_support.mdwn ./doc/bugs/problems_with_utf8_names.mdwn ./doc/bugs/error_with_file_names_starting_with_dash.mdwn ./doc/bugs/unhappy_without_UTF8_locale.mdwn ./doc/bugs/S3_memory_leaks.mdwn ./doc/bugs/upgrade_left_untracked_.git-annex__47____42___directories.mdwn ./doc/bugs/Problems_running_make_on_osx/comment_9_cc283b485b3c95ba7eebc8f0c96969b3._comment ./doc/bugs/Problems_running_make_on_osx/comment_4_c52be386f79f14c8570a8f1397c68581._comment ./doc/bugs/Problems_running_make_on_osx/comment_18_64fab50d95de619eb2e8f08f90237de1._comment ./doc/bugs/Problems_running_make_on_osx/comment_16_5c2dd6002aadaab30841b77a5f5aed34._comment ./doc/bugs/Problems_running_make_on_osx/comment_10_94e4ac430140042a2d0fb5a16d86b4e5._comment ./doc/bugs/Problems_running_make_on_osx/comment_15_6b8867b8e48bf807c955779c9f8f0909._comment ./doc/bugs/Problems_running_make_on_osx/comment_11_56f1143fa191361d63b441741699e17f._comment ./doc/bugs/Problems_running_make_on_osx/comment_20_7db27d1a22666c831848bc6c06d66a84._comment ./doc/bugs/Problems_running_make_on_osx/comment_12_ec5131624d0d2285d3b6880e47033f97._comment ./doc/bugs/Problems_running_make_on_osx/comment_3_68f0f8ae953589ae26d57310b40c878d._comment ./doc/bugs/Problems_running_make_on_osx/comment_14_89a960b6706ed703b390a81a8bc4e311._comment ./doc/bugs/Problems_running_make_on_osx/comment_17_62fccb04b0e4b695312f7a3f32fb96ee._comment ./doc/bugs/Problems_running_make_on_osx/comment_19_4253988ed178054c8b6400beeed68a29._comment ./doc/bugs/Problems_running_make_on_osx/comment_6_0c46f5165ceb5a7b9ea9689c33b3a4f8._comment ./doc/bugs/Problems_running_make_on_osx/comment_1_34120e82331ace01a6a4960862d38f2d._comment ./doc/bugs/Problems_running_make_on_osx/comment_7_237a137cce58a28abcc736cbf2c420b0._comment ./doc/bugs/Problems_running_make_on_osx/comment_5_7f1330a1e541b0f3e2192e596d7f7bee._comment ./doc/bugs/Problems_running_make_on_osx/comment_2_cc53d1681d576186dbc868dd9801d551._comment ./doc/bugs/Problems_running_make_on_osx/comment_13_88ed095a448096bf8a69015a04e64df1._comment ./doc/bugs/Problems_running_make_on_osx/comment_8_efafa203addf8fa79e33e21a87fb5a2b._comment ./doc/bugs/git-annex_directory_hashing_problems_on_osx.mdwn ./doc/bugs/No_easy_way_to_re-inject_a_file_into_an_annex.mdwn ./doc/bugs/git_annex_unlock_is_not_atomic.mdwn ./doc/bugs/free_space_checking.mdwn ./doc/bugs/Displayed_copy_speed_is_wrong.mdwn ./doc/bugs/git_annex_should_use___39__git_add_-f__39___internally.mdwn ./doc/bugs/minor_bug:_errors_are_not_verbose_enough.mdwn ./doc/bugs/No_version_information_from_cli.mdwn ./doc/bugs/Error_while_adding_a_file___34__createSymbolicLink:_already_exists__34__.mdwn ./doc/bugs/tests_fail_when_there_is_no_global_.gitconfig_for_the_user.mdwn ./doc/bugs/git_annex_initremote_walks_.git-annex.mdwn ./doc/bugs/git-annex_incorrectly_parses_bare_IPv6_addresses.mdwn ./doc/bugs/conflicting_haskell_packages/comment_1_e552a6cc6d7d1882e14130edfc2d6b3b._comment ./doc/bugs/tmp_file_handling.mdwn ./doc/bugs/annex_add_in_annex.mdwn ./doc/bugs/making_annex-merge_try_a_fast-forward.mdwn ./doc/bugs/Makefile_is_missing_dependancies.mdwn ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_4_91439d4dbbf1461e281b276eb0003691._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_6_f360f0006bc9115bc5a3e2eb9fe58abd._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_3_86d9e7244ae492bcbe62720b8c4fc4a9._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_2_cd0123392b16d89db41b45464165c247._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_1_5f60006c9bb095167d817f234a14d20b._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_5_ca33a9ca0df33f7c1b58353d7ffb943d._comment ./doc/bugs/git_rename_detection_on_file_move/comment_3_57010bcaca42089b451ad8659a1e018e._comment ./doc/bugs/git_rename_detection_on_file_move/comment_4_79d96599f757757f34d7b784e6c0e81c._comment ./doc/bugs/git_rename_detection_on_file_move/comment_5_d61f5693d947b9736b29fca1dbc7ad76._comment ./doc/bugs/git_rename_detection_on_file_move/comment_2_7101d07400ad5935f880dc00d89bf90e._comment ./doc/bugs/git_rename_detection_on_file_move/comment_1_0531dcfa833b0321a7009526efe3df33._comment ./doc/bugs/add_range_argument_to___34__git_annex_dropunused__34___.mdwn ./doc/bugs/git_rename_detection_on_file_move.mdwn ./doc/bugs/problem_commit_normal_links.mdwn ./doc/bugs/git_annex_unused_seems_to_check_for_current_path.mdwn ./doc/bugs/Makefile_is_missing_dependancies/comment_6_24119fc5d5963ce9dd669f7dcf006859._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_3_c38b6f4abc9b9ad413c3b83ca04386c3._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_8_a3555e3286cdc2bfeb9cde0ff727ba74._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_2_416f12dbd0c2b841fac8164645b81df5._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_5_0a1c52e2c96d19b9c3eb7e99b8c2434f._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_7_96fd4725df4b54e670077a18d3ac4943._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_1_5a3da5f79c8563c7a450aa29728abe7c._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_4_cc13873175edf191047282700315beee._comment ./doc/bugs/touch.hsc_has_problems_on_non-linux_based_systems.mdwn ./doc/bugs/build_issue_with_latest_release_0.20110522-1-gde817ba.mdwn ./doc/bugs/weird_local_clone_confuses.mdwn ./doc/bugs/fsck_output.mdwn ./doc/bugs/git-annex_has_issues_with_git_when_staging__47__commiting_logs.mdwn ./doc/bugs/git_annex_gets_confused_about_remotes_with_dots_in_their_names.mdwn ./doc/bugs/unannex_vs_unlock_hook_confusion.mdwn ./doc/bugs/conflicting_haskell_packages.mdwn ./doc/bugs/backend_version_upgrade_leaves_repo_unusable.mdwn ./doc/bugs/fat_support/comment_3_df3b943bc1081a8f3f7434ae0c8e061e._comment ./doc/bugs/fat_support/comment_4_90a8a15bedd94480945a374f9d706b86._comment ./doc/bugs/fat_support/comment_5_64bbf89de0836673224b83fdefa0407b._comment ./doc/bugs/fat_support/comment_1_04bcc4795d431e8cb32293aab29bbfe2._comment ./doc/bugs/fat_support/comment_2_bb4a97ebadb5c53809fc78431eabd7c8._comment ./doc/bugs/annex_unannex__47__uninit_should_handle_copies.mdwn ./doc/bugs/git_annex_fsck_is_a_no-op_in_bare_repos.mdwn ./doc/bugs/Unfortunate_interaction_with_Calibre.mdwn ./doc/bugs/error_propigation.mdwn ./doc/bugs/scp_interrupt_to_background.mdwn ./doc/bugs/copy_fast_confusing_with_broken_locationlog.mdwn ./doc/bugs/configure_script_should_detect_uuidgen_instead_of_just_uuid.mdwn ./doc/bugs/check_for_curl_in_configure.hs.mdwn ./doc/bugs/Name_scheme_does_not_follow_git__39__s_rules.mdwn ./doc/bugs/building_on_lenny.mdwn ./doc/bugs/encrypted_S3_stalls.mdwn ./doc/bugs/WORM:_Handle_long_filenames_correctly.mdwn ./doc/logo_small.png ./doc/cheatsheet.mdwn ./doc/use_case/Bob.mdwn ./doc/use_case/Alice.mdwn ./doc/upgrades/SHA_size.mdwn ./doc/news/sharebox_a_FUSE_filesystem_for_git-annex.mdwn ./doc/news/version_3.20110624.mdwn ./doc/news/version_3.20110707.mdwn ./doc/news/version_0.20110610.mdwn ./doc/news/version_3.20110702.mdwn ./doc/news/version_3.20110705.mdwn ./doc/news/LWN_article.mdwn ./doc/git-union-merge.mdwn ./doc/special_remotes/S3.mdwn ./doc/special_remotes/web.mdwn ./doc/special_remotes/bup.mdwn ./doc/special_remotes/directory.mdwn ./doc/special_remotes/hook.mdwn ./doc/special_remotes/rsync.mdwn ./doc/users/joey.mdwn ./doc/users/fmarier.mdwn ./doc/users/chrysn.mdwn ./doc/templates/walkthrough.tmpl ./doc/templates/bare.tmpl ./doc/index.mdwn ./doc/summary.mdwn ./doc/forum.mdwn ./doc/encryption/comment_1_1afca8d7182075d46db41f6ad3dd5911._comment ./doc/transferring_data.mdwn ./doc/download.mdwn ./doc/future_proofing.mdwn ./doc/todo/auto_remotes/discussion.mdwn ./doc/todo/file_copy_progress_bar.mdwn ./doc/todo/use_cp_reflink.mdwn ./doc/todo/gitrm.mdwn ./doc/todo/git-annex_unused_eats_memory.mdwn ./doc/todo/add_--exclude_option_to_git_annex_find.mdwn ./doc/todo/tahoe_lfs_for_reals/comment_2_80b9e848edfdc7be21baab7d0cef0e3a._comment ./doc/todo/tahoe_lfs_for_reals/comment_1_0a4793ce6a867638f6e510e71dd4bb44._comment ./doc/todo/object_dir_reorg_v2.mdwn ./doc/todo/S3.mdwn ./doc/todo/auto_remotes.mdwn ./doc/todo/wishlist:_support_for_more_ssh_urls_.mdwn ./doc/todo/support-non-utf8-locales.mdwn ./doc/todo/done.mdwn ./doc/todo/fsck.mdwn ./doc/todo/support_S3_multipart_uploads.mdwn ./doc/todo/wishlist:_Provide_a___34__git_annex__34___command_that_will_skip_duplicates.mdwn ./doc/todo/pushpull.mdwn ./doc/todo/smudge.mdwn ./doc/todo/cache_key_info/comment_1_578df1b3b2cbfdc4aa1805378f35dc48._comment ./doc/todo/object_dir_reorg_v2/comment_3_79bdf9c51dec9f52372ce95b53233bb2._comment ./doc/todo/object_dir_reorg_v2/comment_7_42501404c82ca07147e2cce0cff59474._comment ./doc/todo/object_dir_reorg_v2/comment_5_821c382987f105da72a50e0a5ce61fdc._comment ./doc/todo/object_dir_reorg_v2/comment_1_ba03333dc76ff49eccaba375e68cb525._comment ./doc/todo/object_dir_reorg_v2/comment_2_81276ac309959dc741bc90101c213ab7._comment ./doc/todo/object_dir_reorg_v2/comment_6_8834c3a3f1258c4349d23aff8549bf35._comment ./doc/todo/object_dir_reorg_v2/comment_4_93aada9b1680fed56cc6f0f7c3aca5e5._comment ./doc/todo/union_mounting.mdwn ./doc/todo/wishlist:_swift_backend.mdwn ./doc/todo/wishlist:_swift_backend/comment_1_e6efbb35f61ee521b473a92674036788._comment ./doc/todo/wishlist:_swift_backend/comment_2_5d8c83b0485112e98367b7abaab3f4e3._comment ./doc/todo/git_annex_init_:_include_repo_description_and__47__or_UUID_in_commit_message.mdwn ./doc/todo/wishlist:___34__git_annex_add__34___multiple_processes.mdwn ./doc/todo/hidden_files.mdwn ./doc/todo/smudge/comment_1_4ea616bcdbc9e9a6fae9f2e2795c31c9._comment ./doc/todo/smudge/comment_2_e04b32caa0d2b4c577cdaf382a3ff7f6._comment ./doc/todo/network_remotes.mdwn ./doc/todo/add_a_git_backend.mdwn ./doc/todo/parallel_possibilities/comment_1_d8e34fc2bc4e5cf761574608f970d496._comment ./doc/todo/parallel_possibilities/comment_2_adb76f06a7997abe4559d3169a3181c3._comment ./doc/todo/checkout.mdwn ./doc/todo/immutable_annexed_files.mdwn ./doc/todo/wishlist:_Prevent_repeated_password_prompts_for_one_command.mdwn ./doc/todo/git-annex-shell.mdwn ./doc/todo/speed_up_fsck.mdwn ./doc/todo/tahoe_lfs_for_reals.mdwn ./doc/todo/using_url_backend.mdwn ./doc/todo/branching.mdwn ./doc/todo/rsync.mdwn ./doc/todo/backendSHA1.mdwn ./doc/todo/cache_key_info.mdwn ./doc/todo/parallel_possibilities.mdwn ./doc/todo/symlink_farming_commit_hook.mdwn ./doc/feeds.mdwn ./doc/copies.mdwn ./doc/repomap.png ./doc/special_remotes.mdwn ./doc/todo.mdwn ./doc/walkthrough/using_ssh_remotes.mdwn ./doc/walkthrough/untrusted_repositories.mdwn ./doc/walkthrough/moving_file_content_between_repositories.mdwn ./doc/walkthrough/modifying_annexed_files.mdwn ./doc/walkthrough/Internet_Archive_via_S3.mdwn ./doc/walkthrough/more.mdwn ./doc/walkthrough/removing_files.mdwn ./doc/walkthrough/creating_a_repository.mdwn ./doc/walkthrough/what_to_do_when_you_lose_a_repository.mdwn ./doc/walkthrough/using_Amazon_S3.mdwn ./doc/walkthrough/adding_a_remote.mdwn ./doc/walkthrough/adding_a_remote/comment_1_0a59355bd33a796aec97173607e6adc9._comment ./doc/walkthrough/adding_a_remote/comment_2_f8cd79ef1593a8181a7f1086a87713e8._comment ./doc/walkthrough/adding_a_remote/comment_3_60691af4400521b5a8c8d75efe3b44cb._comment ./doc/walkthrough/adding_a_remote/comment_4_6f7cf5c330272c96b3abeb6612075c9d._comment ./doc/walkthrough/removing_files:_When_things_go_wrong.mdwn ./doc/walkthrough/renaming_files.mdwn ./doc/walkthrough/using_bup.mdwn ./doc/walkthrough/fsck:_when_things_go_wrong.mdwn ./doc/walkthrough/adding_files.mdwn ./doc/walkthrough/unused_data.mdwn ./doc/walkthrough/fsck:_verifying_your_data.mdwn ./doc/walkthrough/getting_file_content.mdwn ./doc/walkthrough/using_the_web.mdwn ./doc/walkthrough/recover_data_from_lost+found.mdwn ./doc/walkthrough/backups.mdwn ./doc/walkthrough/transferring_files:_When_things_go_wrong.mdwn ./doc/walkthrough/using_the_SHA1_backend.mdwn ./doc/walkthrough/migrating_data_to_a_new_backend.mdwn ./doc/GPL ./doc/logo.png ./doc/location_tracking.mdwn ./doc/design.mdwn ./doc/news.mdwn ./doc/encryption.mdwn ./doc/not.mdwn ./doc/download/comment_7_a5eebd214b135f34b18274a682211943._comment ./doc/download/comment_3_cf6044ebe99f71158034e21197228abd._comment ./doc/download/comment_5_c6b1bc40226fc2c8ba3e558150856992._comment ./doc/download/comment_6_3a52993d3553deb9a413debec9a5f92d._comment ./doc/download/comment_2_f85f72b33aedc3425f0c0c47867d02f3._comment ./doc/download/comment_8_59a976de6c7d333709b92f7cd5830850._comment ./doc/download/comment_4_10fc013865c7542c2ed9d6c0963bb391._comment ./doc/download/comment_1_fbd8b6d39e9d3c71791551358c863966._comment ./doc/contact.mdwn ./doc/trust.mdwn ./doc/bare_repositories.mdwn ./doc/distributed_version_control.mdwn ./doc/install.mdwn ./doc/git-annex-shell.mdwn ./doc/bugs.mdwn ./doc/design/encryption/comment_2_a610b3d056a059899178859a3a821ea5._comment ./doc/design/encryption/comment_3_cca186a9536cd3f6e86994631b14231c._comment ./doc/design/encryption/comment_1_4715ffafb3c4a9915bc33f2b26aaa9c1._comment ./doc/design/encryption/comment_4_8f3ba3e504b058791fc6e6f9c38154cf._comment ./doc/design/encryption.mdwn ./doc/comments.mdwn ./doc/git-annex.mdwn ./doc/internals.mdwn ./doc/users.mdwn ./doc/install/Ubuntu.mdwn ./doc/install/Debian.mdwn ./doc/install/OSX.mdwn ./doc/install/FreeBSD.mdwn ./doc/install/comment_3_cff163ea3e7cad926f4ed9e78b896598._comment ./doc/install/Fedora.mdwn ./doc/install/comment_4_82a17eee4a076c6c79fddeda347e0c9a._comment ./doc/walkthrough.mdwn ./CmdLine.hs ./UUID.hs ./Messages.hs ./Setup.hs ./TestConfig.hs ./GPL ./mdwn2man ./Remote.hs ./git-annex.hs ./Locations.hs ./Backend/WORM.hs ./Backend/SHA.hs ./Options.hs ./git-annex-shell.hs ./test.hs ./INSTALL ./Remote/Encryptable.hs ./Remote/Web.hs ./Remote/S3stub.hs ./Remote/Ssh.hs ./Remote/Special.hs ./Remote/Directory.hs ./Remote/S3real.hs ./Remote/Bup.hs ./Remote/Hook.hs ./Remote/Rsync.hs ./Remote/Git.hs ./Utility.hs ./Upgrade.hs ./git-union-merge.hs ./Utility/DataUnits.hs ./Utility/RsyncFile.hs ./Utility/CopyFile.hs ./Utility/Dot.hs ./Utility/Base64.hs ./Types/Crypto.hs ./Types/UUID.hs ./Types/TrustLevel.hs ./Types/Remote.hs ./Types/BranchState.hs ./Types/Backend.hs ./Types/Key.hs ./Config.hs ./Command.hs ./.gitignore ./Backend.hs ./Touch.hsc ./Content.hs ./.gitattributes ./Git.hs ./GitAnnex.hs+Extra-Source-Files: ./debian/NEWS ./debian/control ./debian/rules ./debian/manpages ./debian/changelog ./debian/doc-base ./debian/copyright ./debian/compat ./AnnexQueue.hs ./configure.hs ./Annex.hs ./PresenceLog.hs ./Version.hs ./Crypto.hs ./RemoteLog.hs ./README ./Command/Merge.hs ./Command/AddUrl.hs ./Command/Whereis.hs ./Command/Unlock.hs ./Command/Version.hs ./Command/FromKey.hs ./Command/PreCommit.hs ./Command/Map.hs ./Command/Unused.hs ./Command/Uninit.hs ./Command/Migrate.hs ./Command/Init.hs ./Command/ConfigList.hs ./Command/Trust.hs ./Command/Lock.hs ./Command/SendKey.hs ./Command/RecvKey.hs ./Command/Add.hs ./Command/Fix.hs ./Command/Untrust.hs ./Command/InitRemote.hs ./Command/Semitrust.hs ./Command/Fsck.hs ./Command/Move.hs ./Command/DropUnused.hs ./Command/Get.hs ./Command/Upgrade.hs ./Command/Describe.hs ./Command/Drop.hs ./Command/DropKey.hs ./Command/InAnnex.hs ./Command/Find.hs ./Command/Unannex.hs ./Command/Status.hs ./Command/Copy.hs ./Command/SetKey.hs ./Init.hs ./Types.hs ./Trust.hs ./StatFS.hsc ./Makefile ./git-annex.cabal ./Upgrade/V1.hs ./Upgrade/V2.hs ./Upgrade/V0.hs ./LocationLog.hs ./CHANGELOG ./Git/LsFiles.hs ./Git/UnionMerge.hs ./Git/Queue.hs ./Branch.hs ./doc/upgrades.mdwn ./doc/forum/wishlist:_define_remotes_that_must_have_all_files.mdwn ./doc/forum/Will_git_annex_work_on_a_FAT32_formatted_key__63__.mdwn ./doc/forum/wishlist:_command_options_changes/comment_2_f6a637c78c989382e3c22d41b7fb4cc2._comment ./doc/forum/wishlist:_command_options_changes/comment_3_bf1114533d2895804e531e76eb6b8095._comment ./doc/forum/wishlist:_command_options_changes/comment_1_bfba72a696789bf21b2435dea15f967a._comment ./doc/forum/wishlist:_git-annex_replicate/comment_3_c13f4f9c3d5884fc6255fd04feadc2b1._comment ./doc/forum/wishlist:_git-annex_replicate/comment_1_9926132ec6052760cdf28518a24e2358._comment ./doc/forum/wishlist:_git-annex_replicate/comment_2_c43932f4194aba8fb2470b18e0817599._comment ./doc/forum/Behaviour_of_fsck/comment_4_e4911dc6793f98fb81151daacbe49968._comment ./doc/forum/Behaviour_of_fsck/comment_3_97848f9a3db89c0427cfb671ba13300e._comment ./doc/forum/Behaviour_of_fsck/comment_2_ead36a23c3e6efa1c41e4555f93e014e._comment ./doc/forum/Behaviour_of_fsck/comment_1_0e40f158b3f4ccdcaab1408d858b68b8._comment ./doc/forum/incompatible_versions__63__/comment_1_629f28258746d413e452cbd42a1a43f4._comment ./doc/forum/migration_to_git-annex_and_rsync.mdwn ./doc/forum/hashing_objects_directories.mdwn ./doc/forum/hashing_objects_directories/comment_5_ef6cfd49d24c180c2d0a062e5bd3a0be._comment ./doc/forum/hashing_objects_directories/comment_1_c55c56076be4f54251b0b7f79f28a607._comment ./doc/forum/hashing_objects_directories/comment_2_504c96959c779176f991f4125ea22009._comment ./doc/forum/hashing_objects_directories/comment_3_9134bde0a13aac0b6a4e5ebabd7f22e8._comment ./doc/forum/hashing_objects_directories/comment_4_0de9170e429cbfea66f5afa8980d45ac._comment ./doc/forum/wishlist:_support_for_more_ssh_urls_.mdwn ./doc/forum/Wishlist:_Ways_of_selecting_files_based_on_meta-information.mdwn ./doc/forum/git-annex_on_OSX.mdwn ./doc/forum/version_3_upgrade/comment_1_05fc9c9cad26c520bebb98c852c71e35._comment ./doc/forum/example_of_massively_disconnected_operation.mdwn ./doc/forum/git-annex_communication_channels/comment_2_c7aeefa6ef9a2e75d8667b479ade1b7f._comment ./doc/forum/git-annex_communication_channels/comment_5_404b723a681eb93fee015cea8024b6bc._comment ./doc/forum/git-annex_communication_channels/comment_1_198325d2e9337c90f026396de89eec0e._comment ./doc/forum/git-annex_communication_channels/comment_4_1ba6ddf54843c17c7d19a9996f2ab712._comment ./doc/forum/git-annex_communication_channels/comment_6_0d87d0e26461494b1d7f8a701a924729._comment ./doc/forum/git-annex_communication_channels/comment_3_1ff08a3e0e63fa0e560cbc9602245caa._comment ./doc/forum/git-annex_communication_channels/comment_7_2c87c7a0648fe87c2bf6b4391f1cc468._comment ./doc/forum/wishlist:_git-annex_replicate.mdwn ./doc/forum/performance_improvement:_git_on_ssd__44___annex_on_spindle_disk.mdwn ./doc/forum/Behaviour_of_fsck.mdwn ./doc/forum/working_without_git-annex_commits.mdwn ./doc/forum/migrate_existing_git_repository_to_git-annex.mdwn ./doc/forum/__34__git_annex_lock__34___very_slow_for_big_repo.mdwn ./doc/forum/wishlist:_traffic_accounting_for_git-annex.mdwn ./doc/forum/rsync_over_ssh__63__.mdwn ./doc/forum/unannex_alternatives/comment_3_b1687fc8f9e7744327bbeb6f0635d1cd._comment ./doc/forum/unannex_alternatives/comment_1_dcd4cd41280b41512bbdffafaf307993._comment ./doc/forum/unannex_alternatives/comment_2_58a72a9fe0f58c7af0b4d7927a2dd21d._comment ./doc/forum/wishlist:_git_annex_status/comment_4_9aeeb83d202dc8fb33ff364b0705ad94._comment ./doc/forum/wishlist:_git_annex_status/comment_3_d1fd70c67243971c96d59e1ffb7ef6e7._comment ./doc/forum/wishlist:_git_annex_status/comment_2_c2b0ce025805b774dc77ce264a222824._comment ./doc/forum/wishlist:_git_annex_status/comment_1_994bfd12c5d82e08040d6116915c5090._comment ./doc/forum/wishlist:_command_options_changes.mdwn ./doc/forum/new_microfeatures/comment_2_41ad904c68e89c85e1fc49c9e9106969._comment ./doc/forum/new_microfeatures/comment_1_058bd517c6fffaf3446b1f5d5be63623._comment ./doc/forum/new_microfeatures/comment_3_a1a9347b5bc517f2a89a8b292c3f8517._comment ./doc/forum/new_microfeatures/comment_7_94045b9078b1fff877933b012d1b49e2._comment ./doc/forum/new_microfeatures/comment_5_3c627d275586ff499d928a8f8136babf._comment ./doc/forum/new_microfeatures/comment_4_5a6786dc52382fff5cc42fdb05770196._comment ./doc/forum/new_microfeatures/comment_6_31ea08c008500560c0b96c6601bc6362._comment ./doc/forum/Error_while_adding_a_file___34__createSymbolicLink:_already_exists__34__.mdwn ./doc/forum/wishlist:_git_annex_put_--_same_as_get__44___but_for_defaults.mdwn ./doc/forum/OSX__39__s_default_sshd_behaviour_has_limited_paths_set.mdwn ./doc/forum/bainstorming:_git_annex_push___38___pull.mdwn ./doc/forum/sparse_git_checkouts_with_annex.mdwn ./doc/forum/Need_new_build_instructions_for_Debian_stable.mdwn ./doc/forum/batch_check_on_remote_when_using_copy.mdwn ./doc/forum/tips:_special__95__remotes__47__hook_with_tahoe-lafs.mdwn ./doc/forum/wishlist:alias_system.mdwn ./doc/forum/incompatible_versions__63__.mdwn ./doc/forum/wishlist:_git_backend_for_git-annex.mdwn ./doc/forum/seems_to_build_fine_on_haskell_platform_2011.mdwn ./doc/forum/rsync_over_ssh__63__/comment_1_ee21f32e90303e20339e0a568321bbbe._comment ./doc/forum/rsync_over_ssh__63__/comment_2_aa690da6ecfb2b30fc5080ad76dc77b1._comment ./doc/forum/wishlist:_special_remote_for_sftp_or_rsync.mdwn ./doc/forum/OSX__39__s_haskell-platform_statically_links_things.mdwn ./doc/forum/unannex_alternatives.mdwn ./doc/forum/can_git-annex_replace_ddm__63__.mdwn ./doc/forum/sparse_git_checkouts_with_annex/comment_2_e357db3ccc4079f07a291843975535eb._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_1_c7dc199c5740a0e7ba606dfb5e3e579a._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_3_fcfafca994194d57dccf5319c7c9e646._comment ./doc/forum/sparse_git_checkouts_with_annex/comment_4_04dc14880f31eee2b6d767d4d4258c5a._comment ./doc/forum/git-annex_communication_channels.mdwn ./doc/forum/can_git-annex_replace_ddm__63__/comment_3_4c69097fe2ee81359655e59a03a9bb8d._comment ./doc/forum/can_git-annex_replace_ddm__63__/comment_2_008554306dd082d7f543baf283510e92._comment ./doc/forum/can_git-annex_replace_ddm__63__/comment_1_aa05008dfe800474ff76678a400099e1._comment ./doc/forum/version_3_upgrade.mdwn ./doc/forum/relying_on_git_for_numcopies/comment_3_43d8e1513eb9947f8a503f094c03f307._comment ./doc/forum/relying_on_git_for_numcopies/comment_2_be6acbc26008a9cb54e7b8f498f2c2a2._comment ./doc/forum/relying_on_git_for_numcopies/comment_1_8ad3cccd7f66f6423341d71241ba89fc._comment ./doc/forum/relying_on_git_for_numcopies.mdwn ./doc/forum/wishlist:_do_round_robin_downloading_of_data.mdwn ./doc/forum/wishlist:_git_annex_status.mdwn ./doc/forum/getting_git_annex_to_do_a_force_copy_to_a_remote.mdwn ./doc/forum/Problems_with_large_numbers_of_files.mdwn ./doc/forum/Can_I_store_normal_files_in_the_git-annex_git_repository__63__.mdwn ./doc/forum/Is_an_automagic_upgrade_of_the_object_directory_safe__63__.mdwn ./doc/forum/wishlist:_push_to_cia.vc_from_the_website__39__s_repo__44___not_your_personal_one.mdwn ./doc/forum/new_microfeatures.mdwn ./doc/backends.mdwn ./doc/bugs/__39__annex_add__39___fails_to___39__git_add__39___for_parent_relative_path.mdwn ./doc/bugs/softlink_mtime.mdwn ./doc/bugs/ordering.mdwn ./doc/bugs/dropping_files_with_a_URL_backend_fails.mdwn ./doc/bugs/fsck__47__fix_should_check__47__fix_the_permissions_of_.git__47__annex.mdwn ./doc/bugs/git_annex_get_choke_when_remote_is_an_ssh_url_with_a_port.mdwn ./doc/bugs/unannex_and_uninit_do_not_work_when_git_index_is_broken.mdwn ./doc/bugs/git_annex_migrate_leaves_old_backend_versions_around.mdwn ./doc/bugs/git_annex_unused_failes_on_empty_repository.mdwn ./doc/bugs/git_annex_add_eats_files_when_filename_is_too_long.mdwn ./doc/bugs/S3_bucket_uses_the_same_key_for_encryption_and_hashing.mdwn ./doc/bugs/problem_with_upgrade_v2_-__62___v3.mdwn ./doc/bugs/git_annex_copy_--fast_does_not_copy_files.mdwn ./doc/bugs/Cabal_dependency_monadIO_missing.mdwn ./doc/bugs/dotdot_problem.mdwn ./doc/bugs/Problems_running_make_on_osx.mdwn ./doc/bugs/free_space_checking/comment_2_8a65f6d3dcf5baa3f7f2dbe1346e2615._comment ./doc/bugs/free_space_checking/comment_3_0fc6ff79a357b1619d13018ccacc7c10._comment ./doc/bugs/free_space_checking/comment_1_a868e805be43c5a7c19c41f1af8e41e6._comment ./doc/bugs/done.mdwn ./doc/bugs/git_annex_copy_-f_REMOTE_._doesn__39__t_work_as_expected.mdwn ./doc/bugs/Displayed_copy_speed_is_wrong/comment_2_8b240de1d5ae9229fa2d77d1cc15a552._comment ./doc/bugs/Displayed_copy_speed_is_wrong/comment_1_74de3091e8bfd7acd6795e61f39f07c6._comment ./doc/bugs/bare_git_repos.mdwn ./doc/bugs/fat_support.mdwn ./doc/bugs/problems_with_utf8_names.mdwn ./doc/bugs/error_with_file_names_starting_with_dash.mdwn ./doc/bugs/unhappy_without_UTF8_locale.mdwn ./doc/bugs/S3_memory_leaks.mdwn ./doc/bugs/upgrade_left_untracked_.git-annex__47____42___directories.mdwn ./doc/bugs/--git-dir_and_--work-tree_options.mdwn ./doc/bugs/Problems_running_make_on_osx/comment_9_cc283b485b3c95ba7eebc8f0c96969b3._comment ./doc/bugs/Problems_running_make_on_osx/comment_4_c52be386f79f14c8570a8f1397c68581._comment ./doc/bugs/Problems_running_make_on_osx/comment_18_64fab50d95de619eb2e8f08f90237de1._comment ./doc/bugs/Problems_running_make_on_osx/comment_16_5c2dd6002aadaab30841b77a5f5aed34._comment ./doc/bugs/Problems_running_make_on_osx/comment_10_94e4ac430140042a2d0fb5a16d86b4e5._comment ./doc/bugs/Problems_running_make_on_osx/comment_15_6b8867b8e48bf807c955779c9f8f0909._comment ./doc/bugs/Problems_running_make_on_osx/comment_11_56f1143fa191361d63b441741699e17f._comment ./doc/bugs/Problems_running_make_on_osx/comment_20_7db27d1a22666c831848bc6c06d66a84._comment ./doc/bugs/Problems_running_make_on_osx/comment_12_ec5131624d0d2285d3b6880e47033f97._comment ./doc/bugs/Problems_running_make_on_osx/comment_3_68f0f8ae953589ae26d57310b40c878d._comment ./doc/bugs/Problems_running_make_on_osx/comment_14_89a960b6706ed703b390a81a8bc4e311._comment ./doc/bugs/Problems_running_make_on_osx/comment_17_62fccb04b0e4b695312f7a3f32fb96ee._comment ./doc/bugs/Problems_running_make_on_osx/comment_19_4253988ed178054c8b6400beeed68a29._comment ./doc/bugs/Problems_running_make_on_osx/comment_6_0c46f5165ceb5a7b9ea9689c33b3a4f8._comment ./doc/bugs/Problems_running_make_on_osx/comment_1_34120e82331ace01a6a4960862d38f2d._comment ./doc/bugs/Problems_running_make_on_osx/comment_7_237a137cce58a28abcc736cbf2c420b0._comment ./doc/bugs/Problems_running_make_on_osx/comment_5_7f1330a1e541b0f3e2192e596d7f7bee._comment ./doc/bugs/Problems_running_make_on_osx/comment_2_cc53d1681d576186dbc868dd9801d551._comment ./doc/bugs/Problems_running_make_on_osx/comment_13_88ed095a448096bf8a69015a04e64df1._comment ./doc/bugs/Problems_running_make_on_osx/comment_8_efafa203addf8fa79e33e21a87fb5a2b._comment ./doc/bugs/git-annex_directory_hashing_problems_on_osx.mdwn ./doc/bugs/No_easy_way_to_re-inject_a_file_into_an_annex.mdwn ./doc/bugs/git_annex_unlock_is_not_atomic.mdwn ./doc/bugs/free_space_checking.mdwn ./doc/bugs/wishlist:_more_descriptive_commit_messages_in_git-annex_branch.mdwn ./doc/bugs/Displayed_copy_speed_is_wrong.mdwn ./doc/bugs/git_annex_should_use___39__git_add_-f__39___internally.mdwn ./doc/bugs/minor_bug:_errors_are_not_verbose_enough.mdwn ./doc/bugs/No_version_information_from_cli.mdwn ./doc/bugs/Error_while_adding_a_file___34__createSymbolicLink:_already_exists__34__.mdwn ./doc/bugs/tests_fail_when_there_is_no_global_.gitconfig_for_the_user.mdwn ./doc/bugs/git_annex_initremote_walks_.git-annex.mdwn ./doc/bugs/git-annex_incorrectly_parses_bare_IPv6_addresses.mdwn ./doc/bugs/conflicting_haskell_packages/comment_1_e552a6cc6d7d1882e14130edfc2d6b3b._comment ./doc/bugs/tmp_file_handling.mdwn ./doc/bugs/annex_add_in_annex.mdwn ./doc/bugs/making_annex-merge_try_a_fast-forward.mdwn ./doc/bugs/Makefile_is_missing_dependancies.mdwn ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_4_91439d4dbbf1461e281b276eb0003691._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_6_f360f0006bc9115bc5a3e2eb9fe58abd._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_3_86d9e7244ae492bcbe62720b8c4fc4a9._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_2_cd0123392b16d89db41b45464165c247._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_1_5f60006c9bb095167d817f234a14d20b._comment ./doc/bugs/problem_with_upgrade_v2_-__62___v3/comment_5_ca33a9ca0df33f7c1b58353d7ffb943d._comment ./doc/bugs/git_rename_detection_on_file_move/comment_3_57010bcaca42089b451ad8659a1e018e._comment ./doc/bugs/git_rename_detection_on_file_move/comment_4_79d96599f757757f34d7b784e6c0e81c._comment ./doc/bugs/git_rename_detection_on_file_move/comment_5_d61f5693d947b9736b29fca1dbc7ad76._comment ./doc/bugs/git_rename_detection_on_file_move/comment_2_7101d07400ad5935f880dc00d89bf90e._comment ./doc/bugs/git_rename_detection_on_file_move/comment_1_0531dcfa833b0321a7009526efe3df33._comment ./doc/bugs/add_range_argument_to___34__git_annex_dropunused__34___.mdwn ./doc/bugs/git_rename_detection_on_file_move.mdwn ./doc/bugs/problem_commit_normal_links.mdwn ./doc/bugs/git_annex_unused_seems_to_check_for_current_path.mdwn ./doc/bugs/Makefile_is_missing_dependancies/comment_6_24119fc5d5963ce9dd669f7dcf006859._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_3_c38b6f4abc9b9ad413c3b83ca04386c3._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_8_a3555e3286cdc2bfeb9cde0ff727ba74._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_2_416f12dbd0c2b841fac8164645b81df5._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_5_0a1c52e2c96d19b9c3eb7e99b8c2434f._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_7_96fd4725df4b54e670077a18d3ac4943._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_1_5a3da5f79c8563c7a450aa29728abe7c._comment ./doc/bugs/Makefile_is_missing_dependancies/comment_4_cc13873175edf191047282700315beee._comment ./doc/bugs/touch.hsc_has_problems_on_non-linux_based_systems.mdwn ./doc/bugs/build_issue_with_latest_release_0.20110522-1-gde817ba.mdwn ./doc/bugs/weird_local_clone_confuses.mdwn ./doc/bugs/fsck_output.mdwn ./doc/bugs/git-annex_has_issues_with_git_when_staging__47__commiting_logs.mdwn ./doc/bugs/git_annex_gets_confused_about_remotes_with_dots_in_their_names.mdwn ./doc/bugs/unannex_vs_unlock_hook_confusion.mdwn ./doc/bugs/Cabal_dependency_monadIO_missing/comment_2_4f4d8e1e00a2a4f7e8a8ab082e16adac._comment ./doc/bugs/Cabal_dependency_monadIO_missing/comment_1_14be660aa57fadec0d81b32a8b52c66f._comment ./doc/bugs/conflicting_haskell_packages.mdwn ./doc/bugs/git_command_line_constructed_by_unannex_command_has_tons_of_redundant_-a_paramters.mdwn ./doc/bugs/backend_version_upgrade_leaves_repo_unusable.mdwn ./doc/bugs/fat_support/comment_3_df3b943bc1081a8f3f7434ae0c8e061e._comment ./doc/bugs/fat_support/comment_4_90a8a15bedd94480945a374f9d706b86._comment ./doc/bugs/fat_support/comment_5_64bbf89de0836673224b83fdefa0407b._comment ./doc/bugs/fat_support/comment_1_04bcc4795d431e8cb32293aab29bbfe2._comment ./doc/bugs/fat_support/comment_2_bb4a97ebadb5c53809fc78431eabd7c8._comment ./doc/bugs/unannex_command_doesn__39__t_all_files.mdwn ./doc/bugs/annex_unannex__47__uninit_should_handle_copies.mdwn ./doc/bugs/git_annex_fsck_is_a_no-op_in_bare_repos.mdwn ./doc/bugs/Unfortunate_interaction_with_Calibre.mdwn ./doc/bugs/error_propigation.mdwn ./doc/bugs/scp_interrupt_to_background.mdwn ./doc/bugs/copy_fast_confusing_with_broken_locationlog.mdwn ./doc/bugs/configure_script_should_detect_uuidgen_instead_of_just_uuid.mdwn ./doc/bugs/check_for_curl_in_configure.hs.mdwn ./doc/bugs/Name_scheme_does_not_follow_git__39__s_rules.mdwn ./doc/bugs/Prevent_accidental_merges.mdwn ./doc/bugs/building_on_lenny.mdwn ./doc/bugs/encrypted_S3_stalls.mdwn ./doc/bugs/support_bare_git_repo__44___with_the_annex_directory_exposed_to_http.mdwn ./doc/bugs/WORM:_Handle_long_filenames_correctly.mdwn ./doc/logo_small.png ./doc/cheatsheet.mdwn ./doc/use_case/Bob.mdwn ./doc/use_case/Alice.mdwn ./doc/upgrades/SHA_size.mdwn ./doc/news/sharebox_a_FUSE_filesystem_for_git-annex.mdwn ./doc/news/version_3.20110817.mdwn ./doc/news/version_3.20110707.mdwn ./doc/news/version_3.20110705.mdwn ./doc/news/LWN_article.mdwn ./doc/news/version_3.20110719.mdwn ./doc/news/version_3.20110819.mdwn ./doc/git-union-merge.mdwn ./doc/special_remotes/S3.mdwn ./doc/special_remotes/web.mdwn ./doc/special_remotes/bup.mdwn ./doc/special_remotes/directory.mdwn ./doc/special_remotes/hook.mdwn ./doc/special_remotes/rsync.mdwn ./doc/users/joey.mdwn ./doc/users/fmarier.mdwn ./doc/users/chrysn.mdwn ./doc/templates/walkthrough.tmpl ./doc/templates/bare.tmpl ./doc/index.mdwn ./doc/summary.mdwn ./doc/forum.mdwn ./doc/encryption/comment_1_1afca8d7182075d46db41f6ad3dd5911._comment ./doc/transferring_data.mdwn ./doc/download.mdwn ./doc/future_proofing.mdwn ./doc/todo/auto_remotes/discussion.mdwn ./doc/todo/file_copy_progress_bar.mdwn ./doc/todo/use_cp_reflink.mdwn ./doc/todo/gitrm.mdwn ./doc/todo/git-annex_unused_eats_memory.mdwn ./doc/todo/add_--exclude_option_to_git_annex_find.mdwn ./doc/todo/tahoe_lfs_for_reals/comment_2_80b9e848edfdc7be21baab7d0cef0e3a._comment ./doc/todo/tahoe_lfs_for_reals/comment_1_0a4793ce6a867638f6e510e71dd4bb44._comment ./doc/todo/object_dir_reorg_v2.mdwn ./doc/todo/S3.mdwn ./doc/todo/auto_remotes.mdwn ./doc/todo/wishlist:_support_for_more_ssh_urls_.mdwn ./doc/todo/support-non-utf8-locales.mdwn ./doc/todo/done.mdwn ./doc/todo/fsck.mdwn ./doc/todo/support_S3_multipart_uploads.mdwn ./doc/todo/wishlist:_Provide_a___34__git_annex__34___command_that_will_skip_duplicates.mdwn ./doc/todo/pushpull.mdwn ./doc/todo/smudge.mdwn ./doc/todo/cache_key_info/comment_1_578df1b3b2cbfdc4aa1805378f35dc48._comment ./doc/todo/object_dir_reorg_v2/comment_3_79bdf9c51dec9f52372ce95b53233bb2._comment ./doc/todo/object_dir_reorg_v2/comment_7_42501404c82ca07147e2cce0cff59474._comment ./doc/todo/object_dir_reorg_v2/comment_5_821c382987f105da72a50e0a5ce61fdc._comment ./doc/todo/object_dir_reorg_v2/comment_1_ba03333dc76ff49eccaba375e68cb525._comment ./doc/todo/object_dir_reorg_v2/comment_2_81276ac309959dc741bc90101c213ab7._comment ./doc/todo/object_dir_reorg_v2/comment_6_8834c3a3f1258c4349d23aff8549bf35._comment ./doc/todo/object_dir_reorg_v2/comment_4_93aada9b1680fed56cc6f0f7c3aca5e5._comment ./doc/todo/union_mounting.mdwn ./doc/todo/wishlist:_swift_backend.mdwn ./doc/todo/wishlist:_swift_backend/comment_1_e6efbb35f61ee521b473a92674036788._comment ./doc/todo/wishlist:_swift_backend/comment_2_5d8c83b0485112e98367b7abaab3f4e3._comment ./doc/todo/git_annex_init_:_include_repo_description_and__47__or_UUID_in_commit_message.mdwn ./doc/todo/wishlist:___34__git_annex_add__34___multiple_processes.mdwn ./doc/todo/hidden_files.mdwn ./doc/todo/smudge/comment_1_4ea616bcdbc9e9a6fae9f2e2795c31c9._comment ./doc/todo/smudge/comment_2_e04b32caa0d2b4c577cdaf382a3ff7f6._comment ./doc/todo/network_remotes.mdwn ./doc/todo/add_a_git_backend.mdwn ./doc/todo/parallel_possibilities/comment_1_d8e34fc2bc4e5cf761574608f970d496._comment ./doc/todo/parallel_possibilities/comment_2_adb76f06a7997abe4559d3169a3181c3._comment ./doc/todo/checkout.mdwn ./doc/todo/immutable_annexed_files.mdwn ./doc/todo/wishlist:_Prevent_repeated_password_prompts_for_one_command.mdwn ./doc/todo/git-annex-shell.mdwn ./doc/todo/speed_up_fsck.mdwn ./doc/todo/tahoe_lfs_for_reals.mdwn ./doc/todo/using_url_backend.mdwn ./doc/todo/branching.mdwn ./doc/todo/rsync.mdwn ./doc/todo/backendSHA1.mdwn ./doc/todo/cache_key_info.mdwn ./doc/todo/parallel_possibilities.mdwn ./doc/todo/symlink_farming_commit_hook.mdwn ./doc/feeds.mdwn ./doc/copies.mdwn ./doc/repomap.png ./doc/special_remotes.mdwn ./doc/todo.mdwn ./doc/walkthrough/using_ssh_remotes.mdwn ./doc/walkthrough/untrusted_repositories.mdwn ./doc/walkthrough/moving_file_content_between_repositories.mdwn ./doc/walkthrough/modifying_annexed_files.mdwn ./doc/walkthrough/Internet_Archive_via_S3.mdwn ./doc/walkthrough/more.mdwn ./doc/walkthrough/removing_files.mdwn ./doc/walkthrough/creating_a_repository.mdwn ./doc/walkthrough/what_to_do_when_you_lose_a_repository.mdwn ./doc/walkthrough/using_Amazon_S3.mdwn ./doc/walkthrough/adding_a_remote.mdwn ./doc/walkthrough/adding_a_remote/comment_1_0a59355bd33a796aec97173607e6adc9._comment ./doc/walkthrough/adding_a_remote/comment_2_f8cd79ef1593a8181a7f1086a87713e8._comment ./doc/walkthrough/adding_a_remote/comment_3_60691af4400521b5a8c8d75efe3b44cb._comment ./doc/walkthrough/adding_a_remote/comment_4_6f7cf5c330272c96b3abeb6612075c9d._comment ./doc/walkthrough/removing_files:_When_things_go_wrong.mdwn ./doc/walkthrough/renaming_files.mdwn ./doc/walkthrough/using_bup.mdwn ./doc/walkthrough/fsck:_when_things_go_wrong.mdwn ./doc/walkthrough/adding_files.mdwn ./doc/walkthrough/unused_data.mdwn ./doc/walkthrough/fsck:_verifying_your_data.mdwn ./doc/walkthrough/getting_file_content.mdwn ./doc/walkthrough/using_the_web.mdwn ./doc/walkthrough/recover_data_from_lost+found.mdwn ./doc/walkthrough/backups.mdwn ./doc/walkthrough/transferring_files:_When_things_go_wrong.mdwn ./doc/walkthrough/using_the_SHA1_backend.mdwn ./doc/walkthrough/migrating_data_to_a_new_backend.mdwn ./doc/GPL ./doc/logo.png ./doc/location_tracking.mdwn ./doc/design.mdwn ./doc/news.mdwn ./doc/encryption.mdwn ./doc/not.mdwn ./doc/download/comment_7_a5eebd214b135f34b18274a682211943._comment ./doc/download/comment_3_cf6044ebe99f71158034e21197228abd._comment ./doc/download/comment_5_c6b1bc40226fc2c8ba3e558150856992._comment ./doc/download/comment_6_3a52993d3553deb9a413debec9a5f92d._comment ./doc/download/comment_2_f85f72b33aedc3425f0c0c47867d02f3._comment ./doc/download/comment_8_59a976de6c7d333709b92f7cd5830850._comment ./doc/download/comment_4_10fc013865c7542c2ed9d6c0963bb391._comment ./doc/download/comment_1_fbd8b6d39e9d3c71791551358c863966._comment ./doc/contact.mdwn ./doc/trust.mdwn ./doc/bare_repositories.mdwn ./doc/distributed_version_control.mdwn ./doc/install.mdwn ./doc/git-annex-shell.mdwn ./doc/bugs.mdwn ./doc/design/encryption/comment_2_a610b3d056a059899178859a3a821ea5._comment ./doc/design/encryption/comment_3_cca186a9536cd3f6e86994631b14231c._comment ./doc/design/encryption/comment_1_4715ffafb3c4a9915bc33f2b26aaa9c1._comment ./doc/design/encryption/comment_4_8f3ba3e504b058791fc6e6f9c38154cf._comment ./doc/design/encryption.mdwn ./doc/comments.mdwn ./doc/git-annex.mdwn ./doc/internals.mdwn ./doc/users.mdwn ./doc/install/Ubuntu.mdwn ./doc/install/Debian.mdwn ./doc/install/OSX.mdwn ./doc/install/FreeBSD.mdwn ./doc/install/comment_3_cff163ea3e7cad926f4ed9e78b896598._comment ./doc/install/Debian/comment_2_648e3467e260cdf233acdb0b53313ce0._comment ./doc/install/Debian/comment_1_029486088d098c2d4f1099f2f0e701a9._comment ./doc/install/Fedora.mdwn ./doc/install/comment_4_82a17eee4a076c6c79fddeda347e0c9a._comment ./doc/walkthrough.mdwn ./CmdLine.hs ./UUID.hs ./Messages.hs ./Setup.hs ./TestConfig.hs ./GPL ./mdwn2man ./Remote.hs ./git-annex.hs ./Locations.hs ./Backend/WORM.hs ./Backend/URL.hs ./Backend/SHA.hs ./Options.hs ./git-annex-shell.hs ./test.hs ./INSTALL ./Remote/Web.hs ./Remote/S3stub.hs ./Remote/Helper/Encryptable.hs ./Remote/Helper/Url.hs ./Remote/Helper/Ssh.hs ./Remote/Helper/Special.hs ./Remote/Directory.hs ./Remote/S3real.hs ./Remote/Bup.hs ./Remote/Hook.hs ./Remote/Rsync.hs ./Remote/Git.hs ./Utility.hs ./Upgrade.hs ./git-union-merge.hs ./Utility/DataUnits.hs ./Utility/RsyncFile.hs ./Utility/CopyFile.hs ./Utility/Dot.hs ./Utility/Base64.hs ./Types/Crypto.hs ./Types/UUID.hs ./Types/TrustLevel.hs ./Types/Remote.hs ./Types/BranchState.hs ./Types/Backend.hs ./Types/Key.hs ./Config.hs ./Command.hs ./.gitignore ./Backend.hs ./Touch.hsc ./Content.hs ./.gitattributes ./Git.hs ./GitAnnex.hs Homepage: http://git-annex.branchable.com/ Build-type: Custom Category: Utility@@ -31,7 +31,7 @@ Build-Depends: haskell98, MissingH, hslogger, directory, filepath, unix, containers, utf8-string, network, mtl, bytestring, old-locale, time, pcre-light, extensible-exceptions, dataenc, SHA, process, hS3, HTTP,- base < 5+ base < 5, monad-control Executable git-annex-shell Main-Is: git-annex-shell.hs
git-union-merge.hs view
@@ -20,11 +20,10 @@ usage = error $ "bad parameters\n\n" ++ header tmpIndex :: Git.Repo -> FilePath-tmpIndex g = Git.workTree g </> Git.gitDir g </> "index.git-union-merge"+tmpIndex g = Git.gitDir g </> "index.git-union-merge" setup :: Git.Repo -> IO ()-setup g = do- cleanup g -- idempotency+setup g = cleanup g -- idempotency cleanup :: Git.Repo -> IO () cleanup g = do@@ -34,7 +33,7 @@ parseArgs :: IO [String] parseArgs = do args <- getArgs- if (length args /= 3)+ if length args /= 3 then usage else return args
test.hs view
@@ -19,7 +19,7 @@ import System.Posix.Env import qualified Control.Exception.Extensible as E import Control.Exception (throw)-import Maybe+import Data.Maybe import qualified Data.Map as M import System.Path (recurseDir) import System.IO.HVFS (SystemFS(..))@@ -48,7 +48,7 @@ arbitrary = do n <- arbitrary b <- elements ['A'..'Z']- return $ Types.Key.Key {+ return Types.Key.Key { Types.Key.keyName = n, Types.Key.keyBackendName = [b], Types.Key.keySize = Nothing,@@ -108,7 +108,7 @@ reponame = "test repo" test_add :: Test-test_add = "git-annex add" ~: TestList [basic, sha1dup]+test_add = "git-annex add" ~: TestList [basic, sha1dup, subdirs] where -- this test case runs in the main repo, to set up a basic -- annexed file that later tests will use@@ -129,6 +129,14 @@ git_annex "add" ["-q", sha1annexedfiledup, "--backend=SHA1"] @? "add of second file with same SHA1 failed" annexed_present sha1annexedfiledup annexed_present sha1annexedfile+ subdirs = TestCase $ intmpclonerepo $ do+ createDirectory "dir"+ writeFile "dir/foo" $ content annexedfile+ git_annex "add" ["-q", "dir"] @? "add of subdir failed"+ createDirectory "dir2"+ writeFile "dir2/foo" $ content annexedfile+ changeWorkingDirectory "dir"+ git_annex "add" ["-q", "../dir2"] @? "add of ../subdir failed" test_setkey :: Test test_setkey = "git-annex setkey/fromkey" ~: TestCase $ inmainrepo $ do@@ -270,7 +278,7 @@ -- write different content, to verify that lock -- throws it away changecontent annexedfile- writeFile annexedfile $ (content annexedfile) ++ "foo"+ writeFile annexedfile $ content annexedfile ++ "foo" git_annex "lock" ["-q", annexedfile] @? "lock failed" annexed_present annexedfile git_annex "unlock" ["-q", annexedfile] @? "unlock failed" @@ -279,7 +287,7 @@ git_annex "add" ["-q", annexedfile] @? "add of modified file failed" runchecks [checklink, checkunwritable] annexedfile c <- readFile annexedfile- assertEqual ("content of modified file") c (changedcontent annexedfile)+ assertEqual "content of modified file" c (changedcontent annexedfile) r' <- git_annex "drop" ["-q", annexedfile] not r' @? "drop wrongly succeeded with no known copy of modified file" @@ -304,9 +312,9 @@ @? "git commit of edited file failed" runchecks [checklink, checkunwritable] annexedfile c <- readFile annexedfile- assertEqual ("content of modified file") c (changedcontent annexedfile)+ assertEqual "content of modified file" c (changedcontent annexedfile) r <- git_annex "drop" ["-q", annexedfile]- (not r) @? "drop wrongly succeeded with no known copy of modified file"+ not r @? "drop wrongly succeeded with no known copy of modified file" test_fix :: Test test_fix = "git-annex fix" ~: intmpclonerepo $ do@@ -323,7 +331,7 @@ git_annex "fix" ["-q", newfile] @? "fix of moved file failed" runchecks [checklink, checkunwritable] newfile c <- readFile newfile- assertEqual ("content of moved file") c (content annexedfile)+ assertEqual "content of moved file" c (content annexedfile) where subdir = "s" newfile = subdir ++ "/" ++ annexedfile