packages feed

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 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