packages feed

git-annex 3.20130216.1 → 4.20130227

raw patch · 172 files changed

+4846/−1548 lines, 172 filesdep +regex-compatdep −Globdep ~basedep ~networkdep ~yesod-defaultbinary-added

Dependencies added: regex-compat

Dependencies removed: Glob

Dependency ranges changed: base, network, yesod-default, yesod-form

Files

− .git-annex.cabal.swp

binary file changed (20480 → absent bytes)

.gitignore view
@@ -1,6 +1,5 @@ tmp test-configure build-stamp Build/SysConfig.hs git-annex@@ -11,9 +10,6 @@ html *.tix .hpc-Utility/Touch.hs-Utility/Mounts.hs-Utility/*.o dist # Sandboxed builds cabal-dev
Annex.hs view
@@ -116,6 +116,7 @@ 	, flags :: M.Map String Bool 	, fields :: M.Map String String 	, cleanup :: M.Map String (Annex ())+	, inodeschanged :: Maybe Bool 	}  newState :: Git.Repo -> AnnexState@@ -145,6 +146,7 @@ 	, flags = M.empty 	, fields = M.empty 	, cleanup = M.empty+	, inodeschanged = Nothing 	}  {- Makes an Annex state object for the specified git repo.
Annex/Branch.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU GPL version 3 or higher.  -} +{-# LANGUAGE CPP #-}+ module Annex.Branch ( 	fullname, 	name,@@ -22,7 +24,7 @@ ) where  import qualified Data.ByteString.Lazy.Char8 as L-import System.Environment+import System.Posix.Env  import Common.Annex import Annex.BranchState@@ -285,7 +287,17 @@ withIndex' bootstrapping a = do 	f <- fromRepo gitAnnexIndex 	g <- gitRepo+#ifdef __ANDROID__+	{- Work around for weird getEnvironment breakage on Android. See+	 - https://github.com/neurocyte/ghc-android/issues/7+	 - Instead, use getEnv to get some key environment variables that+	 - git expects to have. -}+	let keyenv = words "USER PATH GIT_EXEC_PATH HOSTNAME HOME"+	let getEnvPair k = maybe Nothing (\v -> Just (k, v)) <$> getEnv k+	e <- liftIO $ catMaybes <$> forM keyenv getEnvPair+#else 	e <- liftIO getEnvironment+#endif 	let g' = g { gitEnv = Just $ ("GIT_INDEX_FILE", f):e }  	Annex.changeState $ \s -> s { Annex.repo = g' }
Annex/Content.hs view
@@ -304,8 +304,8 @@ 	direct (f:fs) = do 		cache <- recordedInodeCache key 		-- check that we have a good file-		ifM (liftIO $ compareInodeCache f cache)-			( return $ Just (f, liftIO $ compareInodeCache f cache)+		ifM (sameInodeCache f cache)+			( return $ Just (f, sameInodeCache f cache) 			, direct fs 			) @@ -356,7 +356,7 @@ 		cache <- recordedInodeCache key 		removeInodeCache key 		mapM_ (resetfile cache) fs-	resetfile cache f = whenM (liftIO $ compareInodeCache f cache) $ do+	resetfile cache f = whenM (sameInodeCache f cache) $ do 		l <- calcGitLink f key 		top <- fromRepo Git.repoPath 		cwd <- liftIO getCurrentDirectory
Annex/Content/Direct.hs view
@@ -1,6 +1,6 @@ {- git-annex file content managing for direct mode  -- - Copyright 2010,2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012-2013 Joey Hess <joey@kitenet.net>  -  - Licensed under the GNU GPL version 3 or higher.  -}@@ -10,16 +10,19 @@ 	removeAssociatedFile, 	addAssociatedFile, 	goodContent,-	changedFileStatus, 	recordedInodeCache, 	updateInodeCache, 	writeInodeCache,-	compareInodeCache,+	sameInodeCache,+	sameFileStatus, 	removeInodeCache, 	toInodeCache,+	inodesChanged,+	createInodeSentinalFile, ) where  import Common.Annex+import qualified Annex import Annex.Perms import qualified Git import Utility.TempFile@@ -94,15 +97,7 @@  - expected mtime and inode.  -} goodContent :: Key -> FilePath -> Annex Bool-goodContent key file = do-	old <- recordedInodeCache key-	liftIO $ compareInodeCache file old--changedFileStatus :: Key -> FileStatus -> Annex Bool-changedFileStatus key status = do-	old <- recordedInodeCache key-	let curr = toInodeCache status-	return $ curr /= old+goodContent key file = sameInodeCache file =<< recordedInodeCache key  {- Gets the recorded inode cache for a key. -} recordedInodeCache :: Key -> Annex (Maybe InodeCache)@@ -128,3 +123,76 @@  withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a withInodeCacheFile key a = a =<< inRepo (gitAnnexInodeCache key)++{- Checks if a InodeCache matches the current version of a file. -}+sameInodeCache :: FilePath -> Maybe InodeCache -> Annex Bool+sameInodeCache _ Nothing = return False+sameInodeCache file (Just old) = go =<< liftIO (genInodeCache file)+  where+	go Nothing = return False+	go (Just curr) = compareInodeCaches curr old++{- Checks if a FileStatus matches the recorded InodeCache of a file. -}+sameFileStatus :: Key -> FileStatus -> Annex Bool+sameFileStatus key status = do+	old <- recordedInodeCache key+	let curr = toInodeCache status+	r <- case (old, curr) of+		(Just o, Just c) -> compareInodeCaches o c+		(Nothing, Nothing) -> return True+		_ -> return False+	return r++{- If the inodes have changed, only the size and mtime are compared. -}+compareInodeCaches :: InodeCache -> InodeCache -> Annex Bool+compareInodeCaches x y+	| x == y = return True+	| otherwise = ifM inodesChanged+		( return $ compareWeak x y+		, return False+		)++{- Some filesystems get new inodes each time they are mounted.+ - In order to work on such a filesystem, a sentinal file is used to detect+ - when the inodes have changed.+ -+ - If the sentinal file does not exist, we have to assume that the+ - inodes have changed.+ -}+inodesChanged :: Annex Bool+inodesChanged = maybe calc return =<< Annex.getState Annex.inodeschanged+  where+	calc = do+		scache <- liftIO . genInodeCache+			=<< fromRepo gitAnnexInodeSentinal+		scached <- readInodeSentinalFile+		let changed = case (scache, scached) of+			(Just c1, Just c2) -> c1 /= c2+			_ -> True+		Annex.changeState $ \s -> s { Annex.inodeschanged = Just changed }+		return changed++readInodeSentinalFile :: Annex (Maybe InodeCache)+readInodeSentinalFile = do+	sentinalcachefile <- fromRepo gitAnnexInodeSentinalCache+	liftIO $ catchDefaultIO Nothing $+		readInodeCache <$> readFile sentinalcachefile++writeInodeSentinalFile :: Annex ()+writeInodeSentinalFile = do+	sentinalfile <- fromRepo gitAnnexInodeSentinal+	sentinalcachefile <- fromRepo gitAnnexInodeSentinalCache+	liftIO $ writeFile sentinalfile ""+	liftIO $ maybe noop (writeFile sentinalcachefile . showInodeCache)+		=<< genInodeCache sentinalfile++{- The sentinal file is only created when first initializing a repository.+ - If there are any annexed objects in the repository already, creating+ - the file would invalidate their inode caches. -}+createInodeSentinalFile :: Annex ()+createInodeSentinalFile =+	unlessM (alreadyexists <||> hasobjects)+		writeInodeSentinalFile+  where+	alreadyexists = isJust <$> readInodeSentinalFile+	hasobjects = liftIO . doesDirectoryExist =<< fromRepo gitAnnexObjectDir
Annex/Direct.hs view
@@ -85,7 +85,7 @@ 	got Nothing = do 		showEndFail 		return False-	got (Just (key, _)) = ifM (liftIO $ compareInodeCache file $ Just cache)+	got (Just (key, _)) = ifM (sameInodeCache file $ Just cache) 		( do 			stageSymlink file =<< hashSymlink =<< calcGitLink file key 			writeInodeCache key cache
Annex/Link.hs view
@@ -38,13 +38,18 @@ getAnnexLinkTarget file = do 	v <- ifM (coreSymlinks <$> Annex.getGitConfig) 		( liftIO $ catchMaybeIO $ readSymbolicLink file-		, liftIO $ catchMaybeIO $ take 8192 <$> readFile file+		, liftIO $ catchMaybeIO $ readfilestart file 		) 	case v of 		Nothing -> return Nothing 		Just l 			| isLinkToAnnex l -> return v 			| otherwise -> return Nothing+  where+	readfilestart f = do+		h <- openFile f ReadMode+		fileEncoding h+		take 8192 <$> hGetContents h  {- Creates a link on disk.  -
Annex/Perms.hs view
@@ -70,7 +70,7 @@ 			) 	  where 		done = forM_ below $ \p -> do-			liftIO $ createDirectory p+			liftIO $ createDirectoryIfMissing True p 			setAnnexPerm p  {- Blocks writing to the directory an annexed file is in, to prevent the
Annex/Ssh.hs view
@@ -1,6 +1,6 @@ {- git-annex ssh interface, with connection caching  -- - Copyright 2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012,2013 Joey Hess <joey@kitenet.net>  -  - Licensed under the GNU GPL version 3 or higher.  -}@@ -13,14 +13,14 @@ ) where  import qualified Data.Map as M+import System.Posix.Env  import Common.Annex import Annex.LockPool import Annex.Perms-#ifndef WITH_OLD_SSH import qualified Build.SysConfig as SysConfig import qualified Annex-#endif+import Config  {- Generates parameters to ssh to a given host (or user@host) on a given  - port, with connection caching. -}@@ -40,33 +40,45 @@ 	cleanstale = whenM (not . any isLock . M.keys <$> getPool) $ 		sshCleanup +{- Returns a filename to use for a ssh connection caching socket, and+ - parameters to enable ssh connection caching. -} sshInfo :: (String, Maybe Integer) -> Annex (Maybe FilePath, [CommandParam])-sshInfo (host, port) = ifM caching-	( do-		dir <- fromRepo gitAnnexSshDir+sshInfo (host, port) = go =<< sshCacheDir+  where+	go Nothing = return (Nothing, [])+	go (Just dir) = do 		let socketfile = dir </> hostport2socket host port 		if valid_unix_socket_path socketfile-			then return (Just socketfile, cacheParams socketfile)+			then return (Just socketfile, cacheparams socketfile) 			else do 				socketfile' <- liftIO $ relPathCwdToFile socketfile 				if valid_unix_socket_path socketfile'-					then return (Just socketfile', cacheParams socketfile')+					then return (Just socketfile', cacheparams socketfile') 					else return (Nothing, [])-	, return (Nothing, [])-	)-  where-#ifdef WITH_OLD_SSH-	caching = return False-#else-	caching = fromMaybe SysConfig.sshconnectioncaching -		. annexSshCaching <$> Annex.getGitConfig-#endif+	cacheparams :: FilePath -> [CommandParam]+	cacheparams socketfile =+		[ Param "-S", Param socketfile+		, Params "-o ControlMaster=auto -o ControlPersist=yes"+		] -cacheParams :: FilePath -> [CommandParam]-cacheParams socketfile =-	[ Param "-S", Param socketfile-	, Params "-o ControlMaster=auto -o ControlPersist=yes"-	]+{- ssh connection caching creates sockets, so will not work on a+ - crippled filesystem. A GIT_ANNEX_TMP_DIR can be provided to use+ - a different filesystem. -}+sshCacheDir :: Annex (Maybe FilePath)+sshCacheDir+	| SysConfig.sshconnectioncaching = ifM crippledFileSystem+		( maybe (return Nothing) usetmpdir =<< gettmpdir+		, ifM (fromMaybe True . annexSshCaching <$> Annex.getGitConfig)+			( Just <$> fromRepo gitAnnexSshDir+			, return Nothing+			)+		)+	| otherwise = return Nothing+  where+	gettmpdir = liftIO $ getEnv "GIT_ANNEX_TMP_DIR"+	usetmpdir tmpdir = liftIO $ catchMaybeIO $ do+		createDirectoryIfMissing True tmpdir+		return $ tmpdir  portParams :: Maybe Integer -> [CommandParam] portParams Nothing = []@@ -74,12 +86,13 @@  {- Stop any unused ssh processes. -} sshCleanup :: Annex ()-sshCleanup = do-	dir <- fromRepo gitAnnexSshDir-	sockets <- filter (not . isLock) <$>-		liftIO (catchDefaultIO [] $ dirContents dir)-	forM_ sockets cleanup+sshCleanup = go =<< sshCacheDir   where+	go Nothing = noop+	go (Just dir) = do+		sockets <- filter (not . isLock) <$>+			liftIO (catchDefaultIO [] $ dirContents dir)+		forM_ sockets cleanup 	cleanup socketfile = do 		-- Drop any shared lock we have, and take an 		-- exclusive lock, without blocking. If the lock
Annex/Version.hs view
@@ -1,6 +1,6 @@ {- git-annex repository versioning  -- - Copyright 2010 Joey Hess <joey@kitenet.net>+ - Copyright 2010,2013 Joey Hess <joey@kitenet.net>  -  - Licensed under the GNU GPL version 3 or higher.  -}@@ -16,8 +16,11 @@ defaultVersion :: Version defaultVersion = "3" +directModeVersion :: Version+directModeVersion = "4"+ supportedVersions :: [Version]-supportedVersions = [defaultVersion]+supportedVersions = [defaultVersion, directModeVersion]  upgradableVersions :: [Version] upgradableVersions = ["0", "1", "2"]@@ -28,8 +31,8 @@ getVersion :: Annex (Maybe Version) getVersion = annexVersion <$> Annex.getGitConfig -setVersion :: Annex ()-setVersion = setConfig versionField defaultVersion+setVersion :: Version -> Annex ()+setVersion = setConfig versionField  removeVersion :: Annex () removeVersion = unsetConfig versionField
Assistant/Pairing.hs view
@@ -75,7 +75,7 @@ data SomeAddr = IPv4Addr HostAddress {- My Android build of the Network library does not currently have IPV6  - support. -}-#ifndef WITH_ANDROID+#ifndef __ANDROID__ 	| IPv6Addr HostAddress6 #endif 	deriving (Ord, Eq, Read, Show)
Assistant/Pairing/MakeRemote.hs view
@@ -41,7 +41,7 @@ 			, genSshHost (sshHostName sshdata) (sshUserName sshdata) 			, "git-annex-shell -c configlist " ++ T.unpack (sshDirectory sshdata) 			]-			""+			Nothing 	void $ makeSshRemote False sshdata  {- Mostly a straightforward conversion.  Except:
Assistant/Ssh.hs view
@@ -15,9 +15,6 @@  import Data.Text (Text) import qualified Data.Text as T-import qualified Control.Exception as E-import System.Process (CreateProcess(..))-import Control.Concurrent import Data.Char  data SshData = SshData@@ -61,36 +58,8 @@ 	| otherwise = makeLegalName $ host ++ "_" ++ dir  {- The output of ssh, including both stdout and stderr. -}-sshTranscript :: [String] -> String -> IO (String, Bool)-sshTranscript opts input = do-	(readf, writef) <- createPipe-	readh <- fdToHandle readf-	writeh <- fdToHandle writef-	(Just inh, _, _, pid) <- createProcess $-		(proc "ssh" opts)-			{ std_in = CreatePipe-			, std_out = UseHandle writeh-			, std_err = UseHandle writeh-			}-	hClose writeh--	-- fork off a thread to start consuming the output-	transcript <- hGetContents readh-	outMVar <- newEmptyMVar-	_ <- forkIO $ E.evaluate (length transcript) >> putMVar outMVar ()--	-- now write and flush any input-	unless (null input) $ do-		hPutStr inh input-		hFlush inh-	hClose inh -- done with stdin--	-- wait on the output-	takeMVar outMVar-	hClose readh--	ok <- checkSuccessProcess pid-	return (transcript, ok)+sshTranscript :: [String] -> (Maybe String) -> IO (String, Bool)+sshTranscript opts input = processTranscript "ssh" opts input  {- Ensure that the ssh public key doesn't include any ssh options, like  - command=foo, or other weirdness -}
Assistant/Threads/Committer.hs view
@@ -247,9 +247,7 @@ 		let inprocess' = inprocess ++ catMaybes (map mkinprocess $ zip pending keysources) 		openfiles <- S.fromList . map fst3 . filter openwrite <$> 			findopenfiles (map keySource inprocess')-		liftIO $ print openfiles 		let checked = map (check openfiles) inprocess'-		liftIO $ print checked  		{- If new events are received when files are closed, 		 - there's no need to retry any changes that cannot
Assistant/Threads/Watcher.hs view
@@ -181,11 +181,11 @@ 	v <- liftAnnex $ catKeyFile file 	case (v, fs) of 		(Just key, Just filestatus) ->-			ifM (liftAnnex $ changedFileStatus key filestatus)-				( do+			ifM (liftAnnex $ sameFileStatus key filestatus)+				( noChange+				, do 					liftAnnex $ changedDirect key file 					pendingAddChange file-				, noChange 				) 		_ -> pendingAddChange file 
Assistant/WebApp/Configurators/Local.hs view
@@ -7,10 +7,17 @@  {-# LANGUAGE CPP, TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings, RankNTypes #-} +#if defined VERSION_yesod_form+#if ! MIN_VERSION_yesod_form(1,2,0)+#define WITH_OLD_YESOD+#endif+#endif+ module Assistant.WebApp.Configurators.Local where  import Assistant.WebApp.Common import Assistant.WebApp.Utility+import Assistant.WebApp.OtherRepos import Assistant.MakeRemote import Init import qualified Git@@ -135,21 +142,36 @@ 			startFullAssistant $ T.unpack p 		_ -> $(widgetFile "configurators/newrepository/first") -{- Adding a new, separate repository. -}+{- Adding a new local repository, which may be entirely separate, or may+ - be connected to the current repository. -} getNewRepositoryR :: Handler RepHtml getNewRepositoryR = page "Add another repository" (Just Configuration) $ do 	home <- liftIO myHomeDir 	((res, form), enctype) <- lift $ runFormGet $ newRepositoryForm home 	case res of-		FormSuccess (RepositoryPath p) -> lift $ do+		FormSuccess (RepositoryPath p) -> do 			let path = T.unpack p 			liftIO $ makeRepo path False 			u <- liftIO $ initRepo True path Nothing-			runAnnex () $ setStandardGroup u ClientGroup+			lift $ runAnnex () $ setStandardGroup u ClientGroup 			liftIO $ addAutoStart path-			redirect $ SwitchToRepositoryR path+			liftIO $ startAssistant path+			askcombine u path 		_ -> $(widgetFile "configurators/newrepository")+  where+	askcombine newrepouuid newrepopath = do+		newrepo <- liftIO $ relHome newrepopath+		mainrepo <- fromJust . relDir <$> lift getYesod+		$(widgetFile "configurators/newrepository/combine") +getCombineRepositoryR :: FilePath -> UUID -> Handler RepHtml+getCombineRepositoryR newrepopath newrepouuid = do+	r <- combineRepos newrepopath remotename+	syncRemote r+	redirect $ EditRepositoryR newrepouuid+  where+	remotename = takeFileName newrepopath+ data RemovableDrive = RemovableDrive  	{ diskFree :: Maybe Integer 	, mountPoint :: Text@@ -188,7 +210,7 @@ 	make mountpoint = do 		liftIO $ makerepo dir 		u <- liftIO $ initRepo False dir $ Just remotename-		r <- addremote dir remotename+		r <- combineRepos dir remotename 		runAnnex () $ setStandardGroup u TransferGroup 		syncRemote r 		return u@@ -204,13 +226,16 @@ 			_ -> do 				createDirectoryIfMissing True dir 				makeRepo dir True-	{- Each repository is made a remote of the other. -}-	addremote dir name = runAnnex undefined $ do-		hostname <- maybe "host" id <$> liftIO getHostname-		hostlocation <- fromRepo Git.repoLocation-		liftIO $ inDir dir $ void $ makeGitRemote hostname hostlocation-		addRemote $ makeGitRemote name dir +{- Each repository is made a remote of the other.+ - Next call syncRemote to get them in sync. -}+combineRepos :: FilePath -> String -> Handler Remote+combineRepos dir name = runAnnex undefined $ do+	hostname <- maybe "host" id <$> liftIO getHostname+	hostlocation <- fromRepo Git.repoLocation+	liftIO $ inDir dir $ void $ makeGitRemote hostname hostlocation+	addRemote $ makeGitRemote name dir+ getEnableDirectoryR :: UUID -> Handler RepHtml getEnableDirectoryR uuid = page "Enable a repository" (Just Configuration) $ do 	description <- lift $ runAnnex "" $@@ -257,8 +282,9 @@ {- Makes a new git repository. -} makeRepo :: FilePath -> Bool -> IO () makeRepo path bare = do-	unlessM (boolSystem "git" params) $-		error "git init failed!"+	(transcript, ok) <- processTranscript "git" (toCommand params) Nothing+	unless ok $+		error $ "git init failed!\nOutput:\n" ++ transcript   where 	baseparams = [Param "init", Param "--quiet"] 	params
Assistant/WebApp/Configurators/Ssh.hs view
@@ -210,7 +210,7 @@ 				(inputUsername sshinput) 			, remotecommand 			]-		parsetranscript . fst <$> sshTranscript sshopts ""+		parsetranscript . fst <$> sshTranscript sshopts Nothing 	parsetranscript s 		| reported "git-annex-shell" = UsableSshInput 		| reported shim = UsableSshInput@@ -230,7 +230,7 @@  - and if it succeeds, runs an action. -} sshSetup :: [String] -> String -> Handler RepHtml -> Handler RepHtml sshSetup opts input a = do-	(transcript, ok) <- liftIO $ sshTranscript opts input+	(transcript, ok) <- liftIO $ sshTranscript opts (Just input) 	if ok 		then a 		else showSshErr transcript
Assistant/WebApp/Notifications.hs view
@@ -7,6 +7,12 @@  {-# LANGUAGE CPP, TypeFamilies, QuasiQuotes, MultiParamTypeClasses, TemplateHaskell, OverloadedStrings, RankNTypes #-} +#if defined VERSION_yesod_default+#if ! MIN_VERSION_yesod_default(1,1,0)+#define WITH_OLD_YESOD+#endif+#endif+ module Assistant.WebApp.Notifications where  import Assistant.Common
Assistant/WebApp/OtherRepos.hs view
@@ -43,14 +43,9 @@  -} getSwitchToRepositoryR :: FilePath -> Handler RepHtml getSwitchToRepositoryR repo = do-	liftIO startassistant-	url <- liftIO geturl-	redirect url+	liftIO $ startAssistant repo+	redirect =<< liftIO geturl   where-	startassistant = do-		program <- readProgramFile-		void $ forkIO $ void $ createProcess $-			(proc program ["assistant"]) { cwd = Just repo } 	geturl = do 		r <- Git.Config.read =<< Git.Construct.fromPath repo 		waiturl $ gitAnnexUrlFile r@@ -66,3 +61,9 @@ 	delayed a = do 		threadDelay 100000 -- 1/10th of a second 		a++startAssistant :: FilePath -> IO ()+startAssistant repo = do+	program <- readProgramFile+	void $ forkIO $ void $ createProcess $+		(proc program ["assistant"]) { cwd = Just repo }
Assistant/WebApp/routes view
@@ -20,6 +20,7 @@ /config/repository/new NewRepositoryR GET /config/repository/switcher RepositorySwitcherR GET /config/repository/switchto/#FilePath SwitchToRepositoryR GET+/config/repository/combine/#FilePath/#UUID CombineRepositoryR GET /config/repository/edit/#UUID EditRepositoryR GET /config/repository/edit/new/#UUID EditNewRepositoryR GET /config/repository/edit/new/cloud/#UUID EditNewCloudRepositoryR GET
Build/Configure.hs view
@@ -138,7 +138,6 @@ 	overrides =  		[ Config "cp_reflink_auto" $ BoolConfig False 		, Config "curl" $ BoolConfig False-		, Config "sshconnectioncaching" $ BoolConfig False 		, Config "sha224" $ MaybeStringConfig Nothing 		, Config "sha384" $ MaybeStringConfig Nothing 		]
CHANGELOG view
@@ -1,11 +1,34 @@-git-annex (3.20130217) UNRELEASED; urgency=low+git-annex (4.20130227) unstable; urgency=low +  * annex.version is now set to 4 for direct mode repositories.   * Should now fully support git repositories with core.symlinks=false;     always using git's pseudosymlink files in such repositories.   * webapp: Allow creating repositories on filesystems that lack support for     symlinks.+  * webapp: Can now add a new local repository, and make it sync with+    the main local repository.+  * Android: Bundle now includes openssh.+  * Android: Support ssh connection caching.+  * Android: Assistant is fully working. (But no webapp yet.)+  * Direct mode: Support filesystems like FAT which can change their inodes+    each time they are mounted.+  * Direct mode: Fix support for adding a modified file.+  * Avoid passing -p to rsync, to interoperate with crippled filesystems.+    Closes: #700282+  * Additional GIT_DIR support bugfixes. May actually work now.+  * webapp: Display any error message from git init if it fails to create+    a repository.+  * Fix a reversion in matching globs introduced in the last release,+    where "*" did not match files inside subdirectories. No longer uses+    the Glob library.+  * copy: Update location log when no copy was performed, if the location+    log was out of date.+  * Makefile now builds using cabal, taking advantage of cabal's automatic+    detection of appropriate build flags.+  * test: The test suite is now built into the git-annex binary, and can+    be run at any time. - -- Joey Hess <joeyh@debian.org>  Sun, 17 Feb 2013 16:42:16 -0400+ -- Joey Hess <joeyh@debian.org>  Wed, 27 Feb 2013 14:07:24 -0400  git-annex (3.20130216) unstable; urgency=low 
Command/Add.hs view
@@ -21,7 +21,7 @@ import Annex.Link import qualified Annex import qualified Annex.Queue-#ifndef WITH_ANDROID+#ifndef __ANDROID__ import Utility.Touch #endif import Utility.FileMode@@ -31,18 +31,21 @@ def :: [Command] def = [notBareRepo $ command "add" paramPaths seek "add files to annex"] -{- Add acts on both files not checked into git yet, and unlocked files. -}+{- Add acts on both files not checked into git yet, and unlocked files.+ -+ - In direct mode, it acts on any files that have changed. -} seek :: [CommandSeek] seek = 	[ withFilesNotInGit start 	, whenNotDirect $ withFilesUnlocked start+	, whenDirect $ withFilesMaybeModified start 	]  {- The add subcommand annexes a file, generating a key for it using a  - backend, and then moving it into the annex directory and setting up  - the symlink pointing to its content. -} start :: FilePath -> CommandStart-start file = ifAnnexed file fixup add+start file = ifAnnexed file addpresent add   where 	add = do 		s <- liftIO $ getSymbolicLinkStatus file@@ -51,7 +54,11 @@ 			else do 				showStart "add" file 				next $ perform file-	fixup (key, _) = do+	addpresent (key, _) = ifM isDirect+		( ifM (goodContent key file) ( stop , add )+		, fixup key+		)+	fixup key = do 		-- fixup from an interrupted add; the symlink 		-- is present but not yet added to git 		showStart "add" file@@ -159,7 +166,7 @@ 	l <- calcGitLink file key 	makeAnnexLink l file -#ifndef WITH_ANDROID+#ifndef __ANDROID__ 	when hascontent $ do 		-- touch the symlink to have the same mtime as the 		-- file it points to
Command/Direct.hs view
@@ -14,6 +14,7 @@ import qualified Git.LsFiles import Config import Annex.Direct+import Annex.Version  def :: [Command] def = [notBareRepo $ @@ -53,4 +54,5 @@ cleanup = do 	showStart "direct" "" 	setDirect True+	setVersion directModeVersion 	return True
Command/Indirect.hs view
@@ -17,6 +17,7 @@ import Annex.Direct import Annex.Content import Annex.CatFile+import Annex.Version import Init  def :: [Command]@@ -88,6 +89,7 @@  cleanup :: CommandCleanup cleanup = do+	setVersion defaultVersion 	showStart "indirect" "" 	showEndOk 	return True
Command/Move.hs view
@@ -79,9 +79,7 @@ 	fast <- Annex.getState Annex.fast 	let fastcheck = fast && not move && not (Remote.hasKeyCheap dest) 	isthere <- if fastcheck-		then do-			remotes <- Remote.keyPossibilities key-			return $ Right $ dest `elem` remotes+		then Right <$> expectedpresent 		else Remote.hasKey dest key 	case isthere of 		Left err -> do@@ -92,21 +90,26 @@ 			ok <- upload (Remote.uuid dest) key (Just file) noRetry $ 				Remote.storeKey dest key (Just file) 			if ok-				then finish True+				then do+					Remote.logStatus dest key InfoPresent+					finish 				else do 					when fastcheck $ 						warning "This could have failed because --fast is enabled." 					stop-		Right True -> finish False+		Right True -> do+			unlessM expectedpresent $+				Remote.logStatus dest key InfoPresent+			finish   where-	finish remotechanged = do-		when remotechanged $-			Remote.logStatus dest key InfoPresent-		if move-			then do-				removeAnnex key-				next $ Command.Drop.cleanupLocal key-			else next $ return True+	finish+		| move = do+			removeAnnex key+			next $ Command.Drop.cleanupLocal key+		| otherwise = next $ return True+	expectedpresent = do+		remotes <- Remote.keyPossibilities key+		return $ dest `elem` remotes  {- Moves (or copies) the content of an annexed file from a remote  - to the current repository.
+ Command/Test.hs view
@@ -0,0 +1,23 @@+{- git-annex command+ -+ - Copyright 2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Command.Test where++import Command++def :: [Command]+def = [ dontCheck repoExists $+	command "test" paramNothing seek "run built-in test suite"]++seek :: [CommandSeek]+seek = [withWords start]++{- We don't actually run the test suite here because of a dependency loop.+ - The main program notices when the command is test and runs it; this+ - function is never run if that works. -}+start :: [String] -> CommandStart+start _ = error "Cannot specify any additional parameters when running test"
Command/Upgrade.hs view
@@ -23,5 +23,5 @@ start = do 	showStart "upgrade" "." 	r <- upgrade-	setVersion+	setVersion defaultVersion 	next $ next $ return r
Common.hs view
@@ -12,7 +12,7 @@ import Data.List as X hiding (head, tail, init, last) import Data.String.Utils as X -import System.Path as X+import "MissingH" System.Path as X import System.FilePath as X import System.Directory as X import System.IO as X hiding (FilePath)
Git/Construct.hs view
@@ -17,6 +17,7 @@ 	fromRemotes, 	fromRemoteLocation, 	repoAbsPath,+	newFrom, ) where  import System.Posix.User@@ -31,17 +32,16 @@  {- Finds the git repository used for the cwd, which may be in a parent  - directory. -}-fromCwd :: IO Repo-fromCwd = getCurrentDirectory >>= seekUp checkForRepo+fromCwd :: IO (Maybe Repo)+fromCwd = getCurrentDirectory >>= seekUp   where-	norepo = error "Not in a git repository."-	seekUp check dir = do-		r <- check dir+	seekUp dir = do+		r <- checkForRepo dir 		case r of 			Nothing -> case parentDir dir of-				"" -> norepo-				d -> seekUp check d-			Just loc -> newFrom loc+				"" -> return Nothing+				d -> seekUp d+			Just loc -> Just <$> newFrom loc  {- Local Repo constructor, accepts a relative or absolute path. -} fromPath :: FilePath -> IO Repo
Git/CurrentRepo.hs view
@@ -47,15 +47,15 @@ 				unsetEnv s 				Just <$> absPath d 			Nothing -> return Nothing-	configure Nothing r = Git.Config.read r-	configure (Just d) r = do-		r' <- Git.Config.read r-		-- Let GIT_DIR override the default gitdir.++	configure Nothing (Just r) = Git.Config.read r+	configure (Just d) _ = do 		absd <- absPath d-		return $ changelocation r' $ Local-			{ gitdir = absd-			, worktree = worktree (location r')-			}+		cwd <- getCurrentDirectory+		r <- newFrom $ Local { gitdir = absd, worktree = Just cwd }+		Git.Config.read r+	configure Nothing Nothing = error "Not in a git repository."+ 	addworktree w r = changelocation r $ 		Local { gitdir = gitdir (location r), worktree = w } 	changelocation r l = r { location = l }
Git/LsFiles.hs view
@@ -9,6 +9,7 @@ 	inRepo, 	notInRepo, 	deleted,+	modified, 	staged, 	stagedNotDeleted, 	stagedDetails,@@ -45,6 +46,13 @@ deleted l repo = pipeNullSplit params repo   where 	params = [Params "ls-files --deleted -z --"] ++ map File l++{- Returns a list of files in the specified locations that have been+ - modified. -}+modified :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+modified l repo = pipeNullSplit params repo+  where+	params = [Params "ls-files --modified -z --"] ++ map File l  {- Returns a list of all files that are staged for commit. -} staged :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)
GitAnnex.hs view
@@ -77,6 +77,9 @@ import qualified Command.XMPPGit #endif #endif+#ifdef WITH_TESTSUITE+import qualified Command.Test+#endif  cmds :: [Command] cmds = concat@@ -134,6 +137,9 @@ #ifdef WITH_XMPP 	, Command.XMPPGit.def #endif+#endif+#ifdef WITH_TESTSUITE+	, Command.Test.def #endif 	] 
INSTALL view
@@ -3,7 +3,8 @@ [[!table format=dsv header=yes data=""" detailed instructions | quick install [[OSX]]               | [download git-annex.app](http://downloads.kitenet.net/git-annex/OSX/current/)-[[Linux|linux_standalone]] | [download prebuilt linux tarball](http://downloads.kitenet.net/git-annex/linux/)+[[Android]]           | [download git-annex.apk](http://downloads.kitenet.net/git-annex/android/current/) **beta**+[[Linux|linux_standalone]] | [download prebuilt linux tarball](http://downloads.kitenet.net/git-annex/linux/current/) [[Debian]]            | `apt-get install git-annex` [[Ubuntu]]            | `apt-get install git-annex` [[Fedora]]            | `yum install git-annex`@@ -14,7 +15,6 @@ [[ScientificLinux5]]  | (and other RHEL5 clones like CentOS5) [[openSUSE]]          |  Windows               | [[sorry, Windows not supported yet|todo/windows_support]]-[[Android]]           |  """]]  ## Using cabal
Init.hs view
@@ -27,6 +27,7 @@ import Utility.FileMode import Config import Annex.Direct+import Annex.Content.Direct import Backend  genDescription :: Maybe String -> Annex String@@ -41,10 +42,11 @@ initialize :: Maybe String -> Annex () initialize mdescription = do 	prepUUID+	setVersion defaultVersion 	checkCrippledFileSystem 	Annex.Branch.create-	setVersion 	gitPreCommitHookWrite+	createInodeSentinalFile 	u <- getUUID 	describeUUID u =<< genDescription mdescription @@ -76,10 +78,11 @@ 	hook <- preCommitHook 	ifM (liftIO $ doesFileExist hook) 		( warning $ "pre-commit hook (" ++ hook ++ ") already exists, not configuring"-		, liftIO $ do-			viaTmp writeFile hook preCommitScript-			p <- getPermissions hook-			setPermissions hook $ p {executable = True}+		, unlessM crippledFileSystem $+			liftIO $ do+				viaTmp writeFile hook preCommitScript+				p <- getPermissions hook+				setPermissions hook $ p {executable = True} 		)  gitPreCommitHookUnWrite :: Annex ()@@ -140,3 +143,4 @@ 			maybe noop (`toDirect` f) =<< isAnnexLink f 		void $ liftIO clean 		setDirect True+	setVersion directModeVersion
Limit.hs view
@@ -12,12 +12,8 @@ import Data.Time.Clock.POSIX import qualified Data.Set as S import qualified Data.Map as M-#ifdef WITH_GLOB-import "Glob" System.FilePath.Glob (simplify, compile, match)-#else-import Text.Regex.PCRE.Light.Char8 import System.Path.WildMatch-#endif+import Text.Regex  import Common.Annex import qualified Annex@@ -86,18 +82,14 @@ limitExclude :: MkLimit limitExclude glob = Right $ const $ return . not . matchglob glob +{- Could just use wildCheckCase, but this way the regex is only compiled+ - once. -} matchglob :: String -> Annex.FileInfo -> Bool matchglob glob (Annex.FileInfo { Annex.matchFile = f }) =-#ifdef WITH_GLOB-	match pattern f-  where-	pattern = simplify $ compile glob-#else-	isJust $ match cregex f []+	isJust $ matchRegex cregex f   where-	cregex = compile regex []+	cregex = mkRegex regex 	regex = '^':wildToRegex glob-#endif  {- Adds a limit to skip files not believed to be present  - in a specfied repository. -}
Locations.hs view
@@ -13,6 +13,8 @@ 	gitAnnexLocation, 	gitAnnexMapping, 	gitAnnexInodeCache,+	gitAnnexInodeSentinal,+	gitAnnexInodeSentinalCache, 	annexLocations, 	annexLocation, 	gitAnnexDir,@@ -128,6 +130,12 @@ 	loc <- gitAnnexLocation key r  	return $ loc ++ ".cache" +gitAnnexInodeSentinal :: Git.Repo -> FilePath+gitAnnexInodeSentinal r = gitAnnexDir r </> "sentinal"++gitAnnexInodeSentinalCache :: Git.Repo -> FilePath+gitAnnexInodeSentinalCache r = gitAnnexInodeSentinal r ++ ".cache"+ {- The annex directory of a repository. -} gitAnnexDir :: Git.Repo -> FilePath gitAnnexDir r = addTrailingPathSeparator $ Git.localGitDir r </> annexDir@@ -228,11 +236,14 @@ gitAnnexAssistantDefaultDir :: FilePath gitAnnexAssistantDefaultDir = "annex" -{- Checks a symlink target to see if it appears to point to annexed content. -}+{- Checks a symlink target to see if it appears to point to annexed content.+ -+ - We only look at paths inside the .git directory, and not at the .git+ - directory itself, because GIT_DIR may cause a directory name other+ - than .git to be used.+ -} isLinkToAnnex :: FilePath -> Bool-isLinkToAnnex s = ('/':d) `isInfixOf` s || d `isPrefixOf` s-  where-	d = ".git" </> objectDir+isLinkToAnnex s = ('/':objectDir) `isInfixOf` s  {- Converts a key into a filename fragment without any directory.  -
Makefile view
@@ -1,91 +1,28 @@-CFLAGS=-Wall-GIT_ANNEX_TMP_BUILD_DIR?=tmp-BASEFLAGS=-Wall -outputdir $(GIT_ANNEX_TMP_BUILD_DIR) -IUtility--# If you get build failures due to missing haskell libraries,-# you can turn off some of these features.-#-# If you're using an old version of yesod, enable -DWITH_OLD_YESOD-FEATURES?=$(GIT_ANNEX_LOCAL_FEATURES) -DWITH_ASSISTANT -DWITH_S3 -DWITH_WEBDAV -DWITH_WEBAPP -DWITH_PAIRING -DWITH_XMPP -DWITH_DNS -DWITH_GLOB--bins=git-annex mans=git-annex.1 git-annex-shell.1-sources=Build/SysConfig.hs Utility/Touch.hs Utility/Mounts.hs-all=$(bins) $(mans) docs--OS?=$(shell uname | sed 's/[-_].*//')-ifeq ($(OS),Android)-OPTFLAGS?=-DWITH_INOTIFY -DWITH_ANDROID-clibs=Utility/libdiskfree.o Utility/libmounts.o-CFLAGS:=-Wall -DWITH_ANDROID-THREADFLAGS=-threaded-else-ifeq ($(OS),Linux)-OPTFLAGS?=-DWITH_INOTIFY -DWITH_DBUS-clibs=Utility/libdiskfree.o Utility/libmounts.o-THREADFLAGS=$(shell if test -e  `ghc --print-libdir`/libHSrts_thr.a; then printf -- -threaded; fi)-else-ifeq ($(OS),SunOS)-# Solaris is not supported by the assistant or watch command.-FEATURES:=$(shell echo $(FEATURES) | sed -e 's/-DWITH_ASSISTANT//' -e 's/-DWITH_WEBAPP//')-else-# BSD system-THREADFLAGS=-threaded-ifeq ($(OS),Darwin)-# use fsevents for OSX-OPTFLAGS?=-DWITH_FSEVENTS-clibs=Utility/libdiskfree.o Utility/libmounts.o-# Ensure OSX compiler builds for 32 bit when using 32 bit ghc-GHCARCH:=$(shell ghc -e 'print System.Info.arch')-ifeq ($(GHCARCH),i386)-CFLAGS=-Wall -m32-endif-else-# BSD system with kqueue-OPTFLAGS?=-DWITH_KQUEUE-clibs=Utility/libdiskfree.o Utility/libmounts.o Utility/libkqueue.o-endif-endif-endif-endif--ALLFLAGS = $(BASEFLAGS) $(FEATURES) $(OPTFLAGS) $(THREADFLAGS)--PREFIX=/usr-GHCFLAGS=-O2 $(ALLFLAGS)--ifdef PROFILE-GHCFLAGS=-prof -auto-all -rtsopts -caf-all -fforce-recomp $(ALLFLAGS)-endif+all=git-annex $(mans) docs  GHC?=ghc GHCMAKE=$(GHC) $(GHCFLAGS) --make--# Am I typing :make in vim? Do a fast build.-ifdef VIM-all=fast-endif+PREFIX=/usr  build: $(all)-	touch build-stamp -sources: $(sources)+# We bypass cabal, and only run the main ghc --make command for a+# fast development built. Note: Does not rebuild C libraries.+fast: dist/caballog+	$$(grep 'ghc --make' dist/caballog | head -n 1 | sed 's/ -O / /')+	ln -sf dist/build/git-annex/git-annex git-annex -# Disables optimisation. Not for production use.-fast: GHCFLAGS=$(ALLFLAGS)-fast: $(bins)+dist/caballog: dist/setup-config+	cabal configure -f-Production+	cabal build -v2 | tee $@  Build/SysConfig.hs: configure.hs Build/TestConfig.hs Build/Configure.hs-	$(GHCMAKE) configure-	./configure $(OS)--%.hs: %.hsc-	hsc2hs $<+	cabal configure -git-annex: $(sources) $(clibs)-	install -d $(GIT_ANNEX_TMP_BUILD_DIR)-	$(GHCMAKE) $@ -o $(GIT_ANNEX_TMP_BUILD_DIR)/git-annex $(clibs)-	ln -sf $(GIT_ANNEX_TMP_BUILD_DIR)/git-annex git-annex+git-annex: Build/SysConfig.hs+	cabal build+	ln -sf dist/build/git-annex/git-annex git-annex  git-annex.1: doc/git-annex.mdwn 	./Build/mdwn2man git-annex 1 doc/git-annex.mdwn > git-annex.1@@ -104,29 +41,14 @@ 		rsync -a --delete html/ $(DESTDIR)$(PREFIX)/share/doc/git-annex/html/; \ 	fi -install: build-stamp install-docs+install: build install-docs 	install -d $(DESTDIR)$(PREFIX)/bin-	install $(bins) $(DESTDIR)$(PREFIX)/bin+	install git-annex $(DESTDIR)$(PREFIX)/bin 	ln -sf git-annex $(DESTDIR)$(PREFIX)/bin/git-annex-shell 	runghc Build/InstallDesktopFile.hs $(PREFIX)/bin/git-annex || true -test: $(sources) $(clibs)-	@if ! $(GHCMAKE) -O0 test $(clibs); then \-		echo "** failed to build the test suite" >&2; \-		exit 1; \-	elif ! ./test; then \-		echo "** test suite failed!" >&2; \-		exit 1; \-	fi--testcoverage:-	rm -f test.tix test-	$(GHC) $(GHCFLAGS) -outputdir $(GIT_ANNEX_TMP_BUILD_DIR)/testcoverage --make -fhpc test-	./test-	@echo ""-	@hpc report test --exclude=Main --exclude=QC-	@hpc markup test --exclude=Main --exclude=QC --destdir=.hpc >/dev/null-	@echo "(See .hpc/ for test coverage details.)"+test: git-annex+	./git-annex test  # hothasktags chokes on some tempolate haskell etc, so ignore errors tags:@@ -150,8 +72,8 @@ 		--exclude='bugs/*' --exclude='todo/*' --exclude='forum/*'  clean:-	rm -rf $(GIT_ANNEX_TMP_BUILD_DIR) $(bins) $(mans) test configure  *.tix .hpc $(sources) \-		doc/.ikiwiki html dist $(clibs) build-stamp tags+	rm -rf tmp dist git-annex $(mans) configure  *.tix .hpc \+		doc/.ikiwiki html dist tags Build/SysConfig.hs  sdist: clean $(mans) 	./Build/make-sdist.sh@@ -160,12 +82,12 @@ hackage: sdist 	@cabal upload dist/*.tar.gz -LINUXSTANDALONE_DEST=$(GIT_ANNEX_TMP_BUILD_DIR)/git-annex.linux+LINUXSTANDALONE_DEST=tmp/git-annex.linux linuxstandalone: 	$(MAKE) git-annex  	rm -rf "$(LINUXSTANDALONE_DEST)"-+	mkdir -p tmp 	cp -R standalone/linux "$(LINUXSTANDALONE_DEST)"  	install -d "$(LINUXSTANDALONE_DEST)/bin"@@ -194,15 +116,15 @@ 	sort "$(LINUXSTANDALONE_DEST)/libdirs.tmp" | uniq > "$(LINUXSTANDALONE_DEST)/libdirs" 	rm -f "$(LINUXSTANDALONE_DEST)/libdirs.tmp" -	cd $(GIT_ANNEX_TMP_BUILD_DIR) && tar czf git-annex-standalone-$(shell dpkg --print-architecture).tar.gz git-annex.linux+	cd tmp && tar czf git-annex-standalone-$(shell dpkg --print-architecture).tar.gz git-annex.linux -OSXAPP_DEST=$(GIT_ANNEX_TMP_BUILD_DIR)/build-dmg/git-annex.app+OSXAPP_DEST=tmp/build-dmg/git-annex.app OSXAPP_BASE=$(OSXAPP_DEST)/Contents/MacOS osxapp: 	$(MAKE) git-annex  	rm -rf "$(OSXAPP_DEST)"-	install -d $(GIT_ANNEX_TMP_BUILD_DIR)/build-dmg+	install -d tmp/build-dmg 	cp -R standalone/osx/git-annex.app "$(OSXAPP_DEST)"  	install -d "$(OSXAPP_BASE)"@@ -210,7 +132,7 @@ 	strip "$(OSXAPP_BASE)/git-annex" 	ln -sf git-annex "$(OSXAPP_BASE)/git-annex-shell" 	gzcat standalone/licences.gz > $(OSXAPP_BASE)/LICENSE-	cp $(OSXAPP_BASE)/LICENSE $(GIT_ANNEX_TMP_BUILD_DIR)/build-dmg/LICENSE.txt+	cp $(OSXAPP_BASE)/LICENSE tmp/build-dmg/LICENSE.txt  	runghc Build/Standalone.hs $(OSXAPP_BASE) @@ -219,47 +141,25 @@  	runghc Build/OSXMkLibs.hs $(OSXAPP_BASE) 	rm -f tmp/git-annex.dmg-	hdiutil create -size 640m -format UDRW -srcfolder $(GIT_ANNEX_TMP_BUILD_DIR)/build-dmg \+	hdiutil create -size 640m -format UDRW -srcfolder tmp/build-dmg \ 		-volname git-annex -o tmp/git-annex.dmg 	rm -f tmp/git-annex.dmg.bz2 	bzip2 --fast tmp/git-annex.dmg -# Cross compile for Android binary.+# Cross compile for Android. # Uses https://github.com/neurocyte/ghc-android-#-# configure is run, probing the local system.-# So the Android should have all the same stuff that configure probes for,-# including the same version of git. android:-	OS=Android $(MAKE) Build/SysConfig.hs-	GHC=$$HOME/.ghc/android-14/arm-linux-androideabi-4.7/bin/arm-unknown-linux-androideabi-ghc \-	CC=$$HOME/.ghc/android-14/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-gcc \-	FEATURES="-DWITH_ANDROID -DWITH_ASSISTANT -DWITH_GLOB -DWITH_DNS" \-	OS=Android $(MAKE) fast+	cabal configure+# cabal cannot cross compile with custom build type, so workaround+	sed -i 's/Build-type: Custom/Build-type: Simple/' git-annex.cabal+	$$HOME/.ghc/android-14/arm-linux-androideabi-4.7/arm-linux-androideabi/bin/cabal configure -f'Android Assistant -Pairing -Webapp -TestSuite'+	$(MAKE) git-annex+	sed -i 's/Build-type: Simple/Build-type: Custom/' git-annex.cabal -ANDROIDAPP_DEST=$(GIT_ANNEX_TMP_BUILD_DIR)/git-annex.android androidapp: 	$(MAKE) android 	$(MAKE) -C standalone/android--	rm -rf "$(ANDROIDAPP_DEST)"-	install -d "$(ANDROIDAPP_DEST)"--	cp -aR standalone/android/git-annex-bundle "$(ANDROIDAPP_DEST)"-	cp -a standalone/android/runshell "$(ANDROIDAPP_DEST)"-	install -d "$(ANDROIDAPP_DEST)/git-annex-bundle/bin"-	cp git-annex "$(ANDROIDAPP_DEST)/git-annex-bundle/bin/"--	$$HOME/.ghc/android-14/arm-linux-androideabi-4.7/bin/arm-linux-androideabi-strip "$(ANDROIDAPP_DEST)"/git-annex-bundle/bin/*--	ln -sf git-annex "$(ANDROIDAPP_DEST)/git-annex-bundle/bin/git-annex-shell"-	zcat standalone/licences.gz > $(ANDROIDAPP_DEST)/git-annex-bundle/LICENSE-	install -d "$(ANDROIDAPP_DEST)/git-annex-bundle/templates"-	-	cd $(ANDROIDAPP_DEST) && tar czf ../git-annex-android.tar.gz .--# used by ./ghci-getflags:-	@echo $(ALLFLAGS) $(clibs)+	mkdir -p tmp+	cp standalone/android/source/term/bin/Term-debug.apk tmp/git-annex.apk -.PHONY: $(bins) test install tags+.PHONY: git-annex tags
Remote/Git.hs view
@@ -427,7 +427,7 @@  -- --inplace to resume partial files rsyncParams :: Remote -> [CommandParam]-rsyncParams r = [Params "-p --progress --inplace"] +++rsyncParams r = [Params "--progress --inplace"] ++ 	map Param (remoteAnnexRsyncOptions $ gitconfig r)  commitOnCleanup :: Remote -> Annex a -> Annex a
Remote/WebDAV.hs view
@@ -5,8 +5,14 @@  - Licensed under the GNU GPL version 3 or higher.  -} -{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables, CPP #-} +#if defined VERSION_http_conduit+#if ! MIN_VERSION_http_conduit(1,9,0)+#define WITH_OLD_HTTP_CONDUIT+#endif+#endif+ module Remote.WebDAV (remote, davCreds, setCredsEnv) where  import Network.Protocol.HTTP.DAV@@ -228,7 +234,11 @@ davUrlExists url user pass = decode <$> catchHttp (getProps url user pass)   where 	decode (Right _) = Right True+#ifdef WITH_OLD_HTTP_CONDUIT 	decode (Left (Left (StatusCodeException status _)))+#else+	decode (Left (Left (StatusCodeException status _ _)))+#endif 		| statusCode status == statusCode notFound404 = Right False 	decode (Left e) = Left $ showEitherException e @@ -275,7 +285,12 @@ type EitherException = Either HttpException E.IOException  showEitherException :: EitherException -> String-showEitherException (Left (StatusCodeException status _)) = show $ statusMessage status+#ifdef WITH_OLD_HTTP_CONDUIT+showEitherException (Left (StatusCodeException status _)) =+#else+showEitherException (Left (StatusCodeException status _ _)) =+#endif+	show $ statusMessage status showEitherException (Left httpexception) = show httpexception showEitherException (Right ioexception) = show ioexception 
Seek.hs view
@@ -88,6 +88,11 @@ 	let unlockedfiles = liftIO $ filterM notSymlink typechangedfiles 	prepFiltered a unlockedfiles +{- Finds files that may be modified. -}+withFilesMaybeModified :: (FilePath -> CommandStart) -> CommandSeek+withFilesMaybeModified a params =+	prepFiltered a $ seekHelper LsFiles.modified params+ withKeys :: (Key -> CommandStart) -> CommandSeek withKeys a params = return $ map (a . parse) params   where
+ Test.hs view
@@ -0,0 +1,1023 @@+{- git-annex test suite+ -+ - Copyright 2010-2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++{-# OPTIONS_GHC -fno-warn-orphans #-}++module Test where++import Test.HUnit+import Test.HUnit.Tools+import Test.QuickCheck+import Test.QuickCheck.Instances ()++import System.Posix.Directory (changeWorkingDirectory)+import System.Posix.Files+import System.Posix.Env+import Control.Exception.Extensible+import qualified Data.Map as M+import System.IO.HVFS (SystemFS(..))+import Text.JSON++import Common+import Utility.QuickCheck ()++import qualified Utility.SafeCommand+import qualified Annex+import qualified Annex.UUID+import qualified Backend+import qualified Git.CurrentRepo+import qualified Git.Filename+import qualified Locations+import qualified Types.KeySource+import qualified Types.Backend+import qualified Types.TrustLevel+import qualified Types+import qualified GitAnnex+import qualified Logs.UUIDBased+import qualified Logs.Trust+import qualified Logs.Remote+import qualified Logs.Unused+import qualified Logs.Transfer+import qualified Logs.Presence+import qualified Remote+import qualified Types.Key+import qualified Types.Messages+import qualified Config+import qualified Crypto+import qualified Utility.Path+import qualified Utility.FileMode+import qualified Utility.Gpg+import qualified Build.SysConfig+import qualified Utility.Format+import qualified Utility.Verifiable+import qualified Utility.Process+import qualified Utility.Misc+import qualified Utility.InodeCache++-- instances for quickcheck+instance Arbitrary Types.Key.Key where+	arbitrary = Types.Key.Key+		<$> arbitrary+		<*> (listOf1 $ elements ['A'..'Z']) -- BACKEND+		<*> ((abs <$>) <$> arbitrary) -- size cannot be negative+		<*> arbitrary++instance Arbitrary Logs.Transfer.TransferInfo where+	arbitrary = Logs.Transfer.TransferInfo+		<$> arbitrary+		<*> arbitrary+		<*> pure Nothing -- cannot generate a ThreadID+		<*> pure Nothing -- remote not needed+		<*> arbitrary+		-- associated file cannot be empty (but can be Nothing)+		<*> arbitrary `suchThat` (/= Just "")+		<*> arbitrary++instance Arbitrary Utility.InodeCache.InodeCache where+	arbitrary = Utility.InodeCache.InodeCache+		<$> arbitrary+		<*> arbitrary+		<*> arbitrary++instance Arbitrary Logs.Presence.LogLine where+	arbitrary = Logs.Presence.LogLine+		<$> arbitrary+		<*> elements [minBound..maxBound]+		<*> arbitrary `suchThat` ('\n' `notElem`)++main :: IO ()+main = do+	prepare+	r <- runVerboseTests $ TestList [quickcheck, blackbox]+	cleanup tmpdir+	propigate r++propigate :: (Counts, Int) -> IO ()+propigate (Counts { errors = e , failures = f }, _)+	| e+f > 0 = error "failed"+	| otherwise = return ()++quickcheck :: Test+quickcheck = TestLabel "quickcheck" $ TestList+	[ qctest "prop_idempotent_deencode_git" Git.Filename.prop_idempotent_deencode+	, qctest "prop_idempotent_deencode" Utility.Format.prop_idempotent_deencode+	, qctest "prop_idempotent_fileKey" Locations.prop_idempotent_fileKey+	, qctest "prop_idempotent_key_encode" Types.Key.prop_idempotent_key_encode+	, qctest "prop_idempotent_shellEscape" Utility.SafeCommand.prop_idempotent_shellEscape+	, qctest "prop_idempotent_shellEscape_multiword" Utility.SafeCommand.prop_idempotent_shellEscape_multiword+	, qctest "prop_idempotent_configEscape" Logs.Remote.prop_idempotent_configEscape+	, qctest "prop_parse_show_Config" Logs.Remote.prop_parse_show_Config+	, qctest "prop_parentDir_basics" Utility.Path.prop_parentDir_basics+	, qctest "prop_relPathDirToFile_basics" Utility.Path.prop_relPathDirToFile_basics+	, qctest "prop_relPathDirToFile_regressionTest" Utility.Path.prop_relPathDirToFile_regressionTest+	, qctest "prop_cost_sane" Config.prop_cost_sane+	, qctest "prop_hmacWithCipher_sane" Crypto.prop_hmacWithCipher_sane+	, qctest "prop_TimeStamp_sane" Logs.UUIDBased.prop_TimeStamp_sane+	, qctest "prop_addLog_sane" Logs.UUIDBased.prop_addLog_sane+	, qctest "prop_verifiable_sane" Utility.Verifiable.prop_verifiable_sane+	, qctest "prop_segment_regressionTest" Utility.Misc.prop_segment_regressionTest+	, qctest "prop_read_write_transferinfo" Logs.Transfer.prop_read_write_transferinfo+	, qctest "prop_read_show_inodecache" Utility.InodeCache.prop_read_show_inodecache+	, qctest "prop_parse_show_log" Logs.Presence.prop_parse_show_log+	, qctest "prop_read_show_TrustLevel" Types.TrustLevel.prop_read_show_TrustLevel+	, qctest "prop_parse_show_TrustLog" Logs.Trust.prop_parse_show_TrustLog+	]++blackbox :: Test+blackbox = TestLabel "blackbox" $ TestList+	-- test order matters, later tests may rely on state from earlier+	[ test_init+	, test_add+	, test_reinject+	, test_unannex+	, test_drop+	, test_get+	, test_move+	, test_copy+	, test_lock+	, test_edit+	, test_fix+	, test_trust+	, test_fsck+	, test_migrate+	, test_unused+	, test_describe+	, test_find+	, test_merge+	, test_status+	, test_version+	, test_sync+	, test_sync_regression+	, test_map+	, test_uninit+	, test_upgrade+	, test_whereis+	, test_hook_remote+	, test_directory_remote+	, test_rsync_remote+	, test_bup_remote+	, test_crypto+	]++test_init :: Test+test_init = "git-annex init" ~: TestCase $ innewrepo $ do+	git_annex "init" [reponame] @? "init failed"+  where+	reponame = "test repo"++test_add :: Test+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+	basic = TestCase $ inmainrepo $ do+		writeFile annexedfile $ content annexedfile+		git_annex "add" [annexedfile] @? "add failed"+		annexed_present annexedfile+		writeFile sha1annexedfile $ content sha1annexedfile+		git_annex "add" [sha1annexedfile, "--backend=SHA1"] @? "add with SHA1 failed"+		annexed_present sha1annexedfile+		checkbackend sha1annexedfile backendSHA1+		writeFile wormannexedfile $ content wormannexedfile+		git_annex "add" [wormannexedfile, "--backend=WORM"] @? "add with WORM failed"+		annexed_present wormannexedfile+		checkbackend wormannexedfile backendWORM+		boolSystem "git" [Params "rm --force -q", File wormannexedfile] @? "git rm failed"+		writeFile ingitfile $ content ingitfile+		boolSystem "git" [Param "add", File ingitfile] @? "git add failed"+		boolSystem "git" [Params "commit -q -a -m commit"] @? "git commit failed"+		git_annex "add" [ingitfile] @? "add ingitfile should be no-op"+		unannexed ingitfile+	sha1dup = TestCase $ intmpclonerepo $ do+		writeFile sha1annexedfiledup $ content sha1annexedfiledup+		git_annex "add" [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" ["dir"] @? "add of subdir failed"+		createDirectory "dir2"+		writeFile "dir2/foo" $ content annexedfile+		changeWorkingDirectory "dir"+		git_annex "add" ["../dir2"] @? "add of ../subdir failed"++test_reinject :: Test+test_reinject = "git-annex reinject/fromkey" ~: TestCase $ intmpclonerepo $ do+	git_annex "drop" ["--force", sha1annexedfile] @? "drop failed"+	writeFile tmp $ content sha1annexedfile+	r <- annexeval $ Types.Backend.getKey backendSHA1 $+		Types.KeySource.KeySource { Types.KeySource.keyFilename = tmp, Types.KeySource.contentLocation = tmp, Types.KeySource.inodeCache = Nothing }+	let key = Types.Key.key2file $ fromJust r+	git_annex "reinject" [tmp, sha1annexedfile] @? "reinject failed"+	git_annex "fromkey" [key, sha1annexedfiledup] @? "fromkey failed"+	annexed_present sha1annexedfiledup+  where+	tmp = "tmpfile"++test_unannex :: Test+test_unannex = "git-annex unannex" ~: TestList [nocopy, withcopy]+  where+	nocopy = "no content" ~: intmpclonerepo $ do+		annexed_notpresent annexedfile+		git_annex "unannex" [annexedfile] @? "unannex failed with no copy"+		annexed_notpresent annexedfile+	withcopy = "with content" ~: intmpclonerepo $ do+		git_annex "get" [annexedfile] @? "get failed"+		annexed_present annexedfile+		git_annex "unannex" [annexedfile, sha1annexedfile] @? "unannex failed"+		unannexed annexedfile+		git_annex "unannex" [annexedfile] @? "unannex failed on non-annexed file"+		unannexed annexedfile+		git_annex "unannex" [ingitfile] @? "unannex ingitfile should be no-op"+		unannexed ingitfile++test_drop :: Test+test_drop = "git-annex drop" ~: TestList [noremote, withremote, untrustedremote]+  where+	noremote = "no remotes" ~: TestCase $ intmpclonerepo $ do+		git_annex "get" [annexedfile] @? "get failed"+		boolSystem "git" [Params "remote rm origin"]+			@? "git remote rm origin failed"+		not <$> git_annex "drop" [annexedfile] @? "drop wrongly succeeded with no known copy of file"+		annexed_present annexedfile+		git_annex "drop" ["--force", annexedfile] @? "drop --force failed"+		annexed_notpresent annexedfile+		git_annex "drop" [annexedfile] @? "drop of dropped file failed"+		git_annex "drop" [ingitfile] @? "drop ingitfile should be no-op"+		unannexed ingitfile+	withremote = "with remote" ~: TestCase $ intmpclonerepo $ do+		git_annex "get" [annexedfile] @? "get failed"+		annexed_present annexedfile+		git_annex "drop" [annexedfile] @? "drop failed though origin has copy"+		annexed_notpresent annexedfile+		inmainrepo $ annexed_present annexedfile+	untrustedremote = "untrusted remote" ~: TestCase $ intmpclonerepo $ do+		git_annex "untrust" ["origin"] @? "untrust of origin failed"+		git_annex "get" [annexedfile] @? "get failed"+		annexed_present annexedfile+		not <$> git_annex "drop" [annexedfile] @? "drop wrongly suceeded with only an untrusted copy of the file"+		annexed_present annexedfile+		inmainrepo $ annexed_present annexedfile++test_get :: Test+test_get = "git-annex get" ~: TestCase $ intmpclonerepo $ do+	inmainrepo $ annexed_present annexedfile+	annexed_notpresent annexedfile+	git_annex "get" [annexedfile] @? "get of file failed"+	inmainrepo $ annexed_present annexedfile+	annexed_present annexedfile+	git_annex "get" [annexedfile] @? "get of file already here failed"+	inmainrepo $ annexed_present annexedfile+	annexed_present annexedfile+	inmainrepo $ unannexed ingitfile+	unannexed ingitfile+	git_annex "get" [ingitfile] @? "get ingitfile should be no-op"+	inmainrepo $ unannexed ingitfile+	unannexed ingitfile++test_move :: Test+test_move = "git-annex move" ~: TestCase $ intmpclonerepo $ do+	annexed_notpresent annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "move" ["--from", "origin", annexedfile] @? "move --from of file failed"+	annexed_present annexedfile+	inmainrepo $ annexed_notpresent annexedfile+	git_annex "move" ["--from", "origin", annexedfile] @? "move --from of file already here failed"+	annexed_present annexedfile+	inmainrepo $ annexed_notpresent annexedfile+	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file failed"+	inmainrepo $ annexed_present annexedfile+	annexed_notpresent annexedfile+	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed"+	inmainrepo $ annexed_present annexedfile+	annexed_notpresent annexedfile+	unannexed ingitfile+	inmainrepo $ unannexed ingitfile+	git_annex "move" ["--to", "origin", ingitfile] @? "move of ingitfile should be no-op"+	unannexed ingitfile+	inmainrepo $ unannexed ingitfile+	git_annex "move" ["--from", "origin", ingitfile] @? "move of ingitfile should be no-op"+	unannexed ingitfile+	inmainrepo $ unannexed ingitfile++test_copy :: Test+test_copy = "git-annex copy" ~: TestCase $ intmpclonerepo $ do+	annexed_notpresent annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "copy" ["--from", "origin", annexedfile] @? "copy --from of file failed"+	annexed_present annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "copy" ["--from", "origin", annexedfile] @? "copy --from of file already here failed"+	annexed_present annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "copy" ["--to", "origin", annexedfile] @? "copy --to of file already there failed"+	annexed_present annexedfile+	inmainrepo $ annexed_present annexedfile+	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed"+	annexed_notpresent annexedfile+	inmainrepo $ annexed_present annexedfile+	unannexed ingitfile+	inmainrepo $ unannexed ingitfile+	git_annex "copy" ["--to", "origin", ingitfile] @? "copy of ingitfile should be no-op"+	unannexed ingitfile+	inmainrepo $ unannexed ingitfile+	git_annex "copy" ["--from", "origin", ingitfile] @? "copy of ingitfile should be no-op"+	checkregularfile ingitfile+	checkcontent ingitfile++test_lock :: Test+test_lock = "git-annex unlock/lock" ~: intmpclonerepo $ do+	-- regression test: unlock of not present file should skip it+	annexed_notpresent annexedfile+	not <$> git_annex "unlock" [annexedfile] @? "unlock failed to fail with not present file"+	annexed_notpresent annexedfile++	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "unlock" [annexedfile] @? "unlock failed"		+	unannexed annexedfile+	-- write different content, to verify that lock+	-- throws it away+	changecontent annexedfile+	writeFile annexedfile $ content annexedfile ++ "foo"+	git_annex "lock" [annexedfile] @? "lock failed"+	annexed_present annexedfile+	git_annex "unlock" [annexedfile] @? "unlock failed"		+	unannexed annexedfile+	changecontent annexedfile+	git_annex "add" [annexedfile] @? "add of modified file failed"+	runchecks [checklink, checkunwritable] annexedfile+	c <- readFile annexedfile+	assertEqual "content of modified file" c (changedcontent annexedfile)+	r' <- git_annex "drop" [annexedfile]+	not r' @? "drop wrongly succeeded with no known copy of modified file"++test_edit :: Test+test_edit = "git-annex edit/commit" ~: TestList [t False, t True]+  where t precommit = TestCase $ intmpclonerepo $ do+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "edit" [annexedfile] @? "edit failed"+	unannexed annexedfile+	changecontent annexedfile+	if precommit+		then do+			-- pre-commit depends on the file being+			-- staged, normally git commit does this+			boolSystem "git" [Param "add", File annexedfile]+				@? "git add of edited file failed"+			git_annex "pre-commit" []+				@? "pre-commit failed"+		else do+			boolSystem "git" [Params "commit -q -a -m contentchanged"]+				@? "git commit of edited file failed"+	runchecks [checklink, checkunwritable] annexedfile+	c <- readFile annexedfile+	assertEqual "content of modified file" c (changedcontent annexedfile)+	not <$> git_annex "drop" [annexedfile] @? "drop wrongly succeeded with no known copy of modified file"++test_fix :: Test+test_fix = "git-annex fix" ~: intmpclonerepo $ do+	annexed_notpresent annexedfile+	git_annex "fix" [annexedfile] @? "fix of not present failed"+	annexed_notpresent annexedfile+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "fix" [annexedfile] @? "fix of present file failed"+	annexed_present annexedfile+	createDirectory subdir+	boolSystem "git" [Param "mv", File annexedfile, File subdir]+		@? "git mv failed"+	git_annex "fix" [newfile] @? "fix of moved file failed"+	runchecks [checklink, checkunwritable] newfile+	c <- readFile newfile+	assertEqual "content of moved file" c (content annexedfile)+  where+	subdir = "s"+	newfile = subdir ++ "/" ++ annexedfile++test_trust :: Test+test_trust = "git-annex trust/untrust/semitrust/dead" ~: intmpclonerepo $ do+	git_annex "trust" [repo] @? "trust failed"+	trustcheck Logs.Trust.Trusted "trusted 1"+	git_annex "trust" [repo] @? "trust of trusted failed"+	trustcheck Logs.Trust.Trusted "trusted 2"+	git_annex "untrust" [repo] @? "untrust failed"+	trustcheck Logs.Trust.UnTrusted "untrusted 1"+	git_annex "untrust" [repo] @? "untrust of untrusted failed"+	trustcheck Logs.Trust.UnTrusted "untrusted 2"+	git_annex "dead" [repo] @? "dead failed"+	trustcheck Logs.Trust.DeadTrusted "deadtrusted 1"+	git_annex "dead" [repo] @? "dead of dead failed"+	trustcheck Logs.Trust.DeadTrusted "deadtrusted 2"+	git_annex "semitrust" [repo] @? "semitrust failed"+	trustcheck Logs.Trust.SemiTrusted "semitrusted 1"+	git_annex "semitrust" [repo] @? "semitrust of semitrusted failed"+	trustcheck Logs.Trust.SemiTrusted "semitrusted 2"+  where+	repo = "origin"+	trustcheck expected msg = do+		present <- annexeval $ do+			l <- Logs.Trust.trustGet expected+			u <- Remote.nameToUUID repo+			return $ u `elem` l+		assertBool msg present++test_fsck :: Test+test_fsck = "git-annex fsck" ~: TestList [basicfsck, barefsck, withlocaluntrusted, withremoteuntrusted]+  where+	basicfsck = TestCase $ intmpclonerepo $ do+		git_annex "fsck" [] @? "fsck failed"+		boolSystem "git" [Params "config annex.numcopies 2"] @? "git config failed"+		fsck_should_fail "numcopies unsatisfied"+		boolSystem "git" [Params "config annex.numcopies 1"] @? "git config failed"+		corrupt annexedfile+		corrupt sha1annexedfile+	barefsck = TestCase $ intmpbareclonerepo $ do+		git_annex "fsck" [] @? "fsck failed"+	withlocaluntrusted = TestCase $ intmpclonerepo $ do+		git_annex "get" [annexedfile] @? "get failed"+		git_annex "untrust" ["origin"] @? "untrust of origin repo failed"+		git_annex "untrust" ["."] @? "untrust of current repo failed"+		fsck_should_fail "content only available in untrusted (current) repository"+		git_annex "trust" ["."] @? "trust of current repo failed"+		git_annex "fsck" [annexedfile] @? "fsck failed on file present in trusted repo"+	withremoteuntrusted = TestCase $ intmpclonerepo $ do+		boolSystem "git" [Params "config annex.numcopies 2"] @? "git config failed"+		git_annex "get" [annexedfile] @? "get failed"+		git_annex "get" [sha1annexedfile] @? "get failed"+		git_annex "fsck" [] @? "fsck failed with numcopies=2 and 2 copies"+		git_annex "untrust" ["origin"] @? "untrust of origin failed"+		fsck_should_fail "content not replicated to enough non-untrusted repositories"++	corrupt f = do+		git_annex "get" [f] @? "get of file failed"+		Utility.FileMode.allowWrite f+		writeFile f (changedcontent f)+		not <$> git_annex "fsck" [] @? "fsck failed to fail with corrupted file content"+		git_annex "fsck" [] @? "fsck unexpectedly failed again; previous one did not fix problem with " ++ f+	fsck_should_fail m = do+		not <$> git_annex "fsck" [] @? "fsck failed to fail with " ++ m++test_migrate :: Test+test_migrate = "git-annex migrate" ~: TestList [t False, t True]+  where t usegitattributes = TestCase $ intmpclonerepo $ do+	annexed_notpresent annexedfile+	annexed_notpresent sha1annexedfile+	git_annex "migrate" [annexedfile] @? "migrate of not present failed"+	git_annex "migrate" [sha1annexedfile] @? "migrate of not present failed"+	git_annex "get" [annexedfile] @? "get of file failed"+	git_annex "get" [sha1annexedfile] @? "get of file failed"+	annexed_present annexedfile+	annexed_present sha1annexedfile+	if usegitattributes+		then do+			writeFile ".gitattributes" $ "* annex.backend=SHA1"+			git_annex "migrate" [sha1annexedfile]+				@? "migrate sha1annexedfile failed"+			git_annex "migrate" [annexedfile]+				@? "migrate annexedfile failed"+		else do+			git_annex "migrate" [sha1annexedfile, "--backend", "SHA1"]+				@? "migrate sha1annexedfile failed"+			git_annex "migrate" [annexedfile, "--backend", "SHA1"]+				@? "migrate annexedfile failed"+	annexed_present annexedfile+	annexed_present sha1annexedfile+	checkbackend annexedfile backendSHA1+	checkbackend sha1annexedfile backendSHA1++	-- check that reversing a migration works+	writeFile ".gitattributes" $ "* annex.backend=SHA256"+	git_annex "migrate" [sha1annexedfile]+		@? "migrate sha1annexedfile failed"+	git_annex "migrate" [annexedfile]+		@? "migrate annexedfile failed"+	annexed_present annexedfile+	annexed_present sha1annexedfile+	checkbackend annexedfile backendSHA256+	checkbackend sha1annexedfile backendSHA256++test_unused :: Test+test_unused = "git-annex unused/dropunused" ~: intmpclonerepo $ do+	-- keys have to be looked up before files are removed+	annexedfilekey <- annexeval $ findkey annexedfile+	sha1annexedfilekey <- annexeval $ findkey sha1annexedfile+	git_annex "get" [annexedfile] @? "get of file failed"+	git_annex "get" [sha1annexedfile] @? "get of file failed"+	checkunused [] "after get"+	boolSystem "git" [Params "rm -q", File annexedfile] @? "git rm failed"+	checkunused [] "after rm"+	boolSystem "git" [Params "commit -q -m foo"] @? "git commit failed"+	checkunused [] "after commit"+	-- unused checks origin/master; once it's gone it is really unused+	boolSystem "git" [Params "remote rm origin"] @? "git remote rm origin failed"+	checkunused [annexedfilekey] "after origin branches are gone"+	boolSystem "git" [Params "rm -q", File sha1annexedfile] @? "git rm failed"+	boolSystem "git" [Params "commit -q -m foo"] @? "git commit failed"+	checkunused [annexedfilekey, sha1annexedfilekey] "after rm sha1annexedfile"++	-- good opportunity to test dropkey also+	git_annex "dropkey" ["--force", Types.Key.key2file annexedfilekey]+		@? "dropkey failed"+	checkunused [sha1annexedfilekey] ("after dropkey --force " ++ Types.Key.key2file annexedfilekey)++	git_annex "dropunused" ["1", "2"] @? "dropunused failed"+	checkunused [] "after dropunused"+	git_annex "dropunused" ["10", "501"] @? "dropunused failed on bogus numbers"++  where+	checkunused expectedkeys desc = do+		git_annex "unused" [] @? "unused failed"+		unusedmap <- annexeval $ Logs.Unused.readUnusedLog ""+		let unusedkeys = M.elems unusedmap+		assertEqual ("unused keys differ " ++ desc)+			(sort expectedkeys) (sort unusedkeys)+	findkey f = do+		r <- Backend.lookupFile f+		return $ fst $ fromJust r++test_describe :: Test+test_describe = "git-annex describe" ~: intmpclonerepo $ do+	git_annex "describe" [".", "this repo"] @? "describe 1 failed"+	git_annex "describe" ["origin", "origin repo"] @? "describe 2 failed"++test_find :: Test+test_find = "git-annex find" ~: intmpclonerepo $ do+	annexed_notpresent annexedfile+	git_annex_expectoutput "find" [] []+	git_annex "get" [annexedfile] @? "get failed"+	annexed_present annexedfile+	annexed_notpresent sha1annexedfile+	git_annex_expectoutput "find" [] [annexedfile]+	git_annex_expectoutput "find" ["--exclude", annexedfile, "--and", "--exclude", sha1annexedfile] []+	git_annex_expectoutput "find" ["--include", annexedfile] [annexedfile]+	git_annex_expectoutput "find" ["--not", "--in", "origin"] []+	git_annex_expectoutput "find" ["--copies", "1", "--and", "--not", "--copies", "2"] [sha1annexedfile]+	git_annex_expectoutput "find" ["--inbackend", "SHA1"] [sha1annexedfile]+	git_annex_expectoutput "find" ["--inbackend", "WORM"] []++	{- --include=* should match files in subdirectories too,+	 - and --exclude=* should exclude them. -}+	createDirectory "dir"+	writeFile "dir/subfile" "subfile"+	git_annex "add" ["dir"] @? "add of subdir failed"+	git_annex_expectoutput "find" ["--include", "*", "--exclude", annexedfile, "--exclude", sha1annexedfile] ["dir/subfile"]+	git_annex_expectoutput "find" ["--exclude", "*"] []++test_merge :: Test+test_merge = "git-annex merge" ~: intmpclonerepo $ do+	git_annex "merge" [] @? "merge failed"++test_status :: Test+test_status = "git-annex status" ~: intmpclonerepo $ do+	json <- git_annex_output "status" ["--json"]+	case Text.JSON.decodeStrict json :: Text.JSON.Result (JSObject JSValue) of+		Ok _ -> return ()+		Error e -> assertFailure e++test_version :: Test+test_version = "git-annex version" ~: intmpclonerepo $ do+	git_annex "version" [] @? "version failed"++test_sync :: Test+test_sync = "git-annex sync" ~: intmpclonerepo $ do+	git_annex "sync" [] @? "sync failed"++{- Regression test for sync merge bug fixed in+ - 0214e0fb175a608a49b812d81b4632c081f63027 -}+test_sync_regression :: Test+test_sync_regression = "git-annex sync_regression" ~:+	{- We need 3 repos to see this bug. -}+	withtmpclonerepo False $ \r1 -> do+		withtmpclonerepo False $ \r2 -> do+			withtmpclonerepo False $ \r3 -> do+				forM_ [r1, r2, r3] $ \r -> indir r $ do+					when (r /= r1) $+						boolSystem "git" [Params "remote add r1", File ("../../" ++ r1)] @? "remote add"+					when (r /= r2) $+						boolSystem "git" [Params "remote add r2", File ("../../" ++ r2)] @? "remote add"+					when (r /= r3) $+						boolSystem "git" [Params "remote add r3", File ("../../" ++ r3)] @? "remote add"+					git_annex "get" [annexedfile] @? "get failed"+					boolSystem "git" [Params "remote rm origin"] @? "remote rm"+				forM_ [r3, r2, r1] $ \r -> indir r $+					git_annex "sync" [] @? "sync failed"+				forM_ [r3, r2] $ \r -> indir r $+					git_annex "drop" ["--force", annexedfile] @? "drop failed"+				indir r1 $ do+					git_annex "sync" [] @? "sync failed in r1"+					git_annex_expectoutput "find" ["--in", "r3"] []+					{- This was the bug. The sync+					 - mangled location log data and it+					 - thought the file was still in r2 -}+					git_annex_expectoutput "find" ["--in", "r2"] []++test_map :: Test+test_map = "git-annex map" ~: intmpclonerepo $ do+	-- set descriptions, that will be looked for in the map+	git_annex "describe" [".", "this repo"] @? "describe 1 failed"+	git_annex "describe" ["origin", "origin repo"] @? "describe 2 failed"+	-- --fast avoids it running graphviz, not a build dependency+	git_annex "map" ["--fast"] @? "map failed"++test_uninit :: Test+test_uninit = "git-annex uninit" ~: intmpclonerepo $ do+	git_annex "get" [] @? "get failed"+	annexed_present annexedfile+	boolSystem "git" [Params "checkout git-annex"] @? "git checkout git-annex"+	not <$> git_annex "uninit" [] @? "uninit failed to fail when git-annex branch was checked out"+	boolSystem "git" [Params "checkout master"] @? "git checkout master"+	_ <- git_annex "uninit" [] -- exit status not checked; does abnormal exit+	checkregularfile annexedfile+	doesDirectoryExist ".git" @? ".git vanished in uninit"+	not <$> doesDirectoryExist ".git/annex" @? ".git/annex still present after uninit"++test_upgrade :: Test+test_upgrade = "git-annex upgrade" ~: intmpclonerepo $ do+	git_annex "upgrade" [] @? "upgrade from same version failed"++test_whereis :: Test+test_whereis = "git-annex whereis" ~: intmpclonerepo $ do+	annexed_notpresent annexedfile+	git_annex "whereis" [annexedfile] @? "whereis on non-present file failed"+	git_annex "untrust" ["origin"] @? "untrust failed"+	not <$> git_annex "whereis" [annexedfile] @? "whereis on non-present file only present in untrusted repo failed to fail"+	git_annex "get" [annexedfile] @? "get failed"+	annexed_present annexedfile+	git_annex "whereis" [annexedfile] @? "whereis on present file failed"++test_hook_remote :: Test+test_hook_remote = "git-annex hook remote" ~: intmpclonerepo $ do+	git_annex "initremote" (words "foo type=hook encryption=none hooktype=foo") @? "initremote failed"+	createDirectory dir+	git_config "annex.foo-store-hook" $+		"cp $ANNEX_FILE " ++ loc+	git_config "annex.foo-retrieve-hook" $+		"cp " ++ loc ++ " $ANNEX_FILE"+	git_config "annex.foo-remove-hook" $+		"rm -f " ++ loc+	git_config "annex.foo-checkpresent-hook" $+		"if [ -e " ++ loc ++ " ]; then echo $ANNEX_KEY; fi"+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to hook remote failed"+	annexed_present annexedfile+	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"+	annexed_notpresent annexedfile+	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from hook remote failed"+	annexed_present annexedfile+	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"+	annexed_present annexedfile+  where+	dir = "dir"+	loc = dir ++ "/$ANNEX_KEY"+	git_config k v = boolSystem "git" [Param "config", Param k, Param v]+		@? "git config failed"++test_directory_remote :: Test+test_directory_remote = "git-annex directory remote" ~: intmpclonerepo $ do+	createDirectory "dir"+	git_annex "initremote" (words $ "foo type=directory encryption=none directory=dir") @? "initremote failed"+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to directory remote failed"+	annexed_present annexedfile+	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"+	annexed_notpresent annexedfile+	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from directory remote failed"+	annexed_present annexedfile+	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"+	annexed_present annexedfile++test_rsync_remote :: Test+test_rsync_remote = "git-annex rsync remote" ~: intmpclonerepo $ do+	createDirectory "dir"+	git_annex "initremote" (words $ "foo type=rsync encryption=none rsyncurl=dir") @? "initremote failed"+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to rsync remote failed"+	annexed_present annexedfile+	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"+	annexed_notpresent annexedfile+	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from rsync remote failed"+	annexed_present annexedfile+	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"+	annexed_present annexedfile++test_bup_remote :: Test+test_bup_remote = "git-annex bup remote" ~: intmpclonerepo $ when Build.SysConfig.bup $ do+	dir <- absPath "dir" -- bup special remote needs an absolute path+	createDirectory dir+	git_annex "initremote" (words $ "foo type=bup encryption=none buprepo="++dir) @? "initremote failed"+	git_annex "get" [annexedfile] @? "get of file failed"+	annexed_present annexedfile+	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to bup remote failed"+	annexed_present annexedfile+	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"+	annexed_notpresent annexedfile+	git_annex "copy" [annexedfile, "--from", "foo"] @? "copy --from bup remote failed"+	annexed_present annexedfile+	not <$> git_annex "move" [annexedfile, "--from", "foo"] @? "move --from bup remote failed to fail"+	annexed_present annexedfile++-- gpg is not a build dependency, so only test when it's available+test_crypto :: Test+test_crypto = "git-annex crypto" ~: intmpclonerepo $ when Build.SysConfig.gpg $ do+	-- force gpg into batch mode for the tests+	setEnv "GPG_BATCH" "1" True+	Utility.Gpg.testTestHarness @? "test harness self-test failed"+	Utility.Gpg.testHarness $ do+		createDirectory "dir"+		let initremote = git_annex "initremote"+			[ "foo"+			, "type=directory"+			, "encryption=" ++ Utility.Gpg.testKeyId+			, "directory=dir"+			]+		initremote @? "initremote failed"+		initremote @? "initremote failed when run twice in a row"+		git_annex "get" [annexedfile] @? "get of file failed"+		annexed_present annexedfile+		git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to encrypted remote failed"+		annexed_present annexedfile+		git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"+		annexed_notpresent annexedfile+		git_annex "move" [annexedfile, "--from", "foo"] @? "move --from encrypted remote failed"+		annexed_present annexedfile+		not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"+		annexed_present annexedfile	++-- This is equivilant to running git-annex, but it's all run in-process+-- so test coverage collection works.+git_annex :: String -> [String] -> IO Bool+git_annex command params = do+	-- catch all errors, including normally fatal errors+	r <- try (run)::IO (Either SomeException ())+	case r of+		Right _ -> return True+		Left _ -> return False+  where+	run = GitAnnex.run (command:"-q":params)++{- Runs git-annex and returns its output. -}+git_annex_output :: String -> [String] -> IO String+git_annex_output command params = do+	got <- Utility.Process.readProcess "git-annex" (command:params)+	-- XXX since the above is a separate process, code coverage stats are+	-- not gathered for things run in it.+	-- Run same command again, to get code coverage.+	_ <- git_annex command params+	return got++git_annex_expectoutput :: String -> [String] -> [String] -> IO ()+git_annex_expectoutput command params expected = do+	got <- lines <$> git_annex_output command params+	got == expected @? ("unexpected value running " ++ command ++ " " ++ show params ++ " -- got: " ++ show got ++ " expected: " ++ show expected)++-- Runs an action in the current annex. Note that shutdown actions+-- are not run; this should only be used for actions that query state.+annexeval :: Types.Annex a -> IO a+annexeval a = do+	s <- Annex.new =<< Git.CurrentRepo.get+	Annex.eval s $ do+		Annex.setOutput Types.Messages.QuietOutput+		a++innewrepo :: Assertion -> Assertion+innewrepo a = withgitrepo $ \r -> indir r a++inmainrepo :: Assertion -> Assertion+inmainrepo a = indir mainrepodir a++intmpclonerepo :: Assertion -> Assertion+intmpclonerepo a = withtmpclonerepo False $ \r -> indir r a++intmpbareclonerepo :: Assertion -> Assertion+intmpbareclonerepo a = withtmpclonerepo True $ \r -> indir r a++withtmpclonerepo :: Bool -> (FilePath -> Assertion) -> Assertion+withtmpclonerepo bare a = do+	dir <- tmprepodir+	bracket (clonerepo mainrepodir dir bare) cleanup a++withgitrepo :: (FilePath -> Assertion) -> Assertion+withgitrepo = bracket (setuprepo mainrepodir) return++indir :: FilePath -> Assertion -> Assertion+indir dir a = do+	cwd <- getCurrentDirectory+	-- Assertion failures throw non-IO errors; catch+	-- any type of error and change back to cwd before+	-- rethrowing.+	r <- bracket_ (changeToTmpDir dir) (changeWorkingDirectory cwd)+		(try (a)::IO (Either SomeException ()))+	case r of+		Right () -> return ()+		Left e -> throw e++setuprepo :: FilePath -> IO FilePath+setuprepo dir = do+	cleanup dir+	ensuretmpdir+	boolSystem "git" [Params "init -q", File dir] @? "git init failed"+	indir dir $ do+		boolSystem "git" [Params "config user.name", Param "Test User"] @? "git config failed"+		boolSystem "git" [Params "config user.email test@example.com"] @? "git config failed"+	return dir++-- clones are always done as local clones; we cannot test ssh clones+clonerepo :: FilePath -> FilePath -> Bool -> IO FilePath+clonerepo old new bare = do+	cleanup new+	ensuretmpdir+	let b = if bare then " --bare" else ""+	boolSystem "git" [Params ("clone -q" ++ b), File old, File new] @? "git clone failed"+	indir new $ git_annex "init" ["-q", new] @? "git annex init failed"+	return new+	+ensuretmpdir :: IO ()+ensuretmpdir = do+	e <- doesDirectoryExist tmpdir+	unless e $+		createDirectory tmpdir++cleanup :: FilePath -> IO ()+cleanup dir = do+	e <- doesDirectoryExist dir+	when e $ do+		-- git-annex prevents annexed file content from being+		-- removed via directory permissions; undo+		recurseDir SystemFS dir >>=+			filterM doesDirectoryExist >>=+			mapM_ Utility.FileMode.allowWrite+		removeDirectoryRecursive dir+	+checklink :: FilePath -> Assertion+checklink f = do+	s <- getSymbolicLinkStatus f+	isSymbolicLink s @? f ++ " is not a symlink"++checkregularfile :: FilePath -> Assertion+checkregularfile f = do+	s <- getSymbolicLinkStatus f+	isRegularFile s @? f ++ " is not a normal file"+	return ()++checkcontent :: FilePath -> Assertion+checkcontent f = do+	c <- readFile f+	assertEqual ("checkcontent " ++ f) c (content f)++checkunwritable :: FilePath -> Assertion+checkunwritable f = do+	-- Look at permissions bits rather than trying to write or using+	-- fileAccess because if run as root, any file can be modified+	-- despite permissions.+	s <- getFileStatus f+	let mode = fileMode s+	if (mode == mode `unionFileModes` ownerWriteMode)+		then assertFailure $ "able to modify annexed file's " ++ f ++ " content"+		else return ()++checkwritable :: FilePath -> Assertion+checkwritable f = do+	r <- tryIO $ writeFile f $ content f+	case r of+		Left _ -> assertFailure $ "unable to modify " ++ f+		Right _ -> return ()++checkdangling :: FilePath -> Assertion+checkdangling f = do+	r <- tryIO $ readFile f+	case r of+		Left _ -> return () -- expected; dangling link+		Right _ -> assertFailure $ f ++ " was not a dangling link as expected"++checklocationlog :: FilePath -> Bool -> Assertion+checklocationlog f expected = do+	thisuuid <- annexeval Annex.UUID.getUUID+	r <- annexeval $ Backend.lookupFile f+	case r of+		Just (k, _) -> do+			uuids <- annexeval $ Remote.keyLocations k+			assertEqual ("bad content in location log for " ++ f ++ " key " ++ (Types.Key.key2file k) ++ " uuid " ++ show thisuuid)+				expected (thisuuid `elem` uuids)+		_ -> assertFailure $ f ++ " failed to look up key"++checkbackend :: FilePath -> Types.Backend -> Assertion+checkbackend file expected = do+	r <- annexeval $ Backend.lookupFile file+	let b = snd $ fromJust r+	assertEqual ("backend for " ++ file) expected b++inlocationlog :: FilePath -> Assertion+inlocationlog f = checklocationlog f True++notinlocationlog :: FilePath -> Assertion+notinlocationlog f = checklocationlog f False++runchecks :: [FilePath -> Assertion] -> FilePath -> Assertion+runchecks [] _ = return ()+runchecks (a:as) f = do+	a f+	runchecks as f++annexed_notpresent :: FilePath -> Assertion+annexed_notpresent = runchecks+	[checklink, checkdangling, notinlocationlog]++annexed_present :: FilePath -> Assertion+annexed_present = runchecks+	[checklink, checkcontent, checkunwritable, inlocationlog]++unannexed :: FilePath -> Assertion+unannexed = runchecks [checkregularfile, checkcontent, checkwritable]++prepare :: IO ()+prepare = do+	whenM (doesDirectoryExist tmpdir) $+		error $ "The temporary directory " ++ tmpdir ++ " already exists; cannot run test suite."++	-- While PATH is mostly avoided, the commit hook does run it,+	-- and so does git_annex_output. Make sure that the just-built+	-- git annex is used.+	cwd <- getCurrentDirectory+	p <- getEnvDefault  "PATH" ""+	setEnv "PATH" (cwd ++ ":" ++ p) True+	setEnv "TOPDIR" cwd True+	-- Avoid git complaining if it cannot determine the user's email+	-- address, or exploding if it doesn't know the user's name.+	setEnv "GIT_AUTHOR_EMAIL" "test@example.com" True+	setEnv "GIT_AUTHOR_NAME" "git-annex test" True+	setEnv "GIT_COMMITTER_EMAIL" "test@example.com" True+	setEnv "GIT_COMMITTER_NAME" "git-annex test" True++changeToTmpDir :: FilePath -> IO ()+changeToTmpDir t = do+	-- Hack alert. Threading state to here was too much bother.+	topdir <- getEnvDefault "TOPDIR" ""+	changeWorkingDirectory $ topdir ++ "/" ++ t++tmpdir :: String+tmpdir = ".t"++mainrepodir :: FilePath+mainrepodir = tmpdir ++ "/repo"++tmprepodir :: IO FilePath+tmprepodir = go (0 :: Int)+  where+	go n = do+		let d = tmpdir ++ "/tmprepo" ++ show n+		ifM (doesDirectoryExist d)+			( go $ n + 1+			, return d+			)++annexedfile :: String+annexedfile = "foo"++wormannexedfile :: String+wormannexedfile = "apple"++sha1annexedfile :: String+sha1annexedfile = "sha1foo"++sha1annexedfiledup :: String+sha1annexedfiledup = "sha1foodup"++ingitfile :: String+ingitfile = "bar"++content :: FilePath -> String		+content f+	| f == annexedfile = "annexed file content"+	| f == ingitfile = "normal file content"+	| f == sha1annexedfile ="sha1 annexed file content"+	| f == sha1annexedfiledup = content sha1annexedfile+	| f == wormannexedfile = "worm annexed file content"+	| otherwise = "unknown file " ++ f++changecontent :: FilePath -> IO ()+changecontent f = writeFile f $ changedcontent f++changedcontent :: FilePath -> String+changedcontent f = (content f) ++ " (modified)"++backendSHA1 :: Types.Backend+backendSHA1 = backend_ "SHA1"++backendSHA256 :: Types.Backend+backendSHA256 = backend_ "SHA256"++backendWORM :: Types.Backend+backendWORM = backend_ "WORM"++backend_ :: String -> Types.Backend+backend_ name = Backend.lookupBackendName name
Upgrade/V1.hs view
@@ -53,14 +53,14 @@ 	ifM (fromRepo Git.repoIsLocalBare) 		( do 			moveContent-			setVersion+			setVersion defaultVersion 		, do 			moveContent 			updateSymlinks 			moveLocationLogs 	 			Annex.Queue.flush-			setVersion+			setVersion defaultVersion 		) 	 	Upgrade.V2.upgrade
Utility/InodeCache.hs view
@@ -13,6 +13,13 @@ data InodeCache = InodeCache FileID FileOffset EpochTime 	deriving (Eq, Show) +{- Weak comparison of the inode caches, comparing the size and mtime, but+ - not the actual inode.  Useful when inodes have changed, perhaps+ - due to some filesystems being remounted. -}+compareWeak :: InodeCache -> InodeCache -> Bool+compareWeak (InodeCache _ size1 mtime1) (InodeCache _ size2 mtime2) =+	size1 == size2 && mtime1 == mtime2+ showInodeCache :: InodeCache -> String showInodeCache (InodeCache inode size mtime) = unwords 	[ show inode@@ -42,9 +49,3 @@ 		(fileSize s) 		(modificationTime s) 	| otherwise = Nothing--{- Compares an inode cache with the current inode of file. -}-compareInodeCache :: FilePath -> Maybe InodeCache -> IO Bool-compareInodeCache file old = do-	curr <- genInodeCache file-	return $ isJust curr && curr == old
Utility/Lsof.hs view
@@ -48,6 +48,7 @@ query :: [String] -> IO [(FilePath, LsofOpenMode, ProcessInfo)] query opts = 	withHandle StdoutHandle (createProcessChecked checkSuccessProcess) p $ \h -> do+		fileEncoding h 		parse <$> hGetContentsStrict h   where 	p = proc "lsof" ("-F0can" : opts)@@ -55,7 +56,7 @@ type LsofParser = String -> [(FilePath, LsofOpenMode, ProcessInfo)]  parse :: LsofParser-#ifdef WITH_ANDROID+#ifdef __ANDROID__ parse = parseDefault #else parse = parseFormatted
Utility/Path.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE PackageImports #-} {- path manipulation  -  - Copyright 2010-2011 Joey Hess <joey@kitenet.net>@@ -8,7 +9,7 @@ module Utility.Path where  import Data.String.Utils-import System.Path+import "MissingH" System.Path import System.FilePath import System.Directory import Data.List
Utility/Process.hs view
@@ -21,6 +21,7 @@ 	createProcessSuccess, 	createProcessChecked, 	createBackgroundProcess,+	processTranscript, 	withHandle, 	withBothHandles, 	withQuietOutput,@@ -40,6 +41,8 @@ import Control.Concurrent import qualified Control.Exception as E import Control.Monad+import Data.Maybe+import System.Posix.IO  import Utility.Misc @@ -116,7 +119,10 @@ 		ExitSuccess -> return () 		ExitFailure n -> fail $ showCmd p ++ " exited " ++ show n -{- Waits for a ProcessHandle and returns True if it exited successfully. -}+{- Waits for a ProcessHandle and returns True if it exited successfully.+ - Note that using this with createProcessChecked will throw away+ - the Bool, and is only useful to ignore the exit code of a process,+ - while still waiting for it. -} checkSuccessProcess :: ProcessHandle -> IO Bool checkSuccessProcess pid = do 	code <- waitForProcess pid@@ -145,6 +151,45 @@  - Note: Zombies will result, and must be waited on. -} createBackgroundProcess :: CreateProcessRunner createBackgroundProcess p a = a =<< createProcess p++{- Runs a process, optionally feeding it some input, and+ - returns a transcript combining its stdout and stderr, and+ - whether it succeeded or failed. -}+processTranscript :: String -> [String] -> (Maybe String) -> IO (String, Bool)+processTranscript cmd opts input = do+	(readf, writef) <- createPipe+	readh <- fdToHandle readf+	writeh <- fdToHandle writef+	p@(_, _, _, pid) <- createProcess $+		(proc cmd opts)+			{ std_in = if isJust input then CreatePipe else Inherit+			, std_out = UseHandle writeh+			, std_err = UseHandle writeh+			}+	hClose writeh++	-- fork off a thread to start consuming the output+	transcript <- hGetContents readh+	outMVar <- newEmptyMVar+	_ <- forkIO $ E.evaluate (length transcript) >> putMVar outMVar ()++	-- now write and flush any input+	case input of+		Just s -> do+			let inh = stdinHandle p+			unless (null s) $ do+				hPutStr inh s+				hFlush inh+			hClose inh+		Nothing -> return ()++	-- wait on the output+	takeMVar outMVar+	hClose readh++	ok <- checkSuccessProcess pid+	return (transcript, ok)+  {- Runs a CreateProcessRunner, on a CreateProcess structure, that  - is adjusted to pipe only from/to a single StdHandle, and passes
Utility/Rsync.hs view
@@ -33,8 +33,6 @@ rsyncServerParams :: [CommandParam] rsyncServerParams = 	[ Param "--server"-	-- preserve permissions-	, Param "-p" 	-- preserve timestamps 	, Param "-t" 	-- allow resuming of transfers of big files
Utility/SRV.hs view
@@ -31,14 +31,12 @@ import ADNS.Resolver import Data.Either #else-#ifndef WITH_HOST #ifdef WITH_DNS import qualified Network.DNS.Lookup as DNS import Network.DNS.Resolver import qualified Data.ByteString.UTF8 as B8 #endif #endif-#endif  newtype SRV = SRV String 	deriving (Show, Eq)@@ -64,9 +62,6 @@ 		resolveSRV resolver srv 	return $ either (\_ -> []) id r #else-#ifdef WITH_HOST-lookupSRV = lookupSRVHost-#else #ifdef WITH_DNS lookupSRV (SRV srv) = do 	seed <- makeResolvSeed defaultResolvConf@@ -81,7 +76,6 @@ 		) #else lookupSRV = lookupSRVHost-#endif #endif #endif 
Utility/Shell.hs view
@@ -10,7 +10,7 @@ module Utility.Shell where  shellPath :: FilePath-#ifndef WITH_ANDROID+#ifndef __ANDROID__ shellPath = "/bin/sh" #else shellPath = "/system/bin/sh"
Utility/ThreadScheduler.hs view
@@ -14,7 +14,7 @@  import Control.Concurrent import System.Posix.Signals-#ifndef WITH_ANDROID+#ifndef __ANDROID__ import System.Posix.Terminal #endif @@ -53,7 +53,7 @@ waitForTermination = do 	lock <- newEmptyMVar 	check softwareTermination lock-#ifndef WITH_ANDROID+#ifndef __ANDROID__ 	whenM (queryTerminal stdInput) $ 		check keyboardSignal lock #endif
Utility/UserInfo.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU GPL version 3 or higher.  -} +{-# LANGUAGE CPP #-}+ module Utility.UserInfo ( 	myHomeDir, 	myUserName,@@ -26,7 +28,11 @@ myUserName = myVal ["USER", "LOGNAME"] userName  myUserGecos :: IO String+#ifdef __ANDROID__+myUserGecos = return "" -- userGecos crashes on Android+#else myUserGecos = myVal [] userGecos+#endif  myVal :: [String] -> (UserEntry -> String) -> IO String myVal envvars extract = maybe (extract <$> getpwent) return =<< check envvars
Utility/Yesod.hs view
@@ -7,6 +7,12 @@  {-# LANGUAGE CPP #-} +#if defined VERSION_yesod_default+#if ! MIN_VERSION_yesod_default(1,1,0)+#define WITH_OLD_YESOD+#endif+#endif+ module Utility.Yesod where  import Yesod.Default.Util
Utility/libdiskfree.c view
@@ -22,7 +22,7 @@ # define STATCALL statfs /* statfs64 not yet tested on a real FreeBSD machine */ # define STATSTRUCT statfs #else-#if defined WITH_ANDROID+#if defined __ANDROID__ # warning free space checking code not available for Android # define UNKNOWN #else
Utility/libmounts.h view
@@ -5,7 +5,7 @@ # include <sys/mount.h> # define GETMNTINFO #else-#if defined WITH_ANDROID+#if defined __ANDROID__ # warning mounts listing code not available for Android # define UNKNOWN #else
debian/changelog view
@@ -1,11 +1,34 @@-git-annex (3.20130217) UNRELEASED; urgency=low+git-annex (4.20130227) unstable; urgency=low +  * annex.version is now set to 4 for direct mode repositories.   * Should now fully support git repositories with core.symlinks=false;     always using git's pseudosymlink files in such repositories.   * webapp: Allow creating repositories on filesystems that lack support for     symlinks.+  * webapp: Can now add a new local repository, and make it sync with+    the main local repository.+  * Android: Bundle now includes openssh.+  * Android: Support ssh connection caching.+  * Android: Assistant is fully working. (But no webapp yet.)+  * Direct mode: Support filesystems like FAT which can change their inodes+    each time they are mounted.+  * Direct mode: Fix support for adding a modified file.+  * Avoid passing -p to rsync, to interoperate with crippled filesystems.+    Closes: #700282+  * Additional GIT_DIR support bugfixes. May actually work now.+  * webapp: Display any error message from git init if it fails to create+    a repository.+  * Fix a reversion in matching globs introduced in the last release,+    where "*" did not match files inside subdirectories. No longer uses+    the Glob library.+  * copy: Update location log when no copy was performed, if the location+    log was out of date.+  * Makefile now builds using cabal, taking advantage of cabal's automatic+    detection of appropriate build flags.+  * test: The test suite is now built into the git-annex binary, and can+    be run at any time. - -- Joey Hess <joeyh@debian.org>  Sun, 17 Feb 2013 16:42:16 -0400+ -- Joey Hess <joeyh@debian.org>  Wed, 27 Feb 2013 14:07:24 -0400  git-annex (3.20130216) unstable; urgency=low 
debian/control view
@@ -4,6 +4,7 @@ Build-Depends:  	debhelper (>= 9), 	ghc (>= 7.4),+	cabal-install, 	libghc-mtl-dev (>= 2.1.1), 	libghc-missingh-dev, 	libghc-hslogger-dev,
debian/rules view
@@ -1,23 +1,8 @@ #!/usr/bin/make -f -ifeq (install ok installed,$(shell dpkg-query -W -f '$${Status}' libghc-yesod-dev 2>/dev/null))-export FEATURES=-DWITH_ASSISTANT -DWITH_S3 -DWITH_HOST -DWITH_PAIRING -DWITH_XMPP -DWITH_WEBAPP -DWITH_OLD_YESOD-else-export FEATURES=-DWITH_ASSISTANT -DWITH_S3 -DWITH_HOST -DWITH_PAIRING -DWITH_XMPP-endif-ifeq (install ok installed,$(shell dpkg-query -W -f '$${Status}' libghc-dav-dev 2>/dev/null))-export FEATURES:=${FEATURES} -DWITH_WEBDAV-endif- %: 	dh $@ -# Builds standalone tarball with the same FEATURES as debian package.-standalone:-	$(MAKE) linuxstandalone- # Not intended for use by anyone except the author. announcedir: 	@echo ${HOME}/src/git-annex/doc/news--.PHONY: standalone
+ doc/assistant/android/appinstalled.png view

binary file changed (absent → 16805 bytes)

+ doc/assistant/android/install.png view

binary file changed (absent → 55106 bytes)

+ doc/assistant/android/terminal.png view

binary file changed (absent → 20565 bytes)

+ doc/assistant/combinerepos.png view

binary file changed (absent → 10677 bytes)

doc/assistant/release_notes.mdwn view
@@ -1,3 +1,15 @@+## version 4.20130227++This release fixes a bug with globbing that broke preferred content expressions.+So, it is a recommended upgrade from the previous release, which introduced+that bug.++In this release, the assistant is fully working on Android, although+it must be set up using the command line.++Repositories can now be placed on filesystems that lack support for symbolic+links; FAT support is complete.+ ## version 3.20130216  This adds a port to Android. Only usable at the command line so far;
doc/assistant/thanks.mdwn view
@@ -218,7 +218,7 @@ McNeill, Christian Schlotter, Ben McQuillan, Anthony, Julian, Martin O, altruism, Eric Solheim, MarkS, ndrwc, Matthew, David Lehn, Matthew Cisneros, Mike Skoglund, Kristy Carey, fmotta, Tom Lowenthal, Branden-Tyree+Tyree, Aaron Whitehouse  ## Also thanks to 
+ doc/bugs/3.20121113_build_error___39__not_in_scope_getAddBoxComR__39__.mdwn view
@@ -0,0 +1,33 @@+What steps will reproduce the problem?++Building from latest source, Cabal update, cabal install --only dependencies, cabal configure, Cabal build++What is the expected output? What do you see instead?++Error message from build++...++Loading package DAV-0.2 ... linking ... done.++Loading object (static) dist/build/git-annex/git-annex-tmp/Utility/libdiskfree.o ... done++Loading object (static) dist/build/git-annex/git-annex-tmp/Utility/libmounts.o ... done++final link ... done+++Assistant/Threads/WebApp.hs:47:1: Not in scope: `getAddBoxComR'++Assistant/Threads/WebApp.hs:47:1: Not in scope: `getEnableWebDAVR'+++What version of git-annex are you using? On what operating system?++Latest version via git from git-annex.branchable.com++Debian Squeeze (6.0.6)++Please provide any additional information below.++> I noticed this earlier and fixed it. [[done]] --[[Joey]]
+ doc/bugs/Could_not_resolve_dependencies.mdwn view
@@ -0,0 +1,40 @@+I'm not able to install git-annex with cabal.++What steps will reproduce the problem?++    bbigras@bbigras-VirtualBox:~$ cabal update+    Downloading the latest package list from hackage.haskell.org+    bbigras@bbigras-VirtualBox:~$ cabal install git-annex --bindir=$HOME/bin+    Resolving dependencies...+    cabal: Could not resolve dependencies:+    trying: git-annex-3.20130207 (user goal)+    trying: git-annex-3.20130207:+webdav+    trying: git-annex-3.20130207:+webapp+    trying: git-annex-3.20130207:+assistant+    trying: yesod-1.1.8.2 (dependency of git-annex-3.20130207:+assistant)+    trying: yesod-auth-1.1.5.2 (dependency of yesod-1.1.8.2)+    trying: authenticate-1.3.2.4 (dependency of yesod-auth-1.1.5.2)+    trying: xml-conduit-1.1.0.1 (dependency of authenticate-1.3.2.4)+    next goal: DAV (dependency of git-annex-3.20130207:+webdav)+    rejecting: DAV-0.3 (conflict: xml-conduit==1.1.0.1, DAV => xml-conduit>=1.0 &&+    <=1.1)+    rejecting: DAV-0.2, 0.1, 0.0.1, 0.0 (conflict: git-annex-3.20130207:webdav =>+    DAV(>=0.3))+    bbigras@bbigras-VirtualBox:~$+++What version of git-annex are you using? On what operating system?++Ubuntu 12.10 x86_64++cabal-install version 0.14.0+using version 1.14.0 of the Cabal library++> The Haskell DAV library needs to be updated to build with+> the newer version of xml-conduit. Library skew of this sort +> is common when using cabal.+> +> You can work around this by building git-annex without webdav:+> `cabal configure --flags=-WebDAV`+> +> This is not a git-annex bug. [[done]] --[[Joey]]
+ doc/bugs/Is_there_any_way_to_rate_limit_uploads_to_an_S3_backend__63__.mdwn view
@@ -0,0 +1,19 @@+What steps will reproduce the problem?++Adding files to a local annex set up to sync to a remote S3 one+++What is the expected output? What do you see instead?++It syncs, but maxes out the uplink+++What version of git-annex are you using? On what operating system?++3.20121112 on Debian testing+++Please provide any additional information below.++The man page lists how to configure rate limiting for rsync, not sure how to do it for this+
+ doc/bugs/Lost_S3_Remote/comment_1_6e80e6db6671581d471fc9a54181c04c._comment view
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 1"+ date="2012-01-06T03:04:35Z"+ content="""+Despite `status` listing S3 support, your git-annex is actually built with S3stub, probably because it failed to find the necessary S3 module at build time. Rebuild git-annex and watch closely, you'll see \"** building without S3 support\". Look above that for the error and fix it.++It was certianly a bug that it showed S3 as supported when built without it. I've fixed that.+"""]]
+ doc/bugs/Lost_S3_Remote/comment_2_c99c65882a3924f4890e500f9492b442._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 2"+ date="2012-01-06T03:08:28Z"+ content="""+BTW, you'll want to \"make clean\", since the S3stub hack symlinks a file into place and it will continue building with S3stub even if you fix the problem until you clean.+"""]]
+ doc/bugs/Lost_S3_Remote/comment_3_1e434d5a20a692cd9dc7f6f8f20f30dd._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkey8WuXUh_x5JC2c9_it1CYRnVTgdGu1M"+ nickname="Dustin"+ subject="Thank you!"+ date="2012-01-06T03:38:27Z"+ content="""+make clean and rebuild worked...  Thank you+"""]]
+ doc/bugs/More_sync__39__ing_weirdness_with_the_assistant_branch_on_OSX.mdwn view
@@ -0,0 +1,15 @@+Running the 'assistant' branch, I occassionally get++To myhost1:/Users/jtang/annex+ ! [rejected]        master -> synced/master (non-fast-forward)+error: failed to push some refs to 'myhost1:/Users/jtang/annex'+hint: Updates were rejected because a pushed branch tip is behind its remote+hint: counterpart. Check out this branch and merge the remote changes+hint: (e.g. 'git pull') before pushing again.+hint: See the 'Note about fast-forwards' in 'git push --help' for details.+(Recording state in git...)++manually running a 'git annex sync' usually fixes it, I guess once the sync command runs periodically this problem will go away, is this even OSX specific? I don't quite get the behaviour that is described in [[design/assistant/blog/day_15__its_aliiive]].++> With my changes today, I've seen it successfully recover from this+> situation. [[done]] --[[Joey]] 
+ doc/bugs/OSX_app_issues/comment_10_54d8f3e429df9a9958370635c890abf0._comment view
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.154.3.194"+ subject="comment 10"+ date="2013-01-19T16:13:20Z"+ content="""+The app uses the version of git included in it, because using the system's installed version if there is one is likely to run into other version incompatabilities. ++You can either install git-annex using cabal and homebrew, as documented, or you could go in and delete+all the git programs out of the app, and then it'd use the system's git stuff instead.+"""]]
+ doc/bugs/OSX_app_issues/comment_11_bb2ceb95a844449795addee6986d0763._comment view
@@ -0,0 +1,26 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlYy4BrJyV1PdfqzevCVziXRp89iUH6Xzw"+ nickname="Christopher"+ subject="Code signing errors in log on starting git-annex.app"+ date="2013-01-19T22:30:32Z"+ content="""+When I run via the App and set up a fresh repo, i get some Console.app spam (looks like one per file added to the repo dir... or maybe one per git command?):++    2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x1008b4000): p=73995[git] clearing CS_VALID+    2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x10f99e000): p=73996[git] clearing CS_VALID+    2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x102b44000): p=73997[git] clearing CS_VALID+    2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x1029f4000): p=73998[git] clearing CS_VALID+    ...++and nothing seems to work. The page address and the pid increment steadily with each line.  I'm using 10.8.2 (12C60) on a Mac Pro, and grabbed:++     /git-annex/OSX/current/10.8.2_Mountain_Lion/git-annex.dmg.bz2	++(published 14-Jan-2013 15:19)++It seems to be a code signing issue, perhaps with the vendored git binaries. While things are sort-of working, the web app shows the files flying by really fast. ++Using a fresh repo via `git annex webapp` works great (I built that after much teeth-knashing, brew install/link cycles, and then cabal install git-annex). ++I am very excited for this to work, this is exactly what I've been waiting for to replace dropbox. Came very close to writing it myself a few times (and in Haskell no less!!). +"""]]
+ doc/bugs/OSX_app_issues/comment_12_f3bc5a4e4895ac9351786f0bdd8005ba._comment view
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmYiJgOvC4IDYkr2KIjMlfVD9r_1Sij_jY"+ nickname="Douglas"+ subject="Error creating remote repository using ssh on OSX"+ date="2013-01-25T13:18:40Z"+ content="""+There is an issue with creating remote repositories using ssh (the problem may require using a different account name.) I filed the following bug:+++<http://git-annex.branchable.com/bugs/Error_creating_remote_repository_using_ssh_on_OSX/>+"""]]
+ doc/bugs/OSX_app_issues/comment_2_fd560811c57df5cbc3976639642b8b19._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkN91jAhoesnVI9TtWANaBPaYjd1V9Pag8"+ nickname="Benjamin"+ subject="Package for older OS X"+ date="2012-11-17T12:36:45Z"+ content="""+Is there an option to provide application bundle for older versions of OS X? The last time I tried the bundle wouldn't work under 10.5. If no specific features from newer OS X versions are required, it could be enough to add a simple switch when building.+"""]]
+ doc/bugs/OSX_app_issues/comment_4_4cda124b57ddc87645d5822f14ed5c59._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkBTVYS5lTecuenAB01eHgfUxE20vWVpU4"+ nickname="Peng"+ subject="Large Mountain Loin package size"+ date="2012-12-28T22:17:43Z"+ content="""+I see that git-annex package file is 489.9MB on Mac Mountain Loin (git-annex.dmg.bz2). The file git-annex.dmg.bz2 is only of size 24M. Is there any way to reduce the package size?+"""]]
+ doc/bugs/OSX_app_issues/comment_5_0d1df34f83a8dac9c438d93806236818._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="2001:4978:f:21a::2"+ subject="comment 5"+ date="2013-01-02T19:52:28Z"+ content="""+The build for today's release is 24 mb.+"""]]
+ doc/bugs/OSX_app_issues/comment_6_bc44d5aea5f77e331a32913ada293730._comment view
@@ -0,0 +1,27 @@+[[!comment format=mdwn+ username="https://www.jsilence.org/"+ nickname="jsilence"+ subject="Setting up a repository fails on OSX 10.6"+ date="2013-01-05T11:17:18Z"+ content="""+I installed Haskell via MacPorts and managed to compile git-annex as described via cabal.++On the initial start, git-annex webapp starts just fine and the webapp opens in the browser. When I try to configure a local repository, the webapp crashes.++    1 jsilence@zeo ~ % git-annex webapp+    (Recording state in git...)+    WebApp crashed: watch mode is not available on this system+    +    Launching web browser on file:///var/folders/6b/6bWnFAnbFXSPCLPvCnKNrE+++TI/-Tmp-/webapp1003.html+    jsilence@zeo ~ % ++\"watch mode is not suported\" suggests that lsof is not in the PATH. lsof resides in /usr/sbin and can be found just fine:++    jsilence@zeo ~ % which lsof+    /usr/sbin/lsof++Any help would be appreciated.++-jsl++"""]]
+ doc/bugs/OSX_app_issues/comment_7_93e0bb53ac2d7daef53426fbdc5f92d9._comment view
@@ -0,0 +1,15 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkurjhi0CRJvgm7QNaZDWS9hitBtavqIpc"+ nickname="Bret"+ subject="git-annex.app Not working on 32 bit machines"+ date="2012-11-03T19:18:47Z"+ content="""+I tried running the git-annex.app on my Core Duo Macbook pro, and it does not run at all.  I get an error on my system.log++`Nov  3 12:13:26 Bret-Mac [0x0-0x15015].com.branchable.git-annex[155]: /Applications/git-annex.app/Contents/MacOS/runshell: line 52: /Applications/git-annex.app/Contents/MacOS/bin/git-annex: Bad CPU type in executable+Nov  3 12:13:26 Bret-Mac com.apple.launchd.peruser.501[92] ([0x0-0x15015].com.branchable.git-annex[155]): Exited with exit code: 1`++It works on my 64 bit machine, and this has become quite the problem for a while now, where people with newer macs dont compile back for a 32bit machine.  ++Is there any hope for a pre-compiled binary that works on a 32 bit machine?+"""]]
+ doc/bugs/OSX_app_issues/comment_7_acd73cc5c4caa88099e2d2f19947aadf._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.152.108.211"+ subject="comment 7"+ date="2013-01-05T17:48:52Z"+ content="""+@jsilence, this problem does not involve lsof. There was a typo in the cabal file that prevented cabal building it with hfsevents. I'm releasing a new version to cabal with this typo fixed.+"""]]
+ doc/bugs/OSX_app_issues/comment_8_141eac2f3fb25fe18b4268786f00ad6a._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkSq2FDpK2n66QRUxtqqdbyDuwgbQmUWus"+ nickname="Jimmy"+ subject="comment 8"+ date="2012-11-07T16:08:00Z"+ content="""+I've been updating my haskell platform install recently, i used to try and get the builder to spit out 32/64bit binaries, but recently it's just become too messy, I've just migrated to a full 64bit build system. I'm afraid I won't be able to  provide 32bit builds any more.+"""]]
+ doc/bugs/OSX_app_issues/comment_8_f4d5b2645d7f29b80925159efb94a998._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmOsimKUgz6rxpmsS_nrBQGavEYyUpDlsE"+ nickname="Tim"+ subject="OS X 10.8.2"+ date="2013-01-11T00:07:54Z"+ content="""+Double click on the app, give permission for it to run and ... nothing+"""]]
+ doc/bugs/OSX_app_issues/comment_9_2e6dfca0fd8df04066769653724eae28._comment view
@@ -0,0 +1,17 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmRFKwny4rArBaz-36xTcsJYqKIgdDaw5Q"+ nickname="Andrew"+ subject="Prefer the system/path git binaries if they're a newer version"+ date="2013-01-19T06:20:38Z"+ content="""+I have used homebrew to install git v1.8.0.2 but git-annex.app packages git v1.7.10.2. git 1.7 crashes due to some newer directives in my global git config.++    error: Malformed value for push.default: simple+    error: Must be one of nothing, matching, tracking or current.+    fatal: bad config file line 38 in /Users/akraut/.gitconfig+    +    git-annex: fd:13: hGetLine: end of file+    failed+    git-annex: webapp: 1 failed++"""]]
+ doc/bugs/Switching_from_indirect_mode_to_direct_mode_breaks_duplicates.mdwn view
@@ -0,0 +1,30 @@+#What steps will reproduce the problem?++1. Create a new repository in indirect mode.++2. Add the same file twice under a different name. Now you have two symlinks pointing to the same file under .git/annex/objects/++3. Switch to direct mode. The first symlink gets replaced by the actual file. The second stays unchanged, pointing to nowhere. But git annex whereis still reports it has a copy.++4. Delete the first file. Git annex whereis still thinks it has a copy of file 2, which is not true -> data loss.++#What is the expected output? What do you see instead?++When switching to direct mode, both symlinks should be replaced by a copy (or at least a hardlink) of the actual file.++> The typo that caused this bug is fixed. --[[Joey]] ++#What version of git-annex are you using? On what operating system?++3.20130107 on Arch Linux x64++#Please provide any additional information below.++The deduplication performed by git-annex is very dangerous in itself+because files with identical content become replaced by references to the+same file without the user necessarily being aware. Think of the user+making a copy of a file, than modifying it. He would expect to end up with+two files, the unchanged original and the modified copy. But what he really+gets is two symlinks pointing to the same modified file.++> I agree, it now copies rather than hard linking.  [[done]] --[[Joey]] 
+ doc/bugs/added_branches_makes___39__git_annex_unused__39___slow.mdwn view
@@ -0,0 +1,81 @@+Creating additional branches in history seems to slow down the 'git annex unused' command quadratically, even if the location of the branches should be irrelevant as far as unused data goes.++This was tested on:++	$ git annex version+	git-annex version: 3.20130216+	local repository version: 3+	default repository version: 3+	supported repository versions: 3+	upgrade supported from repository versions: 0 1 2++What steps will reproduce the problem?++	$ mkdir a+	$ cd a+	$ git init+	$ git annex init+	$ i=0 ; while test $i -lt 1000; do dd if=/dev/urandom of=$i.img bs=1M count=1; i=$(($i+1)); done+	$ git annex add .+	$ git commit -m"foo"+	$ git rm 1*+	$ git commit -m"bar"+	$ git log --oneline --decorate+	ffcca3a (HEAD, master) bar+	3e7793d foo+	$ time -p git annex unused+	unused . (checking for unused data...) (checking master...)+	(...)+	real 0.76+	user 0.40+	sys 0.06+	git commit --allow-empty -m"baz"+	$ git log --oneline --decorate+	4390c32 (HEAD, master) baz+	ffcca3a bar+	3e7793d foo+	$ time -p git annex unused+	unused . (checking for unused data...) (checking master...)+	(...)+	real 0.75+	user 0.38+	sys 0.07+	$ git branch boo HEAD^+	$ time -p git annex unused+	unused . (checking for unused data...) (checking boo...) (checking master...)+	(...)+	real 1.29+	user 0.62+	sys 0.08+	arand@mas:~/tmp/more/a(master)$ git branch beeboo HEAD^+	4390c32 (HEAD, master) baz+	ffcca3a (boo, beeboo) bar+	3e7793d foo+	arand@mas:~/tmp/more/a(master)$ time -p git annex unused+	unused . (checking for unused data...) (checking beeboo...) (checking master...)+	(...)+	real 2.50+	user 1.12+	sys 0.14+	$ git branch -d boo beeboo+	$ git log --oneline --decorate+	4390c32 (HEAD, master) baz+	ffcca3a bar+	3e7793d foo+	$ time -p git annex unused+	unused . (checking for unused data...) (checking master...)+	(...)+	real 0.77+	user 0.42+	sys 0.04++What is the expected output? What do you see instead?++I would expect the time to be the same in all the above cases.++What version of git-annex are you using? On what operating system?++	$ git annex version+	git-annex version: 3.20130216++On current Debian sid/experimental
+ doc/bugs/git-annex_3.20130216.1_tests_are_broken.mdwn view
@@ -0,0 +1,43 @@+    $ pwd+    [bla]/git-annex-3.20130216.1+    $ runhaskell Setup configure --prefix=/usr --libdir=/usr/lib64 --docdir=/usr/share/doc/git-annex-3.20130216.1-r2 \+    --htmldir=/usr/share/doc/git-annex-3.20130216.1-r2/html --with-compiler=ghc-7.6.2 --enable-shared \+    --disable-executable-stripping --global --verbose --enable-tests --flags=S3 --flags=-WebDAV --flags=-Inotify \+    --flags=Dbus --flags=-Assistant --flags=-Webapp --flags=-Pairing --flags=-XMPP --flags=-DNS+    $ runhaskell Setup.hs build+    Building git-annex-3.20130217...+    Preprocessing test suite 'test' for git-annex-3.20130217...+    +    Annex/UUID.hs:30:8:+        Could not find module `System.Random'+        It is a member of the hidden package `random-1.0.1.1'.+        Perhaps you need to add `random' to the build-depends in your .cabal file.+        Use -v to see a list of the files searched for.++Adding `random` to the dependencies of the test suite results in:++    $ runhaskell Setup.hs build+    Building git-annex-3.20130217...+    Preprocessing test suite 'test' for git-annex-3.20130217...+    +    Annex/UUID.hs:29:18:+        Could not find module `Data.UUID'+        It is a member of the hidden package `uuid-1.2.9'.+        Perhaps you need to add `uuid' to the build-depends in your .cabal file.+        Use -v to see a list of the files searched for.++Adding `uuid` results in:++    $ runhaskell Setup.hs build+    Building git-annex-3.20130217...+    Preprocessing test suite 'test' for git-annex-3.20130217...+    +    Command/Add.hs:25:8:+        Could not find module `Utility.Touch'+        Use -v to see a list of the files searched for.+++Also: you included ".git-annex.cabal.swp" in the tarball.++> These problems in the cabal file were fixed the other day. [[done]]+> --[[Joey]]
+ doc/bugs/git-annex_has_issues_with_git_when_staging__47__commiting_logs.mdwn view
@@ -0,0 +1,34 @@+After a series of pretty convoluted copying files around between annex'd repos and pulling changes around between repos. I noticed that occassionally when git-annex tries to stage files (the `.git-annex/*/*/*logs`) git some times gets wedged and doing a "git commit -a" doesn't seem to work or files might not get added thus leaving a bunch of untracked files or modified files that aren't staged for a commit.++I tried running a *`git rm --cached -f -r *`* then *git add -u .git-annex/* or the usual *git add* then a commit fixes things for me. If I don't do that then my subsequent merges/pulls will fail and result in *no known copies of files* I suspect git-annex might have just touched some file modes and git picked up the changes but got confused since there was no content change. It might also just be a git on OSX thing and it doesn't affect linux/bsd users.++For now it's just a bit of extra work for me when it does occur but it does not seem to occur often.++> What do you mean when you say that git "got wedged"? It hung somehow?+>+> If git-annex runs concurrently with another git command that locks+> the repository, its git add of log files can fail.+> +> Update: Also, of course, if you are running a "got annex get" or+> similar, and ctrl-c it after it has gotten some files, it can+> end up with unstaged or in some cases un-added log files that git-annex+> wrote -- since git-annex only stages log files in git on shutdown, and+> ctrl-c bypasses that.+> --[[Joey]] ++>> It "got wedged" as in git doesn't let me commit anything, even though it tells me that there is stuff to be committed in the staging area.++>>> I've never seen git refuse to commit staged files. There would have to+>>> be some error message? --[[Joey]] ++>>>> there were no error messages at all++>>>>> Can I see a transcript? I'm having difficulty getting my head around+>>>>> what git is doing. Sounds like the files could just not be `git+>>>>> added` yet, but I get the impression from other things that you say+>>>>> that it's not so simple. --[[Joey]] ++This turns out to be a bug in git, and I have posted a bug report on the mailing list.+The git-annex behavior that causes this situation is being handled as+another bug, [[git-annex directory hashing problems on osx]].+So, closing this bug report. [[done]] --[[Joey]]
+ doc/bugs/git-annex_on_crippled_filesystem_can_still_failed_due_to_case_.mdwn view
@@ -0,0 +1,32 @@+What steps will reproduce the problem?++    $ git clone ~/corbeau/travail/ travail+    Cloning into 'travail'...+    done.+    Checking out files: 100% (8670/8670), done.+    $ cd travail+    $ git annex init "portable USB drive"+    init portable USB drive +      Detected a crippled filesystem.++      Enabling direct mode.++    git-annex: /media/LACIE/travail/.git/annex/objects/k1: createDirectory: already exists (File exists)+    failed+    git-annex: init: 1 failed++What version of git-annex are you using? On what operating system?+    $ apt-cache policy git-annex+    git-annex:+    Installé : 3.20130216++This on a amd64 debian sid recently updated+++Please provide any additional information below.++The problem is that git annex already created a /media/LACIE/travail/.git/annex/objects/K1 file (same name in uppercase) and FAT isn't realy case sensitive.+++> I *think* I've found the place that used createDirectory+> rather than createDirectoryIfMissing and fixed it. [[done]] --[[Joey]]
+ doc/bugs/git_annex_gets_confused_about_remotes_with_dots_in_their_names.mdwn view
@@ -0,0 +1,34 @@+For test.com//test, I get this:++    % git annex copy . --to test.com//test+    (getting UUID for test...) git-annex: there is no git remote named "test.com//test"++And my .git/config changes from++    [remote "test.com//test"]+    	url = richih@test.com:/test+    	fetch = +refs/heads/*:refs/remotes/test.com//test/*++to++    [remote "test.com//test"]+    	url = richih@test.com:/test+    	fetch = +refs/heads/*:refs/remotes/test.com//test/*+    	annex-uuid = xyz+    [remote "test"]+    	annex-uuid = xyz+++Unless I am misunderstanding something, git annex gets confused about what the name of the remote it supposed to be, truncates at the dot for some operations and uses the full name for others.++> I've fixed this bug. [[done]]+> +> However, using "/" in a remote name seems likely to me to confuse +> git's own remote branch handling. Although I've never tried it.+> --[[Joey]] ++>> From what I can see, git handles / just fine, but would get upset about : which is why it's not allowed in a remote's name.+>> My naming scheme is host//path/to/annex. It sorts nicely and gives all important information left to right with the most specific parts at the beginning and end.+>> If you have any other ideas or scheme, I am all ears :)+>> Either way, thanks for fixing this so quickly.+>> -- RichiH
+ doc/bugs/git_annex_won__39__t_copy_files_to_my_usb_drive.mdwn view
@@ -0,0 +1,60 @@+One of my remotes, on a USB drive, is behaving exceedingly strangely.  Files sometimes refuse to copy to it - whether I copy to it from my home annex, or whether I "cd" to that USB drive and try to "get" files to it.++Note that the external HD is a FAT32 filesystem.  This has never caused problems in the past, but I am wondering if some of the recent work on "crippled" filesystems might have caused breakage on existing repositories which had been working well on FAT32 filesystems?++What steps will reproduce the problem?++On my annex, something like this:++<pre>+Talislanta Books$ git annex whereis talislanta_fantasy_roleplaying.pdf+whereis talislanta_fantasy_roleplaying.pdf (2 copies) +  	d16d0d1a-3cdd-11e2-9161-67c83599f720 -- homeworld+   	fa2bd02e-3ce2-11e2-a675-47389975a32e -- here (macbook)+ok+Talislanta Books$ git annex copy --to=toshiba talislanta_fantasy_roleplaying.pdf+copy talislanta_fantasy_roleplaying.pdf ok+Talislanta Books$ git annex whereis talislanta_fantasy_roleplaying.pdf+whereis talislanta_fantasy_roleplaying.pdf (2 copies) +  	d16d0d1a-3cdd-11e2-9161-67c83599f720 -- homeworld+   	fa2bd02e-3ce2-11e2-a675-47389975a32e -- here (macbook)+ok+Talislanta Books$ cd /Volumes/TOSHIBAEXT/annex/Books/archive/Talislanta\ Books/+Talislanta Books$ git annex whereis talislanta_fantasy_roleplaying.pdf+whereis talislanta_fantasy_roleplaying.pdf (2 copies) +  	d16d0d1a-3cdd-11e2-9161-67c83599f720 -- homeworld+   	fa2bd02e-3ce2-11e2-a675-47389975a32e -- macbook+ok+Talislanta Books$ git annex get talislanta_fantasy_roleplaying.pdf+Talislanta Books$ git annex whereis talislanta_fantasy_roleplaying.pdf+whereis talislanta_fantasy_roleplaying.pdf (2 copies) +  	d16d0d1a-3cdd-11e2-9161-67c83599f720 -- homeworld+   	fa2bd02e-3ce2-11e2-a675-47389975a32e -- macbook+ok+Talislanta Books$+</pre>+++What is the expected output? What do you see instead?++I should be able to copy files to my external hard drive, /Volumes/TOSHIBAEXT/annex+++What version of git-annex are you using? On what operating system?++<pre>+Talislanta Books$ git annex version+git-annex version: 3.20130216+local repository version: 3+default repository version: 3+supported repository versions: 3+upgrade supported from repository versions: 0 1 2+</pre>++OS X 10.6 (lion)++Please provide any additional information below.++Most files are affected by this, a few are not.  I don't see any pattern to which is which.++> Both bugs reported here are now [[done]]. --[[Joey]]
+ doc/bugs/git_defunct_processes___40__child_of_git-annex_assistant__41__.mdwn view
@@ -0,0 +1,34 @@+What steps will reproduce the problem?++run git annex assistant, add a file, which is picked up and pushed by the assistant.  ++What is the expected output? What do you see instead?++a ps -ef shows a large number of defunct git processes.. for example:+<pre>+nelg      9622     1  0 02:01 ?        00:00:01 git-annex assistant+nelg      9637  9622  0 02:01 ?        00:00:00 git --git-dir=/home/nelg/Downloads/test2/.git --work-tree=/home/nelg/Downloads/test2 cat-file --batch+nelg     12080  9622  0 02:19 ?        00:00:00 [git] &lt;defunct&gt;+nelg     12082  9622  0 02:19 ?        00:00:00 [git] &lt;defunct&gt;+nelg     12083  9622  0 02:19 ?        00:00:00 [git] &lt;defunct&gt;+nelg     12084  9622  0 02:19 ?        00:00:00 [git] &lt;defunct&gt;+-----+</pre>++What version of git-annex are you using? On what operating system?++Compiled git annex from git (cbcd208d158f8e42dda03a5eeaf1bac21045a140), on Mandriva 2010.2, 32 bit, using ghc-7.4.1.+ git version 1.7.1+++Please provide any additional information below.++I also found that the version of git I have does not support the option: --allow-empty-message+So, suggest that if the version of git installed is an older version, that the params in  Assistant/Threads/Committer.hs+are changed to  [ Param "-m", Param "git assistant".... or something like that.++I have done this on my copy for testing it.++For testing, I am also using two repositories on the same computer.  I set this up from the command line, as the web app does not seem to support syncing to two different git folders on the same computer.++> [[done]]; all zombies are squelched now in the assistant. --[[Joey]]
+ doc/bugs/wishlist:_more_descriptive_commit_messages_in_git-annex_branch.mdwn view
@@ -0,0 +1,39 @@+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]] ++>> Closing as this is literally impossible to do without making+>> git-annex worse. [[done]] --[[Joey]] 
+ doc/bugs/wishlist:_option_to_print_more_info_with___39__unused__39__.mdwn view
@@ -0,0 +1,37 @@+It would be nice if the 'unused' command could optionally display info about the actual files behind its cryptic keys.++I created a (very rough) bash script that simply splices in some info from git log -S'KEY' --numstat into the unused list, like so:++    arand@mas:~/annex(master)$ bash ~/utv/scripts/annex-vunused +    unused . (checking for unused data...) (checking master...) (checking synced/master...) (checking origin/HEAD...) (checking seagate/master...)+    Some annexed data is no longer used by any files:+    NUMBER  KEY+    1       SHA256E-s1073741824--49bc20df15e412a64472421e13fe86ff1c5165e18b2afccf160d4dc19fe68a14.img+                    8f479a4 Sat Feb 23 16:14:12 2013 +0100 remove bigfile+                    0       1       dummy_bigfile.img+                    2988d18 Sat Feb 23 16:13:48 2013 +0100 dummy file+                    1       0       dummy_bigfile.img+    (To see where data was previously used, try: git log --stat -S'KEY')To remove unwanted data: git-annex dropunused NUMBER+    ok+The script:++    #!/bin/bash+    +    pipe="$(mktemp -u)"+    mkfifo "$pipe"+    +    git annex unused  >"$pipe" || exit 1 &+    +    while read -r line+    do+    	key="$(echo "$line" | sed 's/^[^-]*-\([^-]*\)-.*/\1/')"+    	echo -n "$line"+    	test -n "$key" && \+    		echo && \+    		git log --format="%h %cd %s" --numstat -S"$key" | \+    			sed '/^$/d;/git-annex automatic sync/,/^ /d;s/^/\t\t/'+    +    done < "$pipe"+    rm "$pipe"++It would be nice if something like this was available as an option, since it's good way to get a quick overview of what the content is, and if it's safe to drop it.
doc/design/assistant.mdwn view
@@ -13,10 +13,10 @@ * Month 6 "9k bonus round": [[!traillink desymlink]] * Month 7: user-driven features and polishing;    [presentation at LCA2013](http://mirror.linux.org.au/linux.conf.au/2013/mp4/gitannex.mp4)+* Month 8: [[!traillink Android]]  We are, approximately, here: -* Month 8: [[!traillink Android]] * Months 9-11: more user-driven features and polishing (see remaining TODO items in all pages above) * Month 12: "Windows purgatory" [[Windows]] 
+ doc/design/assistant/OSX/comment_1_9290f6e6f265e906b08631224392b7bf._comment view
@@ -0,0 +1,14 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlu-fdXIt_RF9ggvg4zP0yBbtjWQwHAMS4"+ nickname="Jörn"+ subject="Mount detection"+ date="2012-09-21T09:23:34Z"+ content="""+regarding the current mount polling on OSX: why not use the NSNotificationCenter for being notified on mount events on OSX?++Details see:++1. <http://stackoverflow.com/questions/12409458/detect-when-a-volume-is-mounted-on-os-x>+2. <http://stackoverflow.com/questions/6062299/how-to-add-an-observer-to-nsnotificationcenter-in-a-c-class-using-objective-c>+3. <https://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFNotificationCenterRef/Reference/reference.html#//apple_ref/doc/uid/20001438>+"""]]
doc/design/assistant/android.mdwn view
@@ -2,9 +2,10 @@  1. Get git-annex working at the command line in Android,    along with all the programs it needs, and the assistant. **done**-2. Get the webapp working. Needs Template Haskell, or a workaround.-3. A hopefully small Java app will be developed, which runs the-   webapp daemon, and a web browser to display it.+2. Deal with crippled filesystem; no symlinks; etc. **done**+3. Get an easy to install Android app built. **done**+4. Get the webapp working. Needs Template Haskell, or +   switching to <http://www.yesodweb.com/blog/2012/10/yesod-pure>  ### Android specific features @@ -14,9 +15,21 @@ The app should be aware of network status, and avoid expensive data transfers when not on wifi. This may need to be configurable. -### FAT+## TODO -Due to use of the FAT filesystem, which doesn't do symlinks, [[desymlink]]-is probably needed for at least older Android devices that have SD cards.-Additionally, cripped filesystem mode is needed, to avoid hard links,-file modes, etc.+* webapp+* autostart any configured assistants. Best on boot, but may need to only+  do it when app is opened for the first time.+* Don't make app initially open terminal, but go to a page that+  allows opening the webapp or terminal.+* I have seen an assistant thread crash with an interrupted system call+  when the device went to sleep while it was running. Auto-detect and deal with+  that somehow.+* Make git stop complaining that "warning: no threads uspport, ignoring --threads"+* git does not support http remotes. To fix, need to port libcurl and+  allow git to link to it.+* getEnvironment is broken on Android <https://github.com/neurocyte/ghc-android/issues/7>+  and a few places use it.+* Enable WebDAV support. Currently needs template haskell (could be avoided+  by changing the DAV library to not use it), and also networking support,+  which seems broken in current ghc-android.
+ doc/design/assistant/blog/day_192_193__more_porting.mdwn view
@@ -0,0 +1,44 @@+Felt spread thin yesterday, as I was working on multiple things+concurrently & bouncing around as compiles finished. Been working to get+openssh to build for Android, which is quite a pain, starting with getting+openssl to build and then dealing with the Cyanogenmod patches, some of+which are necessary to build on Android and some of which break builds+outside Cyanogenmod. At the same time was testing git-annex on Android.+Found and fixed several more portability bugs while doing that. And on the+back burner I was making some changes to the webapp..++(Forgot to commit my blog post yesterday too..)++Today, that all came together.++* When adding another local repository in the webapp, +  it now allows you to choose whether it should be combined with+  your current repository, or kept separate. Several people had requested+  a way to add local clones with the webapp, for various reasons, like+  wanting a backup repository, or wanting to make a repository on a NFS+  server, and this allows doing that.++[[!img /assistant/combinerepos.png]]++* More porting fun. FAT filesystems and other things used on Android can+  get all new inode numbers each time mounted. Made git-annex use a+  sentinal file to detect when this has happened, since in direct mode+  it compares inodes. (As a bonus this also makes copying direct mode+  repositories between filesystems work.)++* Got openssh building for Android. Changed it to use $HOME/.ssh rather+  than trusting pwent.++* Got git-annex's ssh connection caching working on Android. That needs+  a place where it can create a socket. When the+  repository is on a crippled filesystem, it instead puts the socket+  in a temporary directory set up on the filesystem where the git-annex+  program resides.++With ssh connection caching, transferring multiple files off my Android+tablet *screams*! I was seeing 6.5 megabytes transferred per second,+sustained over a whole month's worth of photos.++Next problem: `git annex assistant` on Android is for some reason crashing+with a segfault on startup. Especially odd since `git annex watch` works.+I'm so close to snap-photo-and-it-syncs-nirvana, but still so far away...
+ doc/design/assistant/blog/day_194__nice_moment.mdwn view
@@ -0,0 +1,37 @@+<video controls src="http://downloads.kitenet.net/videos/git-annex-android.ogv" width="100%"></video>+<a href="http://downloads.kitenet.net/videos/git-annex-android.ogv">video</a>++Today's work:++* Fixed `git annex add` of a modified file in direct mode.+* Fixed bugs in the inode sentinal file code added yesterday.+* With some help from Kevin Boone, I now understand how KBOX works and+  how to use similar techniques to build my own standalone Android app+  that includes git-annex.++  Kevin is using a cute hack; he ships a tarball and some other stuff+  as (pseudo-)library files (`libfoo.so`), which are the only files+  the Android package manager deigns to install. Then the app runs one+  of these, which installs the programs.++  This avoids needing to write Java code that extracts the programs from+  one of its assets and writes it to an executable file, which is the+  canonical way to do this sort of thing. But I noticed it has a benefit too+  (which KBOX does not yet exploit). Since the pseudo-library file is installed+  with the X bit set, if it's really a program, such as busybox or git-annex,+  that program can be run without needing to copy it to an executable file.+  This can save a lot of disk space. So, I'm planning to include all+  the binaries needed by git-annex as these pseudo-libraries.+* Got the Android Terminal Emulator to build. I will be basing my first+  git-annex Android app on this, since a terminal is needed until there's +  a webapp.+* Wasted several hours fighting with `Android.mk` files to include+  my pseudo shared library. This abuse of Makefiles by the NDK is what CDBS+  wants to grow up to be.. or is it the other way around? Anyway, it+  sucks horribly, and I finally found a way to do it without+  modifying the file at all. Ugh.+* At this point, I can build a `git-annex.apk` file containing a+  `libgit-annex.so`, and a `libbusybox.so`, that can both be directly+  run. The plan from here is to give git-annex the ability to+  auto-install itself, and the other pseudo-libraries, when it's run as+  `libgit-annex.so`.
+ doc/design/assistant/blog/day_195__real_android_app.mdwn view
@@ -0,0 +1,32 @@+Well, it's built. [Real Android app for git-annex](http://downloads.kitenet.net/git-annex/android/current/).++[[!img /assistant/android/appinstalled.png]]++When installed, this will open a terminal in which you have access to+git-annex and all the git commands and busybox commands as well. No webapp+yet, but command line users should feel right at home.++[[!img /assistant/android/terminal.png]]++Please test it out, at least as far as installing it, opening the terminal,+and checking that you can run `git annex`; I've only been able to test on+one Android device so far. I'm especially keen to know if it works with+newer versions of Android than 4.0.3. (I know it only supports arm based+Android, no x86 etc.) Please comment if you tried it.++----++Building this went mostly as planned, although I had about 12 builds of+the app in the middle which crashed on startup with no error message ora+logs. Still, it took only one day to put it all together,+ and I even had time to gimp up a quick icon. (Better icons welcome.)++Kevin thinks that my space-saving hack won't work on all Androiden, and he+may be right. If the `lib` directory is on a different filesystem on some+devices, it will fail. But I used it for now anyhow. Thanks to the hack,+the 7.8 mb compressed .apk file installs to use around 23 mb of disk space.++----++Tomorrow: Why does `git-annex assistant` on Android re-add all existing+files on startup?
+ doc/design/assistant/blog/day_196__android_bugfixes.mdwn view
@@ -0,0 +1,26 @@+So it seems the Android app works pretty well on a variety of systems.+Only report of 100% failure so far is on Cyanogenmod 7.2 (Android 2.3.7).++Worked today on some of the obvious bugs.++* Turns out that getEnvironment is broken on Android, returning no+  environment, which explains the weird git behavior where it complains+  that it cannot determine the username and email (because it sees no USER+  or HOST), and suggests setting them in the global git config (which it+  ignores, because it sees no HOME). Put in a work around for this+  that makes `git annex init` more pleasant, and opened a bug report on+  ghc-android.+* Made the Android app detect when it's been upgraded, and re-link all+  the commands, etc.+* Fixed the bug that made `git-annex assistant` on Android re-add all+  existing files on startup.+* Enabled a few useful things in busybox. Including vi.+* Replaced the service notification icon with one with the git-annex logo.+* Made the terminal not close immediately when the shell exits, which+  should aid in debugging of certain types of crashes.++I want to set up an autobuilder for Android, but to do that I need to+install all the haskell libraries on my server. Since getting them built+for Android involved several days of hacking the first time, this will+be an opportunity to make sure I can replicate that. Hopefully in less time.+;)
+ doc/design/assistant/blog/day_197__template_haskell.mdwn view
@@ -0,0 +1,36 @@+Set up an autobuilder for the linux standalone binaries.+Did not get an Android autobuilder set up yet, but I did update+the Android app with recent improvements, so [[upgrade|install/Android]].++----++Investigated further down paths to getting the webapp built for Android.++* Since recent ghc versions support ghci and thus template haskell on arm,+  at least some of the time, I wonder what's keeping the ghc-android build+  from doing so? It might be due to it being a cross compiler. I tried+  recompiling it with the stage 2, native compiler enabled. While I was+  able to use that ghc binary on Android, it refused to run --interactive,+  claiming it was not built with that enabled. Don't really understand+  the ghc build system, so might have missed something.++  Maybe I need to recompile ghc using the native ghc running on Android.+  But that would involve porting gcc and a lot of libraries and toolchain+  stuff to Android.++* [yesod-pure](http://hackage.haskell.org/package/yesod-pure) is an option,+  and I would not mind making all the code changes to use it, getting+  rid of template haskell entirely. (Probably around 1 thousand lines of+  code would need to be written, but most of it would be trivial+  conversion of hamlet templates.)+  +  Question is, will yesod install at all without template haskell? Not+  easily. `vector`, `monad-logger`, `aeson`, `shakespeare`,+  `shakespeare-css`, `shakespeare-js`, `shakespeare-i18n`, `hamlet`+  all use TH at build time. Hacked them all to just remove the TH parts.++  The hack job on `yesod-core` was especially rough, involving things like+  404 handlers. Did get it to build tho!++  Still a dozen packages before I can build yesod, and then will try +  building [this yesod-pure demo](https://gist.github.com/snoyberg/3870834/raw/212f0164de36524291df3ab35788e2b72d8d1e75/fib.hs).
+ doc/design/assistant/blog/day_198__bugfixes.mdwn view
@@ -0,0 +1,11 @@+Wrote a C shim to get the Android app started. This avoids it relying on+the Android /system/bin/sh to run its shell script, or indeed relying on+any unix utilities from Android at all, which may help on some+systems. Pushed a new build of the Android app.++Tracked down a failure a lot of people are reporting with WebDAV support+to a backported security fix in the TLS library, and filed an upstream bug+about it.++Various other misc fixing and stuff.+My queue of bug reports and stuff only has 47 items in it now. Urk..
+ doc/design/assistant/blog/day_199__wrapping_up_Android_for_now.mdwn view
@@ -0,0 +1,26 @@+An Android autobuilder is now set up to run nightly. At this point+I don't see an immediate way to getting the webapp working on Android, so+it's best to wait a month or two and see how things develop in Haskell land.+So I'm moving on to other things.++Today:++* Fixed a nasty regression that made `*` not match files in subdirectories.+  That broke the preferred content handling, amoung other things. I will+  be pushing out a new release soon.+* As a last Android thing (for now), made the Android app automatically+  run `git annex assistant --autostart` , so you can manually set up+  an assistant-driven repository on Android, listing the repository in+  `.config/git-annex/autostart`+* Made the webapp display any error message from `git init` if it fails.+  This was the one remaining gap in the logging.+  One reason it could fail is if the system has a newer git in use, and+  `~/.gitconfig` is configured with some options the older git bundled+  with git-annex doesn't like.+* Bumped the major version to 4, and annex.version will be set to 4 in+  new direct mode repositories. (But version 3 is otherwise still used, to+  avoid any upgrade pain.) This is to prevent old versions that don't+  understand direct mode from getting confused. I hope direct mode is+  finally complete, too, after the work to make it work on crippled+  filesystems this month.+* Misc other bugfixes etc. Backlog down to 43.
+ doc/design/assistant/blog/day_200__release_day.mdwn view
@@ -0,0 +1,19 @@+As well as making a new release, I rewrote most of the Makefile, so that it+uses cabal to build git-annex. This avoids some duplication, and most+importantly, means that the Makefile can auto-detect available libraries+rather than needing to juggle build flags manually. Which was becoming a+real pain.++I had avoided doing this before because cabal is slow for me on my little+netbook. Adding ten seconds to every rebuild really does matter! But I came+up with a hack to let me do incremental development builds without the+cabal overhead, by intercepting and reusing the ghc command that cabal+runs.++There was also cabal "fun" to get the Android build working with cabal.+And more fun involving building the test suite. For various reasons, I+decided to move the test suite into the git-annex binary. So you can run+`git annex test` at any time, any place, and it self-tests. That's a neat+trick I've seen one or two other programs do, and probably the nicest thing+to come out of what was otherwise a pretty yak shaving change that involved+babysitting builds all day.
+ doc/design/assistant/blog/day_81__enabling_pre-existing_special_remotes.mdwn view
@@ -0,0 +1,34 @@+It's possible for one git annex repository to configure a special remote+that it makes sense for other repositories to also be able to use. Today I+added the UI to support that; in the list of repositories, such+repositories have a "enable" link.++To enable pre-existing rsync special remotes, the webapp has to do the same+probing and ssh key setup that it does when initially creating them.+Rsync.net is also handled as a special case in that code. There was one+ugly part to this.. When a rsync remote is configured in the webapp,+it uses a mangled hostname like "git-annex-example.com-user", to+make ssh use the key it sets up. That gets stored in the `remote.log`, and so+the enabling code has to unmangle it to get back to the real hostname.++---++Based on the still-running [[prioritizing_special_remotes]] poll, a lot+of people want special remote support for their phone or mp3 player.+(As opposed to running git-annex on an Android phone, which comes later..)+It'd be easy enough to make the webapp set up a directory special remote+on such a device, but that makes consuming some types of content on the+phone difficult (mp3 players seem to handle them ok based on what people tell+me). I need to think more about some of the ideas mentioned in [[android]]+for more suitable ways of storing files.++One thing's for sure: You won't want the assistant to sync all your files+to your phone! So I also need to start coming up with partial syncing+controls. One idea is for each remote to have a configurable matcher for files+it likes to receive. That could be only mp3 files, or all files inside a+given subdirectory, or all files *not* in a given subdirectory. That means+that when the assistant detects a file has been moved, it'll need to add+(or remove) a queued transfer. Lots of other things could be matched on,+like file size, number of copies, etc. Oh look, I have a+[beautiful library I wrote earlier](http://joeyh.name/blog/entry/happy_haskell_hacker)+that I can reuse!
doc/design/assistant/polls/prioritizing_special_remotes.mdwn view
@@ -6,7 +6,7 @@ Help me prioritize my work: What special remote would you most like to use with the git-annex assistant? -[[!poll open=yes 15 "Amazon S3 (done)" 12 "Amazon Glacier (done)" 9 "Box.com (done)" 69 "My phone (or MP3 player)" 18 "Tahoe-LAFS" 6 "OpenStack SWIFT" 27 "Google Drive"]]+[[!poll open=yes 15 "Amazon S3 (done)" 12 "Amazon Glacier (done)" 9 "Box.com (done)" 70 "My phone (or MP3 player)" 18 "Tahoe-LAFS" 7 "OpenStack SWIFT" 28 "Google Drive"]]  This poll is ordered with the options I consider easiest to build listed first. Mostly because git-annex already supports them and they
+ doc/direct_mode/comment_1_93fc31e8dc0ad16248a2593a1482d375._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawl2Jj8q2upJL4ZQAc2lp7ugTxJiGtcICv8"+ nickname="Michael"+ subject="comment 1"+ date="2013-02-18T23:24:11Z"+ content="""+So, just which git commands *are* safe?  It seems like I'm going to have to use direct mode, so it'd be nice to know just what I'm allowed to do, and what the workflow should be.+"""]]
+ doc/direct_mode/comment_2_7f7086b34ed136851963f145868a1d23._comment view
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.152.108.183"+ subject="safe and unsafe commands"+ date="2013-02-19T02:55:13Z"+ content="""+All git commands that do not change files in the work tee (and do not stage files from the work tree), are safe. I don't have a complete list; it includes `git log`, `git show`, `git diff`, `git commit` (but not -a or with a file as a parameter), `git branch`, `git fetch`, `git push`, `git grep`, `git status`, `git tag`, `git mv` (this one is somewhat surprising, but I've tested it and it's ok)++git commands that change files in the work tree will replace your data with dangling symlinks. This includes things like `git revert`, `git checkout`, `git merge`, `git pull`, `git reset`++git commands that stage files from the work tree will commit your data to git directly. This includes `git add`, `git commit -a`, and `git commit file`+"""]]
+ doc/direct_mode/comment_3_8020d74bddf0e38b0a297e5dae7c217b._comment view
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawl2Jj8q2upJL4ZQAc2lp7ugTxJiGtcICv8"+ nickname="Michael"+ subject="comment 3"+ date="2013-02-19T03:03:14Z"+ content="""+So, if I edit a \"content file\" (change a music file's metadata, say), what's the workflow to record that fact and then synchronise it to other repositories?++I can't do a `git add`, so I don't understand what has to happen as a first step.  (Thanks for your quick reply above, BTW.)+++"""]]
+ doc/direct_mode/comment_4_97c26bd82f623a3b2d56bab4afff0126._comment view
@@ -0,0 +1,13 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.152.108.183"+ subject="comment 4"+ date="2013-02-19T03:05:35Z"+ content="""+<pre>+git annex add $file+git commit -m changed+git annex sync+git annex copy $file --to otherrepo+</pre>+"""]]
+ doc/forum/How_to_prevent_the_assistant_from_downloading_all_data__63__.mdwn view
@@ -0,0 +1,9 @@+I have a repository on my laptop with a single remote on a USB drive. Both were created without the assistant.++The remote holds all the content. My understanding is that this would be a "backup" repository, using the group definitions.++The local repository generally holds no content. When I want a file, I make sure the remote is available, and then I `git annex get` it.++This works fine in git annex, but I'm now experimenting with the assistant. As soon as I fire up the assistant, it starts downloading all of the data from the remote. I don't ever want it to automatically get any content from the remote. If it sees new content in the repository, I would like it to push that out to the remote. But never get anything from the remote, and never drop anything that is in the repository.++How can I setup this behaviour in the assistant? I have set the remote's repository group to "backup". The local repository is not in any group, since none of the groups fit my model for this repo.
+ doc/forum/Syncronisation_of_syncronisation_between_3_repositories__63__.mdwn view
@@ -0,0 +1,11 @@+Hello Joey,++I just want to know if file transfers between three inter-connected repositories somehow gets syncronized. I have a laptop, a local file server in my home and a virtual server on the internet.++Both my laptop and my file server are configured with a full git repository and connected through pairing and xmpp. The server on the internet is configured as a rsync special remote.++I want the local file server to hold a copy of everything in my annex, the rsync remote should get everything except the folder "media" (too large to upload and not that important) and the laptop whatever I manually decide (preferred content is set to "present").++I have added some files to the repository on the local file server and transferred their content to my laptop by using "git annex get". But when I started the web interface, I saw that those files who are present on both the file server and on the laptop get uploaded to the remote server from both computers, often the same file at the same time. Previously I though the two assistants would somehow talk to each other via xmpp so that doubled effort like that would be avoided. I'm also worried about data consistency because two apparently separate processes rsync to the same remote repository at the same time.++So my question would be: Is your xmpp protocol designed to deal with situations like this and I did not set it up correctly or is what I'm trying to accomplish simply not (yet) possible?
+ doc/forum/assistant_without_watch__63__.mdwn view
@@ -0,0 +1,13 @@+"watch" is described as++> With this running as a daemon in the background, you no longer need to manually run git commands  when  manipulating your files.++and "assistant" is described as++> Like watch, but also automatically syncs changes to other remotes.++I would like the behaviour of assistant, without the watch part:++I have an archive of large files, which I think would be useful to manage manually using git.  But I don't want to manually enforce the "numcopies=" requirement, playing with the assistant and webapp it seems really nice to have it take care of that.++Is there currently an "assistant-without-watch" option?   If not, is it planned?
+ doc/forum/git-annex_and_tagfs.mdwn view
@@ -0,0 +1,14 @@+Hi,++Thanks for git-annex, really a great project.+Another related feature which would be useful to have is described by tagfs [3][] [4][], experimental implementations such as [tagfs over fuse][1], and [tagsistant][2] exist, but having a solution within the power of git-annex would really be attractive.++How hard would this be to implement within the existing infrastructure?+Thanks.++related post: [[multiple_sym_links___40__for_tagging_photos__41____63__]]++[1]: http://code.google.com/p/tagfs/+[2]: www.tagsistant.net/+[3]: http://site.xam.de/2006/01-tagfs.pdf+[4]: http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&ved=0CE4QFjAF&url=http%3A%2F%2Fweb.mit.edu%2F6.033%2F2011%2Fwwwdocs%2Fwriting-samples%2Fsbezek_dp1.pdf&ei=ILQkUdqxMueR0QWgx4CwDw&usg=AFQjCNE1eWeFxmaxzOLZYVsb0tomqWNQaw&bvm=bv.42661473,d.d2k
+ doc/forum/mistakenly_checked___42__files__42___into_an_annex.__bummer..mdwn view
@@ -0,0 +1,3 @@+A couple times working in an annex manually, I accidentally did "git add" instead of "git annex add" and ended up with files checked into my repo instead of symlinks.  So now there is some file content in git, rather than in the annex.  Is there any way to root that out, or is it there forever?  (My limited knowledge of git says: it's there forever, unless maybe you go into the branches where it lives, do an interactive rebase to the time before it was added, remove that commit, replay history, and then garbage collect, but I have no idea if that would suddenly break git annex, and it sounds painful anyway.)++If say I were a neat freak and wanted to just start over with a clean annex, I imagine the thing to do would be to just start the hell over -- and if I wanted to do that, the way to go would be to get into a full repository, do a "git annex uninit" and then throw away the .git directory, then do "git init" and "git annex init" and then "git annex add ." ?
+ doc/forum/switching_to__47__from_direct_mode_while_assistant_is_running.mdwn view
@@ -0,0 +1,2 @@+Is that really unsafe?  Because I did that and the switch to direct mode seemed to leave a lot of files still as links, and when I panicked and switched back to indirect mode, a whole lot of stuff seemed to have become unannexed and I reannexed it.+
+ doc/forum/wishlist:_git_annex_put_--_same_as_get__44___but_for_defaults.mdwn view
@@ -0,0 +1,17 @@+I am running centralized git-annex exclusively.++Similar to++    git annex get++I'd like to have a++    git annex put++which would put all files on the default remote(s).++My main reason for not wanting to use copy --to is that I need to specify the remote's name in this case which makes writing a wrapper unnecessarily hard. Also, this would allow++    mr push++to do the right thing all by itself.
doc/git-annex.mdwn view
@@ -191,7 +191,7 @@   Typically started at boot, or when you log in.    With the --autostart option, the assistant is started in any repositories-  it has created.+  it has created. These are listed in `~/.config/git-annex/autostart`  * webapp @@ -505,6 +505,10 @@    With --force, even files whose content is not currently available will   be rekeyed. Use with caution.++* test++  This runs git-annex's built-in test suite.  * xmppgit 
doc/install.mdwn view
@@ -3,7 +3,8 @@ [[!table format=dsv header=yes data=""" detailed instructions | quick install [[OSX]]               | [download git-annex.app](http://downloads.kitenet.net/git-annex/OSX/current/)-[[Linux|linux_standalone]] | [download prebuilt linux tarball](http://downloads.kitenet.net/git-annex/linux/)+[[Android]]           | [download git-annex.apk](http://downloads.kitenet.net/git-annex/android/current/) **beta**+[[Linux|linux_standalone]] | [download prebuilt linux tarball](http://downloads.kitenet.net/git-annex/linux/current/) [[Debian]]            | `apt-get install git-annex` [[Ubuntu]]            | `apt-get install git-annex` [[Fedora]]            | `yum install git-annex`@@ -14,7 +15,6 @@ [[ScientificLinux5]]  | (and other RHEL5 clones like CentOS5) [[openSUSE]]          |  Windows               | [[sorry, Windows not supported yet|todo/windows_support]]-[[Android]]           |  """]]  ## Using cabal
doc/install/Android.mdwn view
@@ -1,31 +1,25 @@ git-annex can be used on Android, however you need to know your way around-the command line to install and use it. (An Android app may be developed+the command line to install and use it. (Hope to get the webapp working eventually.) -## prebuilt tarball--Download the [prebuilt tarball](http://downloads.kitenet.net/git-annex/android/).-Instructions below assume it was downloaded to `/sdcard/Download`, which-is the default if you use the web browser for the download.+## Android app -To use this tarball, you need to install either-[KBOX](http://kevinboone.net/kbox.html) or-[Terminal IDE](https://play.google.com/store/apps/details?id=com.spartacusrex.spartacuside)-(available in Google Play).-This is both to get a shell console, as well as a location under-`/data` where git-annex can be installed.+First, ensure your Android device is configured to allow installation of+non-Market apps. Go to Setup -&gt; Security, and enable "Unknown Sources". -Open the console app you installed, and enter this command:+Download the [git-annex.apk](http://downloads.kitenet.net/git-annex/android/current/)+onto your Android device, and open it to install. -	cd $(which sh)/..; tar xf /sdcard/Download/git-annex-android.tar.gz+When you start the Git Annex app, it will dump you into terminal. From+here, you can run git-annex, as well as many standard git and unix commands+provided with the app. You can do everything in the [[walkthrough]] and+more. -Now git-annex is installed, but to use it you need to enter a special-shell environment:+## autobuilds -	runshell+A daily build is also available. -Now you have git-annex, git, and some other utilities available, and can-do everything in the [[walkthrough]] and more.+* [download tarball](http://downloads.kitenet.net/git-annex/autobuild/i386/git-annex-standalone-i386.tar.gz) ([build logs](http://downloads.kitenet.net/git-annex/autobuild/android/))  ## building it yourself @@ -35,3 +29,9 @@ yet an easy process.   You also need to install git and all the utilities listed on [[fromscratch]].++You will need to have the Android SDK and NDK installed; see+`standalone/android/Makefile` to configure the paths to them. You'll also+need ant, and the JDK.++Then to build the full Android app bundle, use `make androidapp`
doc/install/Linux_standalone.mdwn view
@@ -1,14 +1,21 @@ If your Linux distribution does not have git-annex packaged up for you, you can either build it [[fromscratch]], or you can use a handy-prebuilt tarball.+prebuilt tarball of the most recent release.  This tarball should work on most Linux systems. It does not depend on anything except for glibc. -[download tarball](http://downloads.kitenet.net/git-annex/linux/)+[download tarball](http://downloads.kitenet.net/git-annex/linux/current/)  To use, just unpack the tarball, `cd git-annex.linux` and run `./runshell` -- this sets up an environment where you can use `git annex`  Warning: This is a last resort. Most Linux users should instead [[install]] git-annex from their distribution of choice.++## autobuilds++A daily build is also available.++* [download tarball](http://downloads.kitenet.net/git-annex/autobuild/i386/git-annex-standalone-i386.tar.gz) ([build logs](http://downloads.kitenet.net/git-annex/autobuild/i386/))+
− doc/news/version_3.20130107.mdwn
@@ -1,13 +0,0 @@-git-annex 3.20130107 released with [[!toggle text="these changes"]]-[[!toggleable text="""-   * webapp: Add UI to stop and restart assistant.-   * committer: Fix a file handle leak.-   * assistant: Make expensive transfer scan work fully in direct mode.-   * More commands work in direct mode repositories: find, whereis, move, copy,-     drop, log, fsck, add, addurl.-   * sync: No longer automatically adds files in direct mode.-   * assistant: Detect when system is not configured with a user name,-     and set environment to prevent git from failing.-   * direct: Avoid hardlinking symlinks that point to the same content-     when the content is not present.-   * Fix transferring files to special remotes in direct mode."""]]
+ doc/news/version_4.20130227.mdwn view
@@ -0,0 +1,29 @@+git-annex 4.20130227 released with [[!toggle text="these changes"]]+[[!toggleable text="""+   * annex.version is now set to 4 for direct mode repositories.+   * Should now fully support git repositories with core.symlinks=false;+     always using git's pseudosymlink files in such repositories.+   * webapp: Allow creating repositories on filesystems that lack support for+     symlinks.+   * webapp: Can now add a new local repository, and make it sync with+     the main local repository.+   * Android: Bundle now includes openssh.+   * Android: Support ssh connection caching.+   * Android: Assistant is fully working. (But no webapp yet.)+   * Direct mode: Support filesystems like FAT which can change their inodes+     each time they are mounted.+   * Direct mode: Fix support for adding a modified file.+   * Avoid passing -p to rsync, to interoperate with crippled filesystems.+     Closes: #[700282](http://bugs.debian.org/700282)+   * Additional GIT\_DIR support bugfixes. May actually work now.+   * webapp: Display any error message from git init if it fails to create+     a repository.+   * Fix a reversion in matching globs introduced in the last release,+     where "*" did not match files inside subdirectories. No longer uses+     the Glob library.+   * copy: Update location log when no copy was performed, if the location+     log was out of date.+   * Makefile now builds using cabal, taking advantage of cabal's automatic+     detection of appropriate build flags.+   * test: The test suite is now built into the git-annex binary, and can+     be run at any time."""]]
doc/preferred_content.mdwn view
@@ -58,7 +58,7 @@ the repo it's being dropped from. This is different than running `git annex drop --copies=2`, which will drop files that current have 2 copies. -## difference: "present"+### difference: "present"  There's a special "present" keyword you can use in a preferred content expression. This means that content is preferred if it's present,
+ doc/special_remotes/bup/comment_1_96179a003da4444f6fc08867872cda0a._comment view
@@ -0,0 +1,43 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkgbXwQtPQSG8igdS7U8l031N8sqDmuyvk"+ nickname="Albert"+ subject="Error with bup and gnupg"+ date="2012-10-22T20:56:56Z"+ content="""+Hello,++I get this error when trying to use git-annex with bup and gnupg:++<pre>+move importable_pilot_surveys.tar (gpg) (checking localaseebup...) (to localaseebup...) +Traceback (most recent call last):+  File \"/usr/lib/bup/cmd/bup-split\", line 133, in <module>+    progress=prog)+  File \"/usr/lib/bup/bup/hashsplit.py\", line 167, in split_to_shalist+    for (sha,size,bits) in sl:+  File \"/usr/lib/bup/bup/hashsplit.py\", line 118, in _split_to_blobs+    for (blob, bits) in hashsplit_iter(files, keep_boundaries, progress):+  File \"/usr/lib/bup/bup/hashsplit.py\", line 86, in _hashsplit_iter+    bnew = next(fi)+  File \"/usr/lib/bup/bup/helpers.py\", line 86, in next+    return it.next()+  File \"/usr/lib/bup/bup/hashsplit.py\", line 49, in blobiter+    for filenum,f in enumerate(files):+  File \"/usr/lib/bup/cmd/bup-split\", line 128, in <genexpr>+    files = extra and (open(fn) for fn in extra) or [sys.stdin]+IOError: [Errno 2] No such file or directory: '-'+</pre>+++I was able to work-around this issue by altering /usr/lib/bup/cmd/bup-split (though I don't think its a bup bug) to just pull from stdin:++files = [sys.stdin]++on ~ line 128.++Any ideas? Also, do you think that bup's data-deduplication does anything when gnupg is enabled, i.e. is it just as well to use a directory remote with gnupg?++Thanks! Git annex rules!++Albert+"""]]
+ doc/special_remotes/bup/comment_2_612b038c15206f9f3c2e23c7104ca627._comment view
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.154.0.23"+ subject="comment 2"+ date="2012-10-23T20:01:43Z"+ content="""+@Albert, thanks for reporting this bug (but put them in [[bugs]] in future please).++This is specific to using the bup special remote with encryption. Without encryption it works. And no, it won't manage to deduplicate anything that's encrypted, as far as I know. ++I think bup-split must have used - for stdin in the past, but now, it just reads from stdin when no file is specified, so I've updated git-annex.+"""]]
+ doc/special_remotes/comment_8_3d4ffec566d68d601eafe8758a616756._comment view
@@ -0,0 +1,13 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlRThEwuPnr8_bcuuCTQ0rQd3w6AfeMiLY"+ nickname="Alex"+ subject="'webhook' special remote?"+ date="2013-02-24T15:05:27Z"+ content="""+Is there any chance a special remote that functions like a hybrid of 'web' and 'hook'? At least in theory, it should be relatively simple, since it would only support 'get' and the only meaningful parameters to pass would be the URL and the output file name.++Maybe make it something like git config annex.myprogram-webhook 'myprogram $ANNEX_URL $ANNEX_FILE', and fetching could work by adding a --handler or --type parameter to addurl.++The use case here is anywhere that simple 'fetch the file over HTTP/FTP/etc' isn't workable - maybe it's on rapidshare and you need to use plowshare to download it; maybe it's a youtube video and you want to use youtube-dl, maybe it's a chapter of a manga and you want to turn it into a CBZ file when you fetch it.++"""]]
+ doc/special_remotes/comment_9_26af468952f0403171370b56e127830a._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlRThEwuPnr8_bcuuCTQ0rQd3w6AfeMiLY"+ nickname="Alex"+ subject="comment 9"+ date="2013-02-24T15:13:16Z"+ content="""+A *ridiculously* cool possibility would be to allow them to match against URLs and then handle those (youtube-dl for youtube video URLs, for instance), but that would be additional work on your end and isn't really necessary.+"""]]
+ doc/special_remotes/hook/comment_1_6a74a25891974a28a8cb42b87cb53c26._comment view
@@ -0,0 +1,32 @@+[[!comment format=mdwn+ username="helmut"+ ip="89.0.176.236"+ subject="Asynchronous hooks?"+ date="2012-10-13T09:46:14Z"+ content="""+Is there a way to use asynchronous remotes? Interaction with git annex would have to+split the part of initiating some action from completing it.++I imagine I could `git annex copy` a file to an asynchronous remote and the command+would almost immediately complete. Later I would learn that the transfer is+completed, so the hook must be able to record that information in the `git-annex`+branch. An additional plumbing command seems required here as well as a way to+indicate that even though the store-hook completed, the file is not transferred.++Similarly `git annex get` would immediately return without actually fetching the+file. This should already be possible by returning non-zero from the retrieve-hook.+Later the hook could use plumbing level commands to actually stick the received file+into the repository.++The remove-hook should need no changes, but the checkpresent-hook would be more like+a trigger without any actual result. The extension of the plumbing required for the+extension to the receive-hook could update the location log. A downside here is that+you never know when a fsck has completed.++My proposal does not include a way to track the completion of actions, but relies on+the hook to always complete them reliably. It is not clear that this is the best road+for asynchronous hooks.++One use case for this would be a remote that is only accessible via uucp. Are there+other use cases? Is the drafted interface useful?+"""]]
+ doc/tips/assume-unstaged/comment_1_44abd811ef79a85e557418e17a3927be._comment view
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://me.yahoo.com/a/2djv2EYwk43rfJIAQXjYt_vfuOU-#a11a6"+ nickname="Olivier R"+ subject="It doesn't work 100%"+ date="2012-05-03T21:42:54Z"+ content="""+When you remove tracked files... it doesn't show the new status. it's like if the file was ignored.+++"""]]
+ doc/tips/using_Amazon_S3/comment_1_666a26f95024760c99c627eed37b1966._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnoUOqs_lbuWyZBqyU6unHgUduJwDDgiKY"+ nickname="Matt"+ subject="ANNEX_S3 vs AWS for keys"+ date="2012-05-29T12:24:25Z"+ content="""+The instructions state ANNEX_S3_ACCESS_KEY_ID and ANNEX_SECRET_ACCESS_KEY but git-annex cannot connect with those constants. git-annex tells me to set both \"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY\" instead, which works. This is with Xubuntu 12.04.+"""]]
+ doc/tips/using_Amazon_S3/comment_2_f5a0883be7dbb421b584c6dc0165f1ef._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.153.81.112"+ subject="comment 2"+ date="2012-05-29T19:10:42Z"+ content="""+Thanks, I've fixed that. (You could have too.. this is a wiki ;)+"""]]
+ doc/todo/Use_a_remote_as_a_sharing_site_for_files_with_obfuscated_URLs.mdwn view
@@ -0,0 +1,7 @@+There are times when it is handy to be able to upload a file to a web host somewhere and share a link for that file to a select few people.++It seems to be that the assistant could handle this scenario. It could generate a directory with a random name on the remote, and transfer the file there (using the existing filename) and the appropriate URL could be displayed in the assistant webapp to allow the user to copy the URL to send it to the appropriate people.++Note: Joey and I had a quick chat about this use case at LCA2013.++[[!tag design/assistant]]
doc/todo/automatic_bookkeeping_watch_command.mdwn view
@@ -10,3 +10,6 @@ so this would not be 100% equivalent to dropbox. --[[Joey]]  This is a big project with its own [[design pages|design/assistant]].++> [[done]].. at least, we have a watch command an an assistant, which+> is still being developed. --[[Joey]] 
+ doc/todo/cache_key_info/comment_1_578df1b3b2cbfdc4aa1805378f35dc48._comment view
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawl9sYlePmv1xK-VvjBdN-5doOa_Xw-jH4U"+ nickname="Richard"+ subject="comment 1"+ date="2011-05-17T07:27:02Z"+ content="""+Sounds like a good idea.++* git annex fsck (or similar) should check/rebuild the caches+* I would simply require a clean tree with a verbose error. 80/20 rule and defaulting to save actions.+"""]]
+ doc/todo/direct_mode_guard.mdwn view
@@ -0,0 +1,22 @@+Currently [[/direct_mode]] allows the user to point many normally safe+git commands at his foot and pull the trigger. At LCA2013, a git-annex+user suggested modifying direct mode to make this impossible.++One way to do it would be to move the .git directory. Instead, make there+be a .git-annex directory in direct mode repositories. git-annex would know+how to use it, and would be extended to support all known safe git+commands, passing parameters through, and in some cases verifying them.++So, for example, `git annex commit` would run `git commit --git-dir=.git-annex`++However, `git annex commit -a` would refuse to run, or even do something+intelligent that does not involve staging every direct mode file.++----++One source of problems here is that there is some overlap between git-annex+and git commands. Ie, `git annex add` cannot be a passthrough for `git+add`. The git wrapper could instead be another program, or it could be+something like `git annex git add`++--[[Joey]]
+ doc/todo/windows_support/comment_1_3cc26ad8101a22e95a8c60cf0c4dedcc._comment view
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkRITTYYsN0TFKN7G5sZ6BWGZOTQ88Pz4s"+ nickname="Zoltán"+ subject="cygwin"+ date="2012-05-15T00:14:08Z"+ content="""+What about [Cygwin](http://cygwin.com/)? It emulates POSIX fairly well under Windows (including signals, forking, fs (also things like /dev/null, /proc), unix file permissions), has all standard gnu utilities. It also emulates symlinks, but they are unfortunately incompatible with NTFS symlinks introduced in Vista [due to some stupid restrictions on Windows](http://cygwin.com/ml/cygwin/2009-10/msg00756.html).++If git-annex could be modified to not require symlinks to work, the it would be a pretty neat solution (and you get a real shell, not some command.com on drugs (aka cmd.exe))+"""]]
+ doc/todo/windows_support/comment_2_8acae818ce468967499050bbe3c532ea._comment view
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawk5cj-itfFHq_yhJHdzk3QOPp-PNW_MjPU"+ nickname="Michael"+ subject="+1 Cygwin"+ date="2012-05-23T19:30:21Z"+ content="""+Windows support is a must. In my experience, binary file means proprietary editor, which means Windows.++Unfortunately, there's not much overlap between people who use graphical editors in Windows all day vs. people who are willing to tolerate Cygwin's setup.exe, compile a Haskell program, learn git and git-annex's 90-odd subcommands, and use a mintty terminal to manage their repository, especially now that there's a sexy GitHub app for Windows.++That aside, I think Windows-based content producers are still *the* audience for git-annex. First Windows support, then a GUI, then the world.+"""]]
+ doc/todo/windows_support/comment_3_bd0a12f4c9b884ab8a06082842381a01._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://xolus.net/openid/max"+ nickname="B0FH"+ subject="What about NTFS support ?"+ date="2012-08-02T17:45:10Z"+ content="""+Has git-annex been tested with an NTFS-formatted disk under Linux ? NTFS is supposed to be case-sensitive and to allow symlinks, and these are supposed to work with ntfs3g.+"""]]
+ doc/todo/windows_support/comment_4_ad06b98b2ddac866ffee334e41fee6a8._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlc1og3PqIGudOMkFNrCCNg66vB7s-jLpc"+ nickname="Paul"+ subject="Re: What about NTFS support?"+ date="2012-08-16T19:30:38Z"+ content="""+I successfully use git-annex on an NTFS formatted external USB drive, so yes, it is possible and works well.+"""]]
+ doc/todo/windows_support/comment_5_444fc7251f57db241b6e80abae41851c._comment view
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://me.yahoo.com/a/dASECLNzvckz4VwqUGYsvthiplY.#d2c27"+ nickname="A. D. Sicks"+ subject="comment 5"+ date="2012-09-09T23:48:21Z"+ content="""+Haskell has C++ binding, so it should be possible to port it to .net/Mono with a VB GUI for Windows users.  Windows has a primitive form of symlinks called shortcuts.  Perhaps shortcut support in Windows could replace the use of symlinks.  I've used shortcuts since XP to put my home Windows directory on another partition and never had a hitch...++If anyone is interested in working on this, hit me up.  I would like to use this in my XP vbox to have access to files on my host OS...I have a student edition of Visual Studio 2005 to do an open source port...+"""]]
+ doc/todo/windows_support/comment_6_34f1f60b570c389bb1e741b990064a7e._comment view
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnlwEMhiNYv__mEUABW4scn83yMraC3hqE"+ nickname="Sean"+ subject="NTFS symlinks"+ date="2013-01-11T21:44:21Z"+ content="""+It seems that NTFS (from Vista forward) has full POSIX support for symlinks. At least, Wikipedia [seems to think so.](http://en.wikipedia.org/wiki/NTFS_symbolic_link). What about doing like GitHub and using MinGW for compatibility? Cygwin absolutely blows in terms of installation size and compatability with the rest of Windows.+"""]]
doc/todo/wishlist:_disable_automatic_commits.mdwn view
@@ -29,3 +29,8 @@ detecting manual commits wouldn't be a stretch.  [[!tag design/assistant]]++> You can do this now by pausing committing via the webapp,+> or setting `annex.autocommit=false`.+> +> The assustant probably doesn't push such commits yet.
doc/upgrades.mdwn view
@@ -18,6 +18,11 @@  ## Upgrade events, so far +### v3 -> v4 (git-annex version 4.x)++v4 is only used for [[direct_mode]], and no upgrade needs to be done from+existing v3 repositories, they will continue to work.+ ### v2 -> v3 (git-annex version 3.x)  Involved moving the .git-annex/ directory into a separate git-annex branch.
− ghci
@@ -1,5 +0,0 @@-#!/bin/sh-# This runs ghci with the same flags used when compiling with ghc.-# Certian flags need to be the same in order for ghci to reuse compiled-# objects.-ghci $(make getflags | sed 's/-Wall//') $@
git-annex.1 view
@@ -174,7 +174,7 @@ Typically started at boot, or when you log in. .IP With the \-\-autostart option, the assistant is started in any repositories-it has created.+it has created. These are listed in ~/.config/git\-annex/autostart .IP .IP "webapp" Runs a web app, that allows easy setup of a git\-annex repository,@@ -453,6 +453,9 @@ .IP With \-\-force, even files whose content is not currently available will be rekeyed. Use with caution.+.IP+.IP "test"+This runs git\-annex's built\-in test suite. .IP .IP "xmppgit" This command is used internally to perform git pulls over XMPP.
git-annex.cabal view
@@ -1,11 +1,11 @@ Name: git-annex-Version: 3.20130216.1+Version: 4.20130227 Cabal-Version: >= 1.8 License: GPL Maintainer: Joey Hess <joey@kitenet.net> Author: Joey Hess Stability: Stable-Copyright: 2010-2012 Joey Hess+Copyright: 2010-2013 Joey Hess License-File: COPYRIGHT Homepage: http://git-annex.branchable.com/ Build-type: Custom@@ -52,6 +52,16 @@ Flag DNS   Description: Enable the haskell DNS library for DNS lookup +Flag Production+  Description: Enable production build (slower build; faster binary)++Flag Android+  Description: Building for Android+  Default: False++Flag TestSuite+  Description: Embed the test suite into git-annex+ Executable git-annex   Main-Is: git-annex.hs   Build-Depends: MissingH, hslogger, directory, filepath,@@ -60,15 +70,21 @@    extensible-exceptions, dataenc, SHA, process, json,    base (>= 4.5 && < 4.8), monad-control, transformers-base, lifted-base,    IfElse, text, QuickCheck >= 2.1, bloomfilter, edit-distance, process,-   SafeSemaphore, uuid, random, Glob+   SafeSemaphore, uuid, random, regex-compat   -- Need to list these because they're generated from .hsc files.   Other-Modules: Utility.Touch Utility.Mounts   Include-Dirs: Utility   C-Sources: Utility/libdiskfree.c Utility/libmounts.c-  Extensions: CPP-  GHC-Options: -threaded-  CPP-Options: -DWITH_GLOB+  CC-Options: -Wall+  GHC-Options: -threaded -Wall +  if flag(Production)+    GHC-Options: -O2++  if flag(TestSuite)+    Build-Depends: testpack, HUnit+    CPP-Options: -DWITH_TESTSUITE+   if flag(S3)     Build-Depends: hS3     CPP-Options: -DWITH_S3@@ -76,14 +92,14 @@   if flag(WebDAV)     Build-Depends: DAV (>= 0.3), http-conduit, xml-conduit, http-types     CPP-Options: -DWITH_WEBDAV-  -  if flag(Assistant)-    Build-Depends: async    if flag(Assistant) && ! os(windows) && ! os(solaris)-    Build-Depends: stm >= 2.3+    Build-Depends: async, stm (>= 2.3)     CPP-Options: -DWITH_ASSISTANT +  if flag(Android)+    CPP-Options: -D__ANDROID__+   if os(linux) && flag(Inotify)     Build-Depends: hinotify     CPP-Options: -DWITH_INOTIFY@@ -100,39 +116,24 @@     Build-Depends: dbus (>= 0.10.3)     CPP-Options: -DWITH_DBUS -  if flag(Webapp) && flag(Assistant)+  if flag(Webapp)     Build-Depends: yesod, yesod-static, case-insensitive,      http-types, transformers, wai, wai-logger, warp, blaze-builder,-     crypto-api, hamlet, clientsession, aeson, yesod-form (>= 1.2.0),-     template-haskell, yesod-default (>= 1.1.0), data-default+     crypto-api, hamlet, clientsession, aeson, yesod-form,+     template-haskell, yesod-default, data-default     CPP-Options: -DWITH_WEBAPP -  if flag(Pairing) && flag(Webapp)+  if flag(Pairing)     Build-Depends: network-multicast, network-info     CPP-Options: -DWITH_PAIRING -  if flag(XMPP) && flag(Assistant)+  if flag(XMPP)     Build-Depends: network-protocol-xmpp, gnutls (>= 0.1.4), xml-types     CPP-Options: -DWITH_XMPP -  if flag(XMPP) && flag(Assistant) && flag(DNS)+  if flag(DNS)     Build-Depends: dns     CPP-Options: -DWITH_DNS--Test-Suite test-  Type: exitcode-stdio-1.0-  Main-Is: test.hs-  Build-Depends: testpack, HUnit, MissingH, hslogger, directory, filepath,-   unix, containers, utf8-string, network, mtl (>= 2.1.1), bytestring,-   old-locale, time, extensible-exceptions, dataenc, SHA,-   process, json, base (>= 4.5 && < 4.7), monad-control,-   transformers-base, lifted-base, IfElse, text, QuickCheck >= 2.1,-   bloomfilter, edit-distance, process, SafeSemaphore, Glob-  Other-Modules: Utility.Touch-  Include-Dirs: Utility-  C-Sources: Utility/libdiskfree.c-  Extensions: CPP-  GHC-Options: -threaded -DWITH_GLOB  source-repository head   type: git
git-annex.hs view
@@ -1,15 +1,20 @@ {- git-annex main program stub  -- - Copyright 2010,2012 Joey Hess <joey@kitenet.net>+ - Copyright 2010-2013 Joey Hess <joey@kitenet.net>  -  - Licensed under the GNU GPL version 3 or higher.  -} +{-# LANGUAGE CPP #-}+ import System.Environment import System.FilePath  import qualified GitAnnex import qualified GitAnnexShell+#ifdef WITH_TESTSUITE+import qualified Test+#endif  main :: IO () main = run =<< getProgName@@ -18,4 +23,12 @@ 		| isshell n = go GitAnnexShell.run 		| otherwise = go GitAnnex.run 	isshell n = takeFileName n == "git-annex-shell"-	go a = a =<< getArgs+	go a = do+		ps <- getArgs+#ifdef WITH_TESTSUITE+		if ps == ["test"]+			then Test.main+			else a ps+#else+		a ps+#endif
+ standalone/android/.gitignore view
@@ -0,0 +1,2 @@+build-utils+start
standalone/android/Makefile view
@@ -1,53 +1,145 @@-# Cross-compiles utilities needed for git-annex on Android.+# Cross-compiles utilities needed for git-annex on Android,+# and builds the Android app.  # Add Android cross-compiler to PATH (as installed by ghc-android)-PATH:=$(HOME)/.ghc/android-14/arm-linux-androideabi-4.7/bin:$(PATH)+# (This directory also needs to have a cc that is a symlink to the prefixed+# gcc cross-compiler executable.)+ANDROID_CROSS_COMPILER?=$(HOME)/.ghc/android-14/arm-linux-androideabi-4.7/bin+PATH:=$(ANDROID_CROSS_COMPILER):$(PATH) -build: source-	mkdir -p git-annex-bundle/bin+# Paths to the Android SDK and NDK.+export ANDROID_SDK_ROOT?=$(HOME)/tmp/adt-bundle-linux-x86/sdk+export ANDROID_NDK_ROOT?=$(HOME)/tmp/android-ndk-r8d++GITTREE=source/git/installed-tree++build: start+	$(MAKE) source/openssl+	$(MAKE) source/openssh+	$(MAKE) source/busybox+	$(MAKE) source/rsync+	$(MAKE) source/gnupg+	$(MAKE) source/git+	$(MAKE) source/term++	# Debug build because it does not need signing keys.+	cd source/term && tools/build-debug++	# Install executables as pseudo-libraries so they will be+	# unpacked from the .apk.+	mkdir -p source/term/libs/armeabi+	cp ../../git-annex source/term/libs/armeabi/lib.git-annex.so+	cp source/busybox/busybox source/term/libs/armeabi/lib.busybox.so+	cp source/openssh/ssh source/term/libs/armeabi/lib.ssh.so+	cp source/openssh/ssh-keygen source/term/libs/armeabi/lib.ssh-keygen.so+	cp source/rsync/rsync source/term/libs/armeabi/lib.rsync.so+	cp source/gnupg/g10/gpg source/term/libs/armeabi/lib.gpg.so+	cp source/git/git source/term/libs/armeabi/lib.git.so+	cp source/git/git-shell source/term/libs/armeabi/lib.git-shell.so+	cp source/git/git-upload-pack source/term/libs/armeabi/lib.git-upload-pack.so+	arm-linux-androideabi-strip --strip-unneeded --remove-section=.comment --remove-section=.note source/term/libs/armeabi/*+	cp runshell source/term/libs/armeabi/lib.runshell.so+	cp start source/term/libs/armeabi/lib.start.so 	-	cd source/git && $(MAKE) install NO_OPENSSL=1 NO_GETTEXT=1 NO_GECOS_IN_PWENT=1 NO_GETPASS=1 NO_NSEC=1 NO_MKDTEMP=1 NO_PTHREADS=1 NO_PERL=1 NO_CURL=1 NO_EXPAT=1 NO_TCLTK=1 NO_ICONV=1 prefix= DESTDIR=../../git-annex-bundle-	rm -f git-annex-bundle/bin/git-cvsserver+	# remove git stuff we don't need to save space+	rm -rf $(GITTREE)/bin/git-cvsserver \+		$(GITTREE)/libexec/git-core/git-daemon \+		$(GITTREE)/libexec/git-core/git-show-index \+		$(GITTREE)/libexec/git-core/mergetools \+		$(GITTREE)/libexec/git-core/git-credential-* \+		$(GITTREE)/libexec/git-core/git-cvsserver \+		$(GITTREE)/libexec/git-core/git-cvsimport \+		$(GITTREE)/libexec/git-core/git-fast-import \+		$(GITTREE)/libexec/git-core/git-http-backend \+		$(GITTREE)/libexec/git-core/git-imap-send \+		$(GITTREE)/libexec/git-core/git-instaweb \+		$(GITTREE)/libexec/git-core/git-p4 \+		$(GITTREE)/libexec/git-core/git-remote-test* \+		$(GITTREE)/libexec/git-core/git-submodule \+		$(GITTREE)/libexec/git-core/git-svn \+		$(GITTREE)/libexec/git-core/git-web--browse+	# Most of git is in one multicall binary, but a few important+	# commands are still shell scripts. Those are put into+	# a tarball, along with a list of all the hard links that should be+	# set up.+	cd $(GITTREE) && mkdir -p links+	cd $(GITTREE) && find -samefile bin/git -not -wholename ./bin/git > links/git+	cd $(GITTREE) && find -samefile bin/git-shell -not -wholename ./bin/git-shell > links/git-shell+	cd $(GITTREE) && find -samefile bin/git-upload-pack -not -wholename ./bin/git-upload-pack > links/git-upload-pack+	cd $(GITTREE) && find -type f -not -samefile bin/git -not -samefile bin/git-shell -not -samefile bin/git-upload-pack|tar czf ../git.tar.gz -T -+	cp source/git/git.tar.gz source/term/libs/armeabi/lib.git.tar.gz.so -	cp source/busybox/configs/android2_defconfig source/busybox/.config-	echo 'CONFIG_FEATURE_INSTALLER=y' >> source/busybox/.config+	git rev-parse HEAD > source/term/libs/armeabi/lib.version.so++	cd source/term && ant debug++source/openssl:+	cd source/openssl && CC=$$(which cc) ./Configure android+	cd source/openssl && $(MAKE)+	touch $@++source/openssh: openssh.patch openssh.config.h+	cd source/openssh && git reset --hard+	cd source/openssh && ./configure --host=arm-linux-androideabi --with-ssl-dir=../openssl --without-openssl-header-check+	cd source/openssh && patch -p1 < ../../openssh.patch+	cp openssh.config.h source/openssh/config.h+	cd source/openssh && sed -i -e 's/getrrsetbyname.o //' openbsd-compat/Makefile+	cd source/openssh && sed -i -e 's/auth-passwd.o //' Makefile+	cd source/openssh && $(MAKE) ssh ssh-keygen+	touch $@++source/busybox: busybox_config+	cp busybox_config source/busybox/.config 	cd source/busybox && yes '' | $(MAKE) oldconfig 	cd source/busybox && $(MAKE)-	cp -a source/busybox/busybox git-annex-bundle/bin/--	cd source/dropbear && git reset --hard origin/master && git am < ../../dropbear.patch-	cp source/automake/lib/config.sub source/automake/lib/config.guess source/dropbear/-	cd source/dropbear && ./configure --host=arm-linux-androideabi --disable-lastlog --disable-utmp --disable-utmpx --disable-wtmp --disable-wtmpx-	cd source/dropbear && $(MAKE) dbclient-	cp -a source/dropbear/dbclient git-annex-bundle/bin/ssh+	touch $@ 	+source/git:+	cd source/git && $(MAKE) install NO_OPENSSL=1 NO_GETTEXT=1 NO_GECOS_IN_PWENT=1 NO_GETPASS=1 NO_NSEC=1 NO_MKDTEMP=1 NO_PTHREADS=1 NO_PERL=1 NO_CURL=1 NO_EXPAT=1 NO_TCLTK=1 NO_ICONV=1 prefix= DESTDIR=installed-tree+	touch $@++source/rsync: rsync.patch 	cd source/rsync && git reset --hard origin/master && git am < ../../rsync.patch 	cp source/automake/lib/config.sub source/automake/lib/config.guess source/rsync/ 	cd source/rsync && ./configure --host=arm-linux-androideabi --disable-locale --disable-iconv-open --disable-iconv --disable-acl-support --disable-xattr-support 	cd source/rsync && $(MAKE)-	cp -a source/rsync/rsync git-annex-bundle/bin/+	touch $@ +source/gnupg: 	cd source/gnupg && git checkout gnupg-1.4.13 	cd source/gnupg && ./autogen.sh 	cd source/gnupg && ./configure --host=arm-linux-androideabi --disable-gnupg-iconv --enable-minimal --disable-card-support --disable-agent-support --disable-photo-viewers --disable-keyserver-helpers --disable-nls 	cd source/gnupg; $(MAKE) || true # expected failure in doc build-	cp -a source/gnupg/g10/gpg git-annex-bundle/bin/+	touch $@ +source/term: term.patch icons+	cd source/term && git reset --hard+	cd source/term && patch -p1 <../../term.patch+	(cd icons && tar c .) | (cd source/term/res && tar x)+	# This renaming has a purpose. It makes the path to the app's+	# /data directory shorter, which makes ssh connection caching+	# sockets placed there have more space for their filenames.+	# Also, it avoids overlap with the Android Terminal Emulator+	# app, if it's also installed.+	cd source/term && find -name .git -prune -o -type f -print0 | xargs -0 perl -pi -e 's/jackpal/ga/g'+	cd source/term && perl -pi -e 's/Terminal Emulator/Git Annex/g' res/*/strings.xml+	cd source/term && tools/update.sh >/dev/null 2>&1+	touch $@+ source: 	mkdir -p source-	git clone git://git.savannah.gnu.org/automake.git source/automake-	git clone git://git.debian.org/git/d-i/busybox source/busybox-	git clone git://github.com/android/platform_external_dropbear source/dropbear-	git clone git://git.kernel.org/pub/scm/git/git.git source/git-	git clone git://git.samba.org/rsync.git source/rsync-	git clone git://git.gnupg.org/gnupg.git source/gnupg+	git clone --bare git://git.savannah.gnu.org/automake.git source/automake+	git clone --bare git://git.debian.org/git/d-i/busybox source/busybox+	git clone --bare git://git.kernel.org/pub/scm/git/git.git source/git+	git clone --bare git://git.samba.org/rsync.git source/rsync+	git clone --bare git://git.gnupg.org/gnupg.git source/gnupg+	git clone --bare git://git.openssl.org/openssl source/openssl+	git clone --bare git://github.com/CyanogenMod/android_external_openssh.git source/openssh+	git clone --bare git://github.com/jackpal/Android-Terminal-Emulator.git source/term  clean:-	cd source/busybox && $(MAKE) clean-	cd source/dropbear && $(MAKE) clean-	cd source/git && $(MAKE) clean-	cd source/rsync && $(MAKE) clean-	cd source/gnupg && $(MAKE) clean+	rm -rf $(GITTREE)+	rm -f start -reallyclean:+reallyclean: clean 	rm -rf source
+ standalone/android/busybox_config view
@@ -0,0 +1,997 @@+# Run "make android2_defconfig", then "make".+#+# Tested with the standalone toolchain from ndk r6:+# android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-8+#+CONFIG_HAVE_DOT_CONFIG=y++#+# Busybox Settings+#++#+# General Configuration+#+# CONFIG_DESKTOP is not set+# CONFIG_EXTRA_COMPAT is not set+# CONFIG_INCLUDE_SUSv2 is not set+# CONFIG_USE_PORTABLE_CODE is not set+CONFIG_PLATFORM_LINUX=y+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set+# CONFIG_SHOW_USAGE is not set+# CONFIG_FEATURE_VERBOSE_USAGE is not set+# CONFIG_FEATURE_COMPRESS_USAGE is not set+CONFIG_FEATURE_INSTALLER=y+# CONFIG_INSTALL_NO_USR is not set+# CONFIG_LOCALE_SUPPORT is not set+# CONFIG_UNICODE_SUPPORT is not set+# CONFIG_UNICODE_USING_LOCALE is not set+# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set+CONFIG_SUBST_WCHAR=0+CONFIG_LAST_SUPPORTED_WCHAR=0+# CONFIG_UNICODE_COMBINING_WCHARS is not set+# CONFIG_UNICODE_WIDE_WCHARS is not set+# CONFIG_UNICODE_BIDI_SUPPORT is not set+# CONFIG_UNICODE_NEUTRAL_TABLE is not set+# CONFIG_UNICODE_PRESERVE_BROKEN is not set+# CONFIG_LONG_OPTS is not set+# CONFIG_FEATURE_DEVPTS is not set+# CONFIG_FEATURE_CLEAN_UP is not set+# CONFIG_FEATURE_UTMP is not set+# CONFIG_FEATURE_WTMP is not set+# CONFIG_FEATURE_PIDFILE is not set+# CONFIG_FEATURE_SUID is not set+# CONFIG_FEATURE_SUID_CONFIG is not set+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set+# CONFIG_SELINUX is not set+# CONFIG_FEATURE_PREFER_APPLETS is not set+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"+CONFIG_FEATURE_SYSLOG=y+# CONFIG_FEATURE_HAVE_RPC is not set++#+# Build Options+#+# CONFIG_STATIC is not set+# CONFIG_PIE is not set+# CONFIG_NOMMU is not set+# CONFIG_BUILD_LIBBUSYBOX is not set+# CONFIG_FEATURE_INDIVIDUAL is not set+# CONFIG_FEATURE_SHARED_BUSYBOX is not set+# CONFIG_LFS is not set+CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-"+CONFIG_EXTRA_CFLAGS=""++#+# Debugging Options+#+# CONFIG_DEBUG is not set+# CONFIG_DEBUG_PESSIMIZE is not set+# CONFIG_WERROR is not set+CONFIG_NO_DEBUG_LIB=y+# CONFIG_DMALLOC is not set+# CONFIG_EFENCE is not set++#+# Installation Options ("make install" behavior)+#+CONFIG_INSTALL_APPLET_SYMLINKS=y+# CONFIG_INSTALL_APPLET_HARDLINKS is not set+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set+# CONFIG_INSTALL_APPLET_DONT is not set+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set+CONFIG_PREFIX="./_install"++#+# Busybox Library Tuning+#+# CONFIG_FEATURE_SYSTEMD is not set+# CONFIG_FEATURE_RTMINMAX is not set+CONFIG_PASSWORD_MINLEN=6+CONFIG_MD5_SMALL=1+# CONFIG_FEATURE_FAST_TOP is not set+# CONFIG_FEATURE_ETC_NETWORKS is not set+CONFIG_FEATURE_USE_TERMIOS=y+# CONFIG_FEATURE_EDITING is not set+CONFIG_FEATURE_EDITING_MAX_LEN=0+# CONFIG_FEATURE_EDITING_VI is not set+CONFIG_FEATURE_EDITING_HISTORY=0+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set+# CONFIG_FEATURE_TAB_COMPLETION is not set+# CONFIG_FEATURE_USERNAME_COMPLETION is not set+# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set+# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set+# CONFIG_FEATURE_NON_POSIX_CP is not set+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set+CONFIG_FEATURE_COPYBUF_KB=4+# CONFIG_FEATURE_SKIP_ROOTFS is not set+# CONFIG_MONOTONIC_SYSCALL is not set+# CONFIG_IOCTL_HEX2STR_ERROR is not set+# CONFIG_FEATURE_HWIB is not set++#+# Applets+#++#+# Archival Utilities+#+CONFIG_FEATURE_SEAMLESS_XZ=y+CONFIG_FEATURE_SEAMLESS_LZMA=y+CONFIG_FEATURE_SEAMLESS_BZ2=y+CONFIG_FEATURE_SEAMLESS_GZ=y+CONFIG_FEATURE_SEAMLESS_Z=y+CONFIG_AR=y+CONFIG_FEATURE_AR_LONG_FILENAMES=y+CONFIG_FEATURE_AR_CREATE=y+CONFIG_BUNZIP2=y+CONFIG_BZIP2=y+CONFIG_CPIO=y+CONFIG_FEATURE_CPIO_O=y+CONFIG_FEATURE_CPIO_P=y+CONFIG_DPKG=y+CONFIG_DPKG_DEB=y+# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set+CONFIG_GUNZIP=y+CONFIG_GZIP=y+# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set+CONFIG_LZOP=y+CONFIG_LZOP_COMPR_HIGH=y+CONFIG_RPM2CPIO=y+CONFIG_RPM=y+CONFIG_TAR=y+CONFIG_FEATURE_TAR_CREATE=y+CONFIG_FEATURE_TAR_AUTODETECT=y+CONFIG_FEATURE_TAR_FROM=y+CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y+CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set+# CONFIG_FEATURE_TAR_TO_COMMAND is not set+CONFIG_FEATURE_TAR_UNAME_GNAME=y+CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y+# CONFIG_FEATURE_TAR_SELINUX is not set+CONFIG_UNCOMPRESS=y+CONFIG_UNLZMA=y+CONFIG_FEATURE_LZMA_FAST=y+CONFIG_LZMA=y+CONFIG_UNXZ=y+CONFIG_XZ=y+CONFIG_UNZIP=y++#+# Coreutils+#+CONFIG_BASENAME=y+CONFIG_CAT=y+# CONFIG_DATE is not set+# CONFIG_FEATURE_DATE_ISOFMT is not set+# CONFIG_FEATURE_DATE_NANO is not set+# CONFIG_FEATURE_DATE_COMPAT is not set+# CONFIG_ID is not set+# CONFIG_GROUPS is not set+CONFIG_TEST=y+CONFIG_FEATURE_TEST_64=y+CONFIG_TOUCH=y+CONFIG_TR=y+CONFIG_FEATURE_TR_CLASSES=y+CONFIG_FEATURE_TR_EQUIV=y+CONFIG_BASE64=y+CONFIG_CAL=y+CONFIG_CATV=y+CONFIG_CHGRP=y+CONFIG_CHMOD=y+CONFIG_CHOWN=y+# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set+CONFIG_CHROOT=y+CONFIG_CKSUM=y+CONFIG_COMM=y+CONFIG_CP=y+# CONFIG_FEATURE_CP_LONG_OPTIONS is not set+CONFIG_CUT=y+CONFIG_DD=y+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y+CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y+CONFIG_FEATURE_DD_IBS_OBS=y+# CONFIG_DF is not set+# CONFIG_FEATURE_DF_FANCY is not set+CONFIG_DIRNAME=y+CONFIG_DOS2UNIX=y+CONFIG_UNIX2DOS=y+CONFIG_DU=y+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y+CONFIG_ECHO=y+CONFIG_FEATURE_FANCY_ECHO=y+# CONFIG_ENV is not set+# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set+CONFIG_EXPAND=y+# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set+# CONFIG_EXPR is not set+# CONFIG_EXPR_MATH_SUPPORT_64 is not set+CONFIG_FALSE=y+CONFIG_FOLD=y+# CONFIG_FSYNC is not set+CONFIG_HEAD=y+CONFIG_FEATURE_FANCY_HEAD=y+# CONFIG_HOSTID is not set+CONFIG_INSTALL=y+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set+CONFIG_LN=y+# CONFIG_LOGNAME is not set+CONFIG_LS=y+CONFIG_FEATURE_LS_FILETYPES=y+CONFIG_FEATURE_LS_FOLLOWLINKS=y+CONFIG_FEATURE_LS_RECURSIVE=y+CONFIG_FEATURE_LS_SORTFILES=y+CONFIG_FEATURE_LS_TIMESTAMPS=y+CONFIG_FEATURE_LS_USERNAME=y+# CONFIG_FEATURE_LS_COLOR is not set+# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set+CONFIG_MD5SUM=y+CONFIG_MKDIR=y+# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set+CONFIG_MKFIFO=y+CONFIG_MKNOD=y+CONFIG_MV=y+# CONFIG_FEATURE_MV_LONG_OPTIONS is not set+CONFIG_NICE=y+CONFIG_NOHUP=y+CONFIG_OD=y+CONFIG_PRINTENV=y+CONFIG_PRINTF=y+CONFIG_PWD=y+CONFIG_READLINK=y+CONFIG_FEATURE_READLINK_FOLLOW=y+CONFIG_REALPATH=y+CONFIG_RM=y+CONFIG_RMDIR=y+# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set+CONFIG_SEQ=y+CONFIG_SHA1SUM=y+CONFIG_SHA256SUM=y+CONFIG_SHA512SUM=y+CONFIG_SLEEP=y+CONFIG_FEATURE_FANCY_SLEEP=y+CONFIG_FEATURE_FLOAT_SLEEP=y+CONFIG_SORT=y+CONFIG_FEATURE_SORT_BIG=y+CONFIG_SPLIT=y+CONFIG_FEATURE_SPLIT_FANCY=y+# CONFIG_STAT is not set+# CONFIG_FEATURE_STAT_FORMAT is not set+CONFIG_STTY=y+CONFIG_SUM=y+CONFIG_SYNC=y+CONFIG_TAC=y+CONFIG_TAIL=y+CONFIG_FEATURE_FANCY_TAIL=y+CONFIG_TEE=y+CONFIG_FEATURE_TEE_USE_BLOCK_IO=y+CONFIG_TRUE=y+# CONFIG_TTY is not set+CONFIG_UNAME=y+CONFIG_UNEXPAND=y+# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set+CONFIG_UNIQ=y+# CONFIG_USLEEP is not set+CONFIG_UUDECODE=y+CONFIG_UUENCODE=y+CONFIG_WC=y+CONFIG_FEATURE_WC_LARGE=y+# CONFIG_WHO is not set+CONFIG_WHOAMI=y+CONFIG_YES=y++#+# Common options for cp and mv+#+CONFIG_FEATURE_PRESERVE_HARDLINKS=y++#+# Common options for ls, more and telnet+#+CONFIG_FEATURE_AUTOWIDTH=y++#+# Common options for df, du, ls+#+CONFIG_FEATURE_HUMAN_READABLE=y++#+# Common options for md5sum, sha1sum, sha256sum, sha512sum+#+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y++#+# Console Utilities+#+CONFIG_CHVT=y+CONFIG_FGCONSOLE=y+CONFIG_CLEAR=y+CONFIG_DEALLOCVT=y+CONFIG_DUMPKMAP=y+# CONFIG_KBD_MODE is not set+# CONFIG_LOADFONT is not set+CONFIG_LOADKMAP=y+CONFIG_OPENVT=y+CONFIG_RESET=y+CONFIG_RESIZE=y+CONFIG_FEATURE_RESIZE_PRINT=y+CONFIG_SETCONSOLE=y+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set+# CONFIG_SETFONT is not set+# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set+CONFIG_DEFAULT_SETFONT_DIR=""+CONFIG_SETKEYCODES=y+CONFIG_SETLOGCONS=y+CONFIG_SHOWKEY=y+# CONFIG_FEATURE_LOADFONT_PSF2 is not set+# CONFIG_FEATURE_LOADFONT_RAW is not set++#+# Debian Utilities+#+CONFIG_MKTEMP=y+CONFIG_PIPE_PROGRESS=y+CONFIG_RUN_PARTS=y+# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set+CONFIG_FEATURE_RUN_PARTS_FANCY=y+CONFIG_START_STOP_DAEMON=y+CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set+CONFIG_WHICH=y++#+# Editors+#+CONFIG_PATCH=y+CONFIG_VI=y+CONFIG_FEATURE_VI_MAX_LEN=0+# CONFIG_FEATURE_VI_8BIT is not set+# CONFIG_FEATURE_VI_COLON is not set+# CONFIG_FEATURE_VI_YANKMARK is not set+CONFIG_FEATURE_VI_SEARCH=y+# CONFIG_FEATURE_VI_REGEX_SEARCH is not set+CONFIG_FEATURE_VI_USE_SIGNALS=y+# CONFIG_FEATURE_VI_DOT_CMD is not set+# CONFIG_FEATURE_VI_READONLY is not set+# CONFIG_FEATURE_VI_SETOPTS is not set+# CONFIG_FEATURE_VI_SET is not set+CONFIG_FEATURE_VI_WIN_RESIZE=y+# CONFIG_FEATURE_VI_ASK_TERMINAL is not set+# CONFIG_FEATURE_VI_OPTIMIZE_CURSOR is not set+# CONFIG_AWK is not set+# CONFIG_FEATURE_AWK_LIBM is not set+CONFIG_CMP=y+CONFIG_DIFF=y+# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set+CONFIG_FEATURE_DIFF_DIR=y+# CONFIG_ED is not set+CONFIG_SED=y+# CONFIG_FEATURE_ALLOW_EXEC is not set++#+# Finding Utilities+#+CONFIG_FIND=y+CONFIG_FEATURE_FIND_PRINT0=y+CONFIG_FEATURE_FIND_MTIME=y+# CONFIG_FEATURE_FIND_MMIN is not set+CONFIG_FEATURE_FIND_PERM=y+CONFIG_FEATURE_FIND_TYPE=y+# CONFIG_FEATURE_FIND_XDEV is not set+# CONFIG_FEATURE_FIND_MAXDEPTH is not set+# CONFIG_FEATURE_FIND_NEWER is not set+# CONFIG_FEATURE_FIND_INUM is not set+# CONFIG_FEATURE_FIND_EXEC is not set+# CONFIG_FEATURE_FIND_USER is not set+# CONFIG_FEATURE_FIND_GROUP is not set+# CONFIG_FEATURE_FIND_NOT is not set+# CONFIG_FEATURE_FIND_DEPTH is not set+# CONFIG_FEATURE_FIND_PAREN is not set+# CONFIG_FEATURE_FIND_SIZE is not set+# CONFIG_FEATURE_FIND_PRUNE is not set+# CONFIG_FEATURE_FIND_DELETE is not set+# CONFIG_FEATURE_FIND_PATH is not set+# CONFIG_FEATURE_FIND_REGEX is not set+# CONFIG_FEATURE_FIND_CONTEXT is not set+# CONFIG_FEATURE_FIND_LINKS is not set+CONFIG_GREP=y+# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set+# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set+# CONFIG_FEATURE_GREP_CONTEXT is not set+CONFIG_XARGS=y+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y+CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y++#+# Init Utilities+#+# CONFIG_BOOTCHARTD is not set+# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set+# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set+# CONFIG_HALT is not set+# CONFIG_FEATURE_CALL_TELINIT is not set+# CONFIG_TELINIT_PATH=""+# CONFIG_INIT is not set+# CONFIG_FEATURE_USE_INITTAB is not set+# CONFIG_FEATURE_KILL_REMOVED is not set+# CONFIG_FEATURE_KILL_DELAY=0+# CONFIG_FEATURE_INIT_SCTTY is not set+# CONFIG_FEATURE_INIT_SYSLOG is not set+# CONFIG_FEATURE_EXTRA_QUIET is not set+# CONFIG_FEATURE_INIT_COREDUMPS is not set+# CONFIG_FEATURE_INITRD is not set+# CONFIG_INIT_TERMINAL_TYPE="linux"+# CONFIG_MESG is not set+# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y++#+# Login/Password Management Utilities+#+# CONFIG_ADD_SHELL is not set+# CONFIG_REMOVE_SHELL is not set+# CONFIG_FEATURE_SHADOWPASSWDS is not set+# CONFIG_USE_BB_PWD_GRP is not set+# CONFIG_USE_BB_SHADOW is not set+# CONFIG_USE_BB_CRYPT is not set+# CONFIG_USE_BB_CRYPT_SHA is not set+# CONFIG_ADDUSER is not set+# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set+# CONFIG_FEATURE_CHECK_NAMES is not set+CONFIG_FIRST_SYSTEM_ID=0+CONFIG_LAST_SYSTEM_ID=0+# CONFIG_ADDGROUP is not set+# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set+# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set+# CONFIG_DELUSER is not set+# CONFIG_DELGROUP is not set+# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set+# CONFIG_GETTY is not set+# CONFIG_LOGIN is not set+# CONFIG_PAM is not set+# CONFIG_LOGIN_SCRIPTS is not set+# CONFIG_FEATURE_NOLOGIN is not set+# CONFIG_FEATURE_SECURETTY is not set+# CONFIG_PASSWD is not set+# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set+# CONFIG_CRYPTPW is not set+# CONFIG_CHPASSWD is not set+# CONFIG_SU is not set+# CONFIG_FEATURE_SU_SYSLOG is not set+# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set+# CONFIG_SULOGIN is not set+# CONFIG_VLOCK is not set++#+# Linux Ext2 FS Progs+#+CONFIG_CHATTR=y+# CONFIG_FSCK is not set+CONFIG_LSATTR=y+CONFIG_TUNE2FS=y++#+# Linux Module Utilities+#+# CONFIG_MODINFO is not set+# CONFIG_MODPROBE_SMALL is not set+# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y+# CONFIG_INSMOD is not set+# CONFIG_RMMOD is not set+# CONFIG_LSMOD is not set+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set+# CONFIG_MODPROBE is not set+# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set+# CONFIG_DEPMOD is not set++#+# Options common to multiple modutils+#+# CONFIG_FEATURE_2_4_MODULES is not set+# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set+# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set+# CONFIG_FEATURE_MODUTILS_ALIAS is not set+# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set+# CONFIG_DEFAULT_MODULES_DIR="/lib/modules"+# CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"++#+# Linux System Utilities+#+CONFIG_BLOCKDEV=y+CONFIG_REV=y+# CONFIG_ACPID is not set+# CONFIG_FEATURE_ACPID_COMPAT is not set+CONFIG_BLKID=y+# CONFIG_FEATURE_BLKID_TYPE is not set+CONFIG_DMESG=y+CONFIG_FEATURE_DMESG_PRETTY=y+CONFIG_FBSET=y+CONFIG_FEATURE_FBSET_FANCY=y+CONFIG_FEATURE_FBSET_READMODE=y+CONFIG_FDFLUSH=y+CONFIG_FDFORMAT=y+CONFIG_FDISK=y+CONFIG_FDISK_SUPPORT_LARGE_DISKS=y+CONFIG_FEATURE_FDISK_WRITABLE=y+# CONFIG_FEATURE_AIX_LABEL is not set+# CONFIG_FEATURE_SGI_LABEL is not set+# CONFIG_FEATURE_SUN_LABEL is not set+# CONFIG_FEATURE_OSF_LABEL is not set+# CONFIG_FEATURE_GPT_LABEL is not set+CONFIG_FEATURE_FDISK_ADVANCED=y+CONFIG_FINDFS=y+CONFIG_FLOCK=y+CONFIG_FREERAMDISK=y+# CONFIG_FSCK_MINIX is not set+# CONFIG_MKFS_EXT2 is not set+# CONFIG_MKFS_MINIX is not set+# CONFIG_FEATURE_MINIX2 is not set+# CONFIG_MKFS_REISER is not set+# CONFIG_MKFS_VFAT is not set+CONFIG_GETOPT=y+CONFIG_FEATURE_GETOPT_LONG=y+CONFIG_HEXDUMP=y+CONFIG_FEATURE_HEXDUMP_REVERSE=y+CONFIG_HD=y+# CONFIG_HWCLOCK is not set+# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set+# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set+# CONFIG_IPCRM is not set+# CONFIG_IPCS is not set+CONFIG_LOSETUP=y+CONFIG_LSPCI=y+CONFIG_LSUSB=y+# CONFIG_MDEV is not set+# CONFIG_FEATURE_MDEV_CONF is not set+# CONFIG_FEATURE_MDEV_RENAME is not set+# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set+# CONFIG_FEATURE_MDEV_EXEC is not set+# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set+CONFIG_MKSWAP=y+CONFIG_FEATURE_MKSWAP_UUID=y+CONFIG_MORE=y+# CONFIG_MOUNT is not set+# CONFIG_FEATURE_MOUNT_FAKE is not set+# CONFIG_FEATURE_MOUNT_VERBOSE is not set+# CONFIG_FEATURE_MOUNT_HELPERS is not set+# CONFIG_FEATURE_MOUNT_LABEL is not set+# CONFIG_FEATURE_MOUNT_NFS is not set+# CONFIG_FEATURE_MOUNT_CIFS is not set+# CONFIG_FEATURE_MOUNT_FLAGS is not set+# CONFIG_FEATURE_MOUNT_FSTAB is not set+# CONFIG_PIVOT_ROOT is not set+# CONFIG_RDATE is not set+CONFIG_RDEV=y+CONFIG_READPROFILE=y+CONFIG_RTCWAKE=y+CONFIG_SCRIPT=y+CONFIG_SCRIPTREPLAY=y+# CONFIG_SETARCH is not set+# CONFIG_SWAPONOFF is not set+# CONFIG_FEATURE_SWAPON_PRI is not set+# CONFIG_SWITCH_ROOT is not set+# CONFIG_UMOUNT is not set+# CONFIG_FEATURE_UMOUNT_ALL is not set+# CONFIG_FEATURE_MOUNT_LOOP is not set+# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set+# CONFIG_FEATURE_MTAB_SUPPORT is not set+CONFIG_VOLUMEID=y++#+# Filesystem/Volume identification+#+CONFIG_FEATURE_VOLUMEID_EXT=y+CONFIG_FEATURE_VOLUMEID_BTRFS=y+CONFIG_FEATURE_VOLUMEID_REISERFS=y+CONFIG_FEATURE_VOLUMEID_FAT=y+CONFIG_FEATURE_VOLUMEID_HFS=y+CONFIG_FEATURE_VOLUMEID_JFS=y+CONFIG_FEATURE_VOLUMEID_XFS=y+CONFIG_FEATURE_VOLUMEID_NTFS=y+CONFIG_FEATURE_VOLUMEID_ISO9660=y+CONFIG_FEATURE_VOLUMEID_UDF=y+CONFIG_FEATURE_VOLUMEID_LUKS=y+CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y+CONFIG_FEATURE_VOLUMEID_CRAMFS=y+CONFIG_FEATURE_VOLUMEID_ROMFS=y+CONFIG_FEATURE_VOLUMEID_SYSV=y+CONFIG_FEATURE_VOLUMEID_OCFS2=y+CONFIG_FEATURE_VOLUMEID_LINUXRAID=y++#+# Miscellaneous Utilities+#+# CONFIG_CONSPY is not set+# CONFIG_NANDWRITE is not set+CONFIG_NANDDUMP=y+CONFIG_SETSERIAL=y+# CONFIG_UBIATTACH is not set+# CONFIG_UBIDETACH is not set+# CONFIG_UBIMKVOL is not set+# CONFIG_UBIRMVOL is not set+# CONFIG_UBIRSVOL is not set+# CONFIG_UBIUPDATEVOL is not set+# CONFIG_ADJTIMEX is not set+# CONFIG_BBCONFIG is not set+# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set+CONFIG_BEEP=y+CONFIG_FEATURE_BEEP_FREQ=4000+CONFIG_FEATURE_BEEP_LENGTH_MS=30+CONFIG_CHAT=y+CONFIG_FEATURE_CHAT_NOFAIL=y+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set+CONFIG_FEATURE_CHAT_IMPLICIT_CR=y+CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y+CONFIG_FEATURE_CHAT_SEND_ESCAPES=y+CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y+CONFIG_FEATURE_CHAT_CLR_ABORT=y+CONFIG_CHRT=y+# CONFIG_CROND is not set+# CONFIG_FEATURE_CROND_D is not set+# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set+CONFIG_FEATURE_CROND_DIR=""+# CONFIG_CRONTAB is not set+CONFIG_DC=y+CONFIG_FEATURE_DC_LIBM=y+# CONFIG_DEVFSD is not set+# CONFIG_DEVFSD_MODLOAD is not set+# CONFIG_DEVFSD_FG_NP is not set+# CONFIG_DEVFSD_VERBOSE is not set+# CONFIG_FEATURE_DEVFS is not set+CONFIG_DEVMEM=y+# CONFIG_EJECT is not set+# CONFIG_FEATURE_EJECT_SCSI is not set+CONFIG_FBSPLASH=y+CONFIG_FLASHCP=y+CONFIG_FLASH_LOCK=y+CONFIG_FLASH_UNLOCK=y+# CONFIG_FLASH_ERASEALL is not set+# CONFIG_IONICE is not set+CONFIG_INOTIFYD=y+# CONFIG_LAST is not set+# CONFIG_FEATURE_LAST_SMALL is not set+# CONFIG_FEATURE_LAST_FANCY is not set+# CONFIG_LESS is not set+CONFIG_FEATURE_LESS_MAXLINES=0+# CONFIG_FEATURE_LESS_BRACKETS is not set+# CONFIG_FEATURE_LESS_FLAGS is not set+# CONFIG_FEATURE_LESS_MARKS is not set+# CONFIG_FEATURE_LESS_REGEXP is not set+# CONFIG_FEATURE_LESS_WINCH is not set+# CONFIG_FEATURE_LESS_DASHCMD is not set+# CONFIG_FEATURE_LESS_LINENUMS is not set+CONFIG_HDPARM=y+CONFIG_FEATURE_HDPARM_GET_IDENTITY=y+CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y+CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y+CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y+CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y+CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y+CONFIG_MAKEDEVS=y+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set+CONFIG_FEATURE_MAKEDEVS_TABLE=y+CONFIG_MAN=y+# CONFIG_MICROCOM is not set+# CONFIG_MOUNTPOINT is not set+# CONFIG_MT is not set+CONFIG_RAIDAUTORUN=y+# CONFIG_READAHEAD is not set+# CONFIG_RFKILL is not set+# CONFIG_RUNLEVEL is not set+CONFIG_RX=y+CONFIG_SETSID=y+CONFIG_STRINGS=y+# CONFIG_TASKSET is not set+# CONFIG_FEATURE_TASKSET_FANCY is not set+CONFIG_TIME=y+CONFIG_TIMEOUT=y+CONFIG_TTYSIZE=y+CONFIG_VOLNAME=y+# CONFIG_WALL is not set+# CONFIG_WATCHDOG is not set++#+# Networking Utilities+#+# CONFIG_NAMEIF is not set+# CONFIG_FEATURE_NAMEIF_EXTENDED is not set+CONFIG_NBDCLIENT=y+CONFIG_NC=y+CONFIG_NC_SERVER=y+CONFIG_NC_EXTRA=y+# CONFIG_NC_110_COMPAT is not set+# CONFIG_PING is not set+# CONFIG_PING6 is not set+# CONFIG_FEATURE_FANCY_PING is not set+CONFIG_WHOIS=y+# CONFIG_FEATURE_IPV6 is not set+# CONFIG_FEATURE_UNIX_LOCAL is not set+# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set+# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set+CONFIG_ARP=y+# CONFIG_ARPING is not set+# CONFIG_BRCTL is not set+# CONFIG_FEATURE_BRCTL_FANCY is not set+# CONFIG_FEATURE_BRCTL_SHOW is not set+CONFIG_DNSD=y+# CONFIG_ETHER_WAKE is not set+CONFIG_FAKEIDENTD=y+CONFIG_FTPD=y+CONFIG_FEATURE_FTP_WRITE=y+CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y+CONFIG_FTPGET=y+CONFIG_FTPPUT=y+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set+# CONFIG_HOSTNAME is not set+CONFIG_HTTPD=y+CONFIG_FEATURE_HTTPD_RANGES=y+CONFIG_FEATURE_HTTPD_USE_SENDFILE=y+CONFIG_FEATURE_HTTPD_SETUID=y+CONFIG_FEATURE_HTTPD_BASIC_AUTH=y+# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set+CONFIG_FEATURE_HTTPD_CGI=y+CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y+CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y+CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y+CONFIG_FEATURE_HTTPD_ERROR_PAGES=y+CONFIG_FEATURE_HTTPD_PROXY=y+CONFIG_FEATURE_HTTPD_GZIP=y+CONFIG_IFCONFIG=y+CONFIG_FEATURE_IFCONFIG_STATUS=y+# CONFIG_FEATURE_IFCONFIG_SLIP is not set+CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y+CONFIG_FEATURE_IFCONFIG_HW=y+CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y+# CONFIG_IFENSLAVE is not set+# CONFIG_IFPLUGD is not set+CONFIG_IFUPDOWN=y+CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"+CONFIG_FEATURE_IFUPDOWN_IP=y+CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y+# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set+CONFIG_FEATURE_IFUPDOWN_IPV4=y+# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set+CONFIG_FEATURE_IFUPDOWN_MAPPING=y+# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set+# CONFIG_INETD is not set+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set+# CONFIG_FEATURE_INETD_RPC is not set+CONFIG_IP=y+CONFIG_FEATURE_IP_ADDRESS=y+CONFIG_FEATURE_IP_LINK=y+CONFIG_FEATURE_IP_ROUTE=y+CONFIG_FEATURE_IP_TUNNEL=y+CONFIG_FEATURE_IP_RULE=y+CONFIG_FEATURE_IP_SHORT_FORMS=y+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set+CONFIG_IPADDR=y+CONFIG_IPLINK=y+CONFIG_IPROUTE=y+CONFIG_IPTUNNEL=y+CONFIG_IPRULE=y+CONFIG_IPCALC=y+CONFIG_FEATURE_IPCALC_FANCY=y+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set+CONFIG_NETSTAT=y+CONFIG_FEATURE_NETSTAT_WIDE=y+CONFIG_FEATURE_NETSTAT_PRG=y+# CONFIG_NSLOOKUP is not set+# CONFIG_NTPD is not set+# CONFIG_FEATURE_NTPD_SERVER is not set+CONFIG_PSCAN=y+CONFIG_ROUTE=y+# CONFIG_SLATTACH is not set+CONFIG_TCPSVD=y+# CONFIG_TELNET is not set+# CONFIG_FEATURE_TELNET_TTYPE is not set+# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set+# CONFIG_TELNETD is not set+# CONFIG_FEATURE_TELNETD_STANDALONE is not set+# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set+# CONFIG_TFTP is not set+# CONFIG_TFTPD is not set+# CONFIG_FEATURE_TFTP_GET is not set+# CONFIG_FEATURE_TFTP_PUT is not set+# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set+# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set+# CONFIG_TFTP_DEBUG is not set+# CONFIG_TRACEROUTE is not set+# CONFIG_TRACEROUTE6 is not set+# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set+# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set+# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set+CONFIG_TUNCTL=y+CONFIG_FEATURE_TUNCTL_UG=y+# CONFIG_UDHCPD is not set+# CONFIG_DHCPRELAY is not set+# CONFIG_DUMPLEASES is not set+# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set+# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set+CONFIG_DHCPD_LEASES_FILE=""+CONFIG_UDHCPC=y+CONFIG_FEATURE_UDHCPC_ARPING=y+# CONFIG_FEATURE_UDHCP_PORT is not set+CONFIG_UDHCP_DEBUG=9+CONFIG_FEATURE_UDHCP_RFC3397=y+CONFIG_FEATURE_UDHCP_8021Q=y+CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80+CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n"+# CONFIG_UDPSVD is not set+# CONFIG_VCONFIG is not set+CONFIG_WGET=y+CONFIG_FEATURE_WGET_STATUSBAR=y+CONFIG_FEATURE_WGET_AUTHENTICATION=y+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set+CONFIG_FEATURE_WGET_TIMEOUT=y+# CONFIG_ZCIP is not set++#+# Print Utilities+#+CONFIG_LPD=y+CONFIG_LPR=y+CONFIG_LPQ=y++#+# Mail Utilities+#+CONFIG_MAKEMIME=y+CONFIG_FEATURE_MIME_CHARSET="us-ascii"+CONFIG_POPMAILDIR=y+CONFIG_FEATURE_POPMAILDIR_DELIVERY=y+CONFIG_REFORMIME=y+CONFIG_FEATURE_REFORMIME_COMPAT=y+CONFIG_SENDMAIL=y++#+# Process Utilities+#+CONFIG_IOSTAT=y+CONFIG_MPSTAT=y+CONFIG_NMETER=y+CONFIG_PMAP=y+# CONFIG_POWERTOP is not set+CONFIG_PSTREE=y+CONFIG_PWDX=y+CONFIG_SMEMCAP=y+# CONFIG_FREE is not set+CONFIG_FUSER=y+# CONFIG_KILL is not set+# CONFIG_KILLALL is not set+# CONFIG_KILLALL5 is not set+# CONFIG_PGREP is not set+CONFIG_PIDOF=y+CONFIG_FEATURE_PIDOF_SINGLE=y+CONFIG_FEATURE_PIDOF_OMIT=y+# CONFIG_PKILL is not set+# CONFIG_PS is not set+# CONFIG_FEATURE_PS_WIDE is not set+# CONFIG_FEATURE_PS_TIME is not set+# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set+CONFIG_RENICE=y+CONFIG_BB_SYSCTL=y+CONFIG_TOP=y+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y+CONFIG_FEATURE_TOP_SMP_CPU=y+CONFIG_FEATURE_TOP_DECIMALS=y+CONFIG_FEATURE_TOP_SMP_PROCESS=y+CONFIG_FEATURE_TOPMEM=y+CONFIG_FEATURE_SHOW_THREADS=y+# CONFIG_UPTIME is not set+CONFIG_WATCH=y++#+# Runit Utilities+#+CONFIG_RUNSV=y+CONFIG_RUNSVDIR=y+# CONFIG_FEATURE_RUNSVDIR_LOG is not set+CONFIG_SV=y+CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service"+CONFIG_SVLOGD=y+CONFIG_CHPST=y+CONFIG_SETUIDGID=y+CONFIG_ENVUIDGID=y+CONFIG_ENVDIR=y+CONFIG_SOFTLIMIT=y+# CONFIG_CHCON is not set+# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set+# CONFIG_GETENFORCE is not set+# CONFIG_GETSEBOOL is not set+# CONFIG_LOAD_POLICY is not set+# CONFIG_MATCHPATHCON is not set+# CONFIG_RESTORECON is not set+# CONFIG_RUNCON is not set+# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set+# CONFIG_SELINUXENABLED is not set+# CONFIG_SETENFORCE is not set+# CONFIG_SETFILES is not set+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set+# CONFIG_SETSEBOOL is not set+# CONFIG_SESTATUS is not set++#+# Shells+#+CONFIG_ASH=y+# CONFIG_ASH_BASH_COMPAT is not set+# CONFIG_ASH_IDLE_TIMEOUT is not set+CONFIG_ASH_JOB_CONTROL=y+# CONFIG_ASH_ALIAS is not set+CONFIG_ASH_GETOPTS=y+# CONFIG_ASH_BUILTIN_ECHO is not set+# CONFIG_ASH_BUILTIN_PRINTF is not set+# CONFIG_ASH_BUILTIN_TEST is not set+# CONFIG_ASH_CMDCMD is not set+# CONFIG_ASH_MAIL is not set+# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set+# CONFIG_ASH_RANDOM_SUPPORT is not set+# CONFIG_ASH_EXPAND_PRMT is not set+CONFIG_CTTYHACK=y+# CONFIG_HUSH is not set+# CONFIG_HUSH_BASH_COMPAT is not set+# CONFIG_HUSH_BRACE_EXPANSION is not set+# CONFIG_HUSH_HELP is not set+# CONFIG_HUSH_INTERACTIVE is not set+# CONFIG_HUSH_SAVEHISTORY is not set+# CONFIG_HUSH_JOB is not set+# CONFIG_HUSH_TICK is not set+# CONFIG_HUSH_IF is not set+# CONFIG_HUSH_LOOPS is not set+# CONFIG_HUSH_CASE is not set+# CONFIG_HUSH_FUNCTIONS is not set+# CONFIG_HUSH_LOCAL is not set+# CONFIG_HUSH_RANDOM_SUPPORT is not set+# CONFIG_HUSH_EXPORT_N is not set+# CONFIG_HUSH_MODE_X is not set+# CONFIG_MSH is not set+CONFIG_FEATURE_SH_IS_ASH=y+# CONFIG_FEATURE_SH_IS_HUSH is not set+# CONFIG_FEATURE_SH_IS_NONE is not set+# CONFIG_FEATURE_BASH_IS_ASH is not set+# CONFIG_FEATURE_BASH_IS_HUSH is not set+CONFIG_FEATURE_BASH_IS_NONE=y+# CONFIG_SH_MATH_SUPPORT is not set+# CONFIG_SH_MATH_SUPPORT_64 is not set+# CONFIG_FEATURE_SH_EXTRA_QUIET is not set+CONFIG_FEATURE_SH_STANDALONE=y+# CONFIG_FEATURE_SH_NOFORK is not set+# CONFIG_FEATURE_SH_HISTFILESIZE is not set++#+# System Logging Utilities+#+# CONFIG_SYSLOGD is not set+# CONFIG_FEATURE_ROTATE_LOGFILE is not set+# CONFIG_FEATURE_REMOTE_LOG is not set+# CONFIG_FEATURE_SYSLOGD_DUP is not set+# CONFIG_FEATURE_SYSLOGD_CFG is not set+CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0+# CONFIG_FEATURE_IPC_SYSLOG is not set+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0+# CONFIG_LOGREAD is not set+# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set+CONFIG_KLOGD=y+CONFIG_FEATURE_KLOGD_KLOGCTL=y+# CONFIG_LOGGER is not set
+ standalone/android/icons/drawable-hdpi/ic_launcher.png view

binary file changed (absent → 1991 bytes)

+ standalone/android/icons/drawable-hdpi/ic_stat_service_notification_icon.png view

binary file changed (absent → 1071 bytes)

+ standalone/android/icons/drawable-ldpi/ic_launcher.png view

binary file changed (absent → 1031 bytes)

+ standalone/android/icons/drawable-ldpi/ic_stat_service_notification_icon.png view

binary file changed (absent → 587 bytes)

+ standalone/android/icons/drawable-mdpi/ic_launcher.png view

binary file changed (absent → 1389 bytes)

+ standalone/android/icons/drawable-mdpi/ic_stat_service_notification_icon.png view

binary file changed (absent → 712 bytes)

+ standalone/android/icons/drawable-xhdpi/ic_launcher.png view

binary file changed (absent → 2671 bytes)

+ standalone/android/icons/drawable/ic_launcher.png view

binary file changed (absent → 1389 bytes)

+ standalone/android/icons/drawable/ic_stat_service_notification_icon.png view

binary file changed (absent → 712 bytes)

+ standalone/android/openssh.config.h view
@@ -0,0 +1,249 @@+#define DISABLE_SHADOW 1+#define DISABLE_UTMP 1+#define DISABLE_UTMPX 1+#define DISABLE_WTMP 1+#define DISABLE_WTMPX 1+#define ENABLE_PKCS11 /**/+#define GETPGRP_VOID 1+#define GLOB_HAS_ALTDIRFUNC 1+#define HAS_SHADOW_EXPIRE 1+#define HAVE_ADDR_IN_UTMP 1+#define HAVE_ADDR_IN_UTMPX 1+#define HAVE_ADDR_V6_IN_UTMP 1+#define HAVE_ADDR_V6_IN_UTMPX 1+#define HAVE_ASPRINTF 1+#define HAVE_ATTRIBUTE__NONNULL__ 1+#define HAVE_BASENAME 1+#define HAVE_BCOPY 1+#define HAVE_BN_IS_PRIME_EX 1+#define HAVE_CLOCK 1+#define HAVE_CLOCK_T 1+#define HAVE_CONST_GAI_STRERROR_PROTO 1+#define HAVE_CONTROL_IN_MSGHDR 1+#define HAVE_DAEMON 1+#define HAVE_DECL_GLOB_NOMATCH 1+#define HAVE_DECL_H_ERRNO 1+#define HAVE_DECL_MAXSYMLINKS 1+#define HAVE_DECL_OFFSETOF 1+#define HAVE_DECL_O_NONBLOCK 1+#define HAVE_DECL_SHUT_RD 1+#define HAVE_DECL_WRITEV 1+#define HAVE_DECL__GETLONG 0+#define HAVE_DECL__GETSHORT 0+#define HAVE_DEV_PTMX 1+#define HAVE_DIRENT_H 1+#define HAVE_DIRFD 1+#define HAVE_DIRNAME 1+#define HAVE_DSA_GENERATE_PARAMETERS_EX 1+#define HAVE_ENDIAN_H 1+#define HAVE_ENDUTENT 1+#define HAVE_ENDUTXENT 1+#define HAVE_EVP_SHA256 1+#define HAVE_EXIT_IN_UTMP 1+#define HAVE_FCHMOD 1+#define HAVE_FCHOWN 1+#define HAVE_FCNTL_H 1+#define HAVE_FEATURES_H 1+#define HAVE_FREEADDRINFO 1+#define HAVE_FSBLKCNT_T 1+#define HAVE_FSFILCNT_T 1+#define HAVE_GAI_STRERROR 1+#define HAVE_GETADDRINFO 1+#define HAVE_GETCWD 1+#define HAVE_GETNAMEINFO 1+#define HAVE_GETOPT 1+#define HAVE_GETOPT_H 1+#define HAVE_GETPAGESIZE 1+#define HAVE_GETRLIMIT 1+#define HAVE_GETTIMEOFDAY 1+#define HAVE_GETTTYENT 1+#define HAVE_GETUTENT 1+#define HAVE_GETUTID 1+#define HAVE_GETUTLINE 1+#define HAVE_GETUTXENT 1+#define HAVE_GETUTXID 1+#define HAVE_GETUTXLINE 1+#define HAVE_GLOB 1+#define HAVE_GLOB_H 1+#define HAVE_HEADER_AD 1+#define HAVE_HMAC_CTX_INIT 1+#define HAVE_HOST_IN_UTMP 1+#define HAVE_HOST_IN_UTMPX 1+#define HAVE_ID_IN_UTMP 1+#define HAVE_ID_IN_UTMPX 1+#define HAVE_INET_ATON 1+#define HAVE_INET_NTOA 1+#define HAVE_INET_NTOP 1+#define HAVE_INT64_T 1+#define HAVE_INTTYPES_H 1+#define HAVE_INTXX_T 1+#define HAVE_IN_ADDR_T 1+#define HAVE_ISBLANK 1+#define HAVE_LASTLOG_H 1+#define HAVE_LIBGEN_H 1+#define HAVE_LIBNSL 1+#define HAVE_LIBZ 1+#define HAVE_LIMITS_H 1+#define HAVE_LINUX_AUDIT_H 1+#define HAVE_LINUX_FILTER_H 1+#define HAVE_LINUX_IF_TUN_H 1+#define HAVE_LOGOUT 1+#define HAVE_LOGWTMP 1+#define HAVE_LONG_DOUBLE 1+#define HAVE_LONG_LONG 1+#define HAVE_MEMMOVE 1+#define HAVE_MEMORY_H 1+#define HAVE_MKDTEMP 1+#define HAVE_MMAP 1+#define HAVE_MODE_T 1+#define HAVE_NANOSLEEP 1+#define HAVE_NETDB_H 1+#define HAVE_OPENSSL 1+#define HAVE_PATHS_H 1+#define HAVE_PID_IN_UTMP 1+#define HAVE_PID_T 1+#define HAVE_POLL 1+#define HAVE_POLL_H 1+#define HAVE_PRCTL 1+#define HAVE_PROC_PID 1+#define HAVE_PUTUTLINE 1+#define HAVE_PUTUTXLINE 1+#define HAVE_REALPATH 1+#define HAVE_RECVMSG 1+#define HAVE_RLIMIT_NPROC /**/+#define HAVE_RSA_GENERATE_KEY_EX 1+#define HAVE_RSA_GET_DEFAULT_METHOD 1+#define HAVE_SA_FAMILY_T 1+#define HAVE_SENDMSG 1+#define HAVE_SETEGID 1+#define HAVE_SETENV 1+#define HAVE_SETEUID 1+#define HAVE_SETGROUPS 1+#define HAVE_SETREGID 1+#define HAVE_SETRESGID 1+#define HAVE_SETRESUID 1+#define HAVE_SETREUID 1+#define HAVE_SETRLIMIT 1+#define HAVE_SETSID 1+#define HAVE_SETUTENT 1+#define HAVE_SETUTXENT 1+#define HAVE_SETVBUF 1+#define HAVE_SHA256_UPDATE 1+#define HAVE_SIGACTION 1+#define HAVE_SIGVEC 1+#define HAVE_SIG_ATOMIC_T 1+#define HAVE_SIZE_T 1+#define HAVE_SNPRINTF 1+#define HAVE_SOCKETPAIR 1+#define HAVE_SO_PEERCRED 1+#define HAVE_SSIZE_T 1+#define HAVE_SS_FAMILY_IN_SS 1+#define HAVE_STATFS 1+#define HAVE_STDDEF_H 1+#define HAVE_STDINT_H 1+#define HAVE_STDLIB_H 1+#define HAVE_STRDUP 1+#define HAVE_STRERROR 1+#define HAVE_STRFTIME 1+#define HAVE_STRICT_MKSTEMP 1+#define HAVE_STRINGS_H 1+#define HAVE_STRING_H 1+#define HAVE_STRNLEN 1+#define HAVE_STRPTIME 1+#define HAVE_STRSEP 1+#define HAVE_STRTOLL 1+#define HAVE_STRTOUL 1+#define HAVE_STRUCT_ADDRINFO 1+#define HAVE_STRUCT_IN6_ADDR 1+#define HAVE_STRUCT_SOCKADDR_IN6 1+#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1+#define HAVE_STRUCT_SOCKADDR_STORAGE 1+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1+#define HAVE_STRUCT_TIMESPEC 1+#define HAVE_STRUCT_TIMEVAL 1+#define HAVE_SYSCONF 1+#define HAVE_SYS_CDEFS_H 1+#define HAVE_SYS_DIR_H 1+#define HAVE_SYS_ERRLIST 1+#define HAVE_SYS_MMAN_H 1+#define HAVE_SYS_MOUNT_H 1+#define HAVE_SYS_NERR 1+#define HAVE_SYS_POLL_H 1+#define HAVE_SYS_PRCTL_H 1+#define HAVE_SYS_SELECT_H 1+#define HAVE_SYS_STAT_H 1+#define HAVE_SYS_SYSMACROS_H 1+#define HAVE_SYS_TIME_H 1+#define HAVE_SYS_TYPES_H 1+#define HAVE_SYS_UN_H 1+#define HAVE_TCGETPGRP 1+#define HAVE_TCSENDBREAK 1+#define HAVE_TIME 1+#define HAVE_TIME_H 1+#define HAVE_TRUNCATE 1+#define HAVE_TV_IN_UTMP 1+#define HAVE_TV_IN_UTMPX 1+#define HAVE_TYPE_IN_UTMP 1+#define HAVE_TYPE_IN_UTMPX 1+#define HAVE_UINTXX_T 1+#define HAVE_UNISTD_H 1+#define HAVE_UNSETENV 1+#define HAVE_UNSIGNED_LONG_LONG 1+#define HAVE_UPDWTMP 1+#define HAVE_UPDWTMPX 1+#define HAVE_UTIMES 1+#define HAVE_UTIME_H 1+#define HAVE_UTMPNAME 1+#define HAVE_UTMPXNAME 1+#define HAVE_UTMP_H 1+#define HAVE_U_CHAR 1+#define HAVE_U_INT 1+#define HAVE_U_INT64_T 1+#define HAVE_U_INTXX_T 1+#define HAVE_VASPRINTF 1+#define HAVE_VA_COPY 1+#define HAVE_VSNPRINTF 1+#define HAVE_WAITPID 1+#define HAVE__GETLONG 1+#define HAVE__GETSHORT 1+#define HAVE__RES_EXTERN 1+#define HAVE___FUNCTION__ 1+#define HAVE___PROGNAME 1+#define HAVE___VA_COPY 1+#define HAVE___func__ 1+#define IPV4_IN_IPV6 1+#define LINK_OPNOTSUPP_ERRNO EPERM+#define LINUX_OOM_ADJUST 1+#define LOCKED_PASSWD_PREFIX "!"+#define LOGIN_PROGRAM_FALLBACK "/bin/login"+#define MISSING_FD_MASK 1+#define MISSING_HOWMANY 1+#define OPENSSL_HAS_ECC 1+#define OPENSSL_PRNG_ONLY 1+#define PACKAGE_BUGREPORT "openssh-unix-dev@mindrot.org"+#define PACKAGE_NAME "OpenSSH"+#define PACKAGE_STRING "OpenSSH Portable"+#define PACKAGE_TARNAME "openssh"+#define PACKAGE_URL ""+#define PACKAGE_VERSION "Portable"+#define PAM_TTY_KLUDGE 1+#define SANDBOX_RLIMIT 1+#define SECCOMP_AUDIT_ARCH AUDIT_ARCH_ARM+#define SIZEOF_CHAR 1+#define SIZEOF_INT 4+#define SIZEOF_LONG_INT 8+#define SIZEOF_LONG_LONG_INT 8+#define SIZEOF_SHORT_INT 2+#define SNPRINTF_CONST const+#define SPT_TYPE SPT_REUSEARGV+#define SSH_PRIVSEP_USER "shell"+#define SSH_TUN_COMPAT_AF 1+#define SSH_TUN_LINUX 1+#define SSH_TUN_PREPEND_AF 1+#define STDC_HEADERS 1+#define USER_PATH "/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin"+#define XAUTH_PATH "/usr/bin/xauth"+#define _PATH_BTMP "/var/log/btmp"+#define _PATH_PASSWD_PROG "/usr/bin/passwd"+#define _PATH_SSH_PIDDIR "/var/run"+#define ANDROID
+ standalone/android/openssh.patch view
@@ -0,0 +1,192 @@+diff --git a/auth.c b/auth.c+index 6623e0f..dd10253 100644+--- a/auth.c++++ b/auth.c+@@ -337,7 +337,7 @@ expand_authorized_keys(const char *filename, struct passwd *pw)+ 	char *file, ret[MAXPATHLEN];+ 	int i;+ +-	file = percent_expand(filename, "h", pw->pw_dir,++	file = percent_expand(filename, "h", _PATH_ROOT_HOME_PREFIX,+ 	    "u", pw->pw_name, (char *)NULL);+ + 	/*+@@ -347,7 +347,7 @@ expand_authorized_keys(const char *filename, struct passwd *pw)+ 	if (*file == '/')+ 		return (file);+ +-	i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);++	i = snprintf(ret, sizeof(ret), "%s/%s", _PATH_ROOT_HOME_PREFIX, file);+ 	if (i < 0 || (size_t)i >= sizeof(ret))+ 		fatal("expand_authorized_keys: path too long");+ 	xfree(file);+@@ -436,7 +436,7 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,+ 		    strerror(errno));+ 		return -1;+ 	}+-	if (realpath(pw->pw_dir, homedir) != NULL)++	if (realpath(_PATH_ROOT_HOME_PREFIX, homedir) != NULL)+ 		comparehome = 1;+ + 	/* check the open file to avoid races */+diff --git a/misc.c b/misc.c+index 0bf2db6..4327d03 100644+--- a/misc.c++++ b/misc.c+@@ -25,6 +25,7 @@+  */+ + #include "includes.h"++#include "pathnames.h"+ + #include <sys/types.h>+ #include <sys/ioctl.h>+@@ -538,12 +539,13 @@ tilde_expand_filename(const char *filename, uid_t uid)+ 	} else if ((pw = getpwuid(uid)) == NULL)	/* ~/path */+ 		fatal("tilde_expand_filename: No such uid %ld", (long)uid);+ +-	if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))++	char *pw_dir=_PATH_ROOT_HOME_PREFIX;++	if (strlcpy(ret, pw_dir, sizeof(ret)) >= sizeof(ret))+ 		fatal("tilde_expand_filename: Path too long");+ + 	/* Make sure directory has a trailing '/' */+-	len = strlen(pw->pw_dir);+-	if ((len == 0 || pw->pw_dir[len - 1] != '/') &&++	len = strlen(pw_dir);++	if ((len == 0 || pw_dir[len - 1] != '/') &&+ 	    strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))+ 		fatal("tilde_expand_filename: Path too long");+ +diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c+index d2bea21..5b5d599 100644+--- a/openbsd-compat/getrrsetbyname.c++++ b/openbsd-compat/getrrsetbyname.c+@@ -56,8 +56,7 @@+ #include <arpa/inet.h>+ + #include "getrrsetbyname.h"+-#include "nameser.h"+-#include "nameser_compat.h"++#include "arpa/nameser.h"+ + #if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO+ extern int h_errno;+diff --git a/pathnames.h b/pathnames.h+index b7b9d91..3c10b11 100644+--- a/pathnames.h++++ b/pathnames.h+@@ -67,7 +67,7 @@+ #endif+ + #ifndef _PATH_ROOT_HOME_PREFIX+-#define _PATH_ROOT_HOME_PREFIX	"/data"++#define _PATH_ROOT_HOME_PREFIX	getenv("HOME")+ #endif+ + /*+diff --git a/ssh-add.c b/ssh-add.c+index 738644d..f6fce4a 100644+--- a/ssh-add.c++++ b/ssh-add.c+@@ -471,7 +471,7 @@ main(int argc, char **argv)+ 		}+ + 		for (i = 0; default_files[i]; i++) {+-			snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,++			snprintf(buf, sizeof(buf), "%s/%s", _PATH_ROOT_HOME_PREFIX,+ 			    default_files[i]);+ 			if (stat(buf, &st) < 0)+ 				continue;+diff --git a/ssh-keygen.c b/ssh-keygen.c+index 4baf7df..ef8bb25 100644+--- a/ssh-keygen.c++++ b/ssh-keygen.c+@@ -224,7 +224,7 @@ ask_filename(struct passwd *pw, const char *prompt)+ 		}+ 	}+ 	snprintf(identity_file, sizeof(identity_file), "%s/%s",+-	    strcmp(pw->pw_dir, "/") ? pw->pw_dir : _PATH_ROOT_HOME_PREFIX, name);++	    _PATH_ROOT_HOME_PREFIX, name);+ 	fprintf(stderr, "%s (%s): ", prompt, identity_file);+ 	if (fgets(buf, sizeof(buf), stdin) == NULL)+ 		exit(1);+@@ -2268,7 +2268,7 @@ main(int argc, char **argv)+ + 	/* Create ~/.ssh directory if it doesn't already exist. */+ 	snprintf(dotsshdir, sizeof dotsshdir, "%s/%s",+-	    strcmp(pw->pw_dir, "/") ? pw->pw_dir : _PATH_ROOT_HOME_PREFIX,++	    _PATH_ROOT_HOME_PREFIX,+ 	    _PATH_SSH_USER_DIR);+ 	if (strstr(identity_file, dotsshdir) != NULL) {+ 		if (stat(dotsshdir, &st) < 0) {+diff --git a/ssh.c b/ssh.c+index 898e966..ef6c858 100644+--- a/ssh.c++++ b/ssh.c+@@ -703,7 +703,7 @@ main(int ac, char **av)+ 			fatal("Can't open user config file %.100s: "+ 			    "%.100s", config, strerror(errno));+ 	} else {+-		r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,++		r = snprintf(buf, sizeof buf, "%s/%s", _PATH_ROOT_HOME_PREFIX,+ 		    _PATH_SSH_USER_CONFFILE);+ 		if (r > 0 && (size_t)r < sizeof(buf))+ 			(void)read_config_file(buf, host, &options, 1);+@@ -748,7 +748,7 @@ main(int ac, char **av)+ 	if (options.local_command != NULL) {+ 		debug3("expanding LocalCommand: %s", options.local_command);+ 		cp = options.local_command;+-		options.local_command = percent_expand(cp, "d", pw->pw_dir,++		options.local_command = percent_expand(cp, "d", _PATH_ROOT_HOME_PREFIX,+ 		    "h", host, "l", thishost, "n", host_arg, "r", options.user,+ 		    "p", portstr, "u", pw->pw_name, "L", shorthost,+ 		    (char *)NULL);+@@ -888,7 +888,7 @@ main(int ac, char **av)+ 	 */+ 	if (config == NULL) {+ 		r = snprintf(buf, sizeof buf, "%s/%s",+-		    strcmp(pw->pw_dir, "/") ? pw->pw_dir : _PATH_ROOT_HOME_PREFIX,++		    _PATH_ROOT_HOME_PREFIX,+ 		    _PATH_SSH_USER_DIR);+ 		if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) {+ #ifdef WITH_SELINUX+@@ -1532,7 +1532,7 @@ load_public_identity_files(void)+ 	if ((pw = getpwuid(original_real_uid)) == NULL)+ 		fatal("load_public_identity_files: getpwuid failed");+ 	pwname = xstrdup(pw->pw_name);+-	pwdir = xstrdup(pw->pw_dir);++	pwdir = xstrdup(_PATH_ROOT_HOME_PREFIX);+ 	if (gethostname(thishost, sizeof(thishost)) == -1)+ 		fatal("load_public_identity_files: gethostname: %s",+ 		    strerror(errno));+diff --git a/uidswap.c b/uidswap.c+index bc6194e..5cbf5d1 100644+--- a/uidswap.c++++ b/uidswap.c+@@ -28,7 +28,6 @@+ #include "xmalloc.h"+ + #ifdef ANDROID+-#include <private/android_filesystem_config.h>+ #include <linux/capability.h>+ #include <linux/prctl.h>+ #endif+@@ -230,7 +229,7 @@ permanently_set_uid(struct passwd *pw)+ 	debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid,+ 	    (u_int)pw->pw_gid);+ +-#ifdef ANDROID++#if 0+ 	if (pw->pw_uid == AID_SHELL) {+ 		prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);+ +@@ -317,7 +316,7 @@ permanently_set_uid(struct passwd *pw)+ 		    (u_int)pw->pw_uid);+ 	}+ +-#ifdef ANDROID++#if 0+ 	if (pw->pw_uid == AID_SHELL) {+ 		/* set CAP_SYS_BOOT capability, so "adb reboot" will succeed */+ 		header.version = _LINUX_CAPABILITY_VERSION;
standalone/android/runshell view
@@ -1,62 +1,118 @@ #!/system/bin/sh-# Runs a shell command (or interactive shell) using the binaries and-# libraries bundled with this app.+# This is runs a shell in an environment configured for git-annex.+# Nearly the only command that can be used in here is busybox!+# lib.start.so will run us in the root of our app directory+base=$(./busybox pwd)+cmd=$base/busybox  set -e -base="$(dirname $0)"/git-annex-bundle+prep () {+	# Cannot rely on Android providing a sane HOME+	HOME="/sdcard/git-annex.home"+	export HOME+} -if [ ! -d "$base" ]; then-	echo "** cannot find base directory (I seem to be $0)" >&2-	exit 1-fi+buildtree () {+	$cmd echo "Installation starting to $base"+	$cmd cat "lib/lib.version.so" -if [ ! -e "$base/bin/git-annex" ]; then-	echo "** base directory $base does not contain bin/git-annex" >&2-	exit 1-fi-if [ ! -e "$base/bin/git" ]; then-	echo "** base directory $base does not contain bin/git" >&2-	exit 1-fi+	if $cmd test -e "$base/bin"; then+		$cmd mv "$base/bin" "$base/bin.old"+	fi+	$cmd mkdir -p "$base/bin" -# Install busybox links.-if [ ! -e "$base/bin/sh" ]; then-	echo "(First run detected ... setting up busybox ...)"-	"$base/bin/busybox" --install "$base/bin"-fi+	for prog in busybox git-annex git-shell git-upload-pack git gpg rsync ssh ssh-keygen; do+		$cmd echo "installing $prog"+		if $cmd test -e "$base/bin/$prog"; then+			$cmd rm "$base/bin/$prog"+		fi+		$cmd ln "$base/lib/lib.$prog.so" "$base/bin/$prog"+	done -# Get absolute path to base, to avoid breakage when things change directories.-orig="$(pwd)"-cd "$base"-base="$(pwd)"-cd "$orig"+	$cmd --install $base/bin -# Put our binaries first, to avoid issues with out of date or incompatable-# system or App binaries.-ORIG_PATH="$PATH"-export ORIG_PATH-PATH=$base/bin:$PATH-export PATH+	$cmd rm -rf "$base/bin.old" -ORIG_GIT_EXEC_PATH="$GIT_EXEC_PATH"-export ORIG_GIT_EXEC_PATH-GIT_EXEC_PATH=$base/libexec/git-core-export GIT_EXEC_PATH+	$cmd tar zxf $base/lib/lib.git.tar.gz.so+	for prog in git git-shell git-upload-pack; do+		for link in $($cmd cat "$base/links/$prog"); do+			$cmd echo "linking $link to $prog"+			if $cmd test -e "$base/$link"; then+				$cmd rm "$base/$link"+			fi+			$cmd ln "$base/bin/$prog" "$base/$link"+		done+		$cmd rm "$base/links/$prog"+	done -ORIG_GIT_TEMPLATE_DIR="$GIT_TEMPLATE_DIR"-export ORIG_GIT_TEMPLATE_DIR-GIT_TEMPLATE_DIR="$base/templates"-export GIT_TEMPLATE_DIR+	$cmd mkdir -p "$base/templates"+	$cmd mkdir -p "$base/tmp" -# Indicate which variables were exported above.-GIT_ANNEX_STANDLONE_ENV="PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR"-export GIT_ANNEX_STANDLONE_ENV+	$cmd cat "$base/lib/lib.version.so" > "$base/installed-version"+	$cmd echo "Installation complete"+} -if [ "$1" ]; then-	cmd="$1"-	shift 1-	exec "$cmd" "$@"-else-	sh+install () {+	if $cmd test ! -e "$base/git-annex"; then+		if ! $cmd mkdir -p "$HOME"; then+			$cmd echo "mkdir of $HOME failed!"+		fi+		if ! buildtree > $HOME/git-annex-install.log 2>&1; then+			$cmd echo "Installation failed! Please report a bug and attach $HOME/git-annex-install.log"+			$cmd sh+		fi+	elif $cmd test ! -e "$base/installed-version" || ! $cmd cmp "$base/installed-version" "$base/lib/lib.version.so" >/dev/null; then+		if ! buildtree > $HOME/git-annex-install.log 2>&1; then+			$cmd echo "Upgrade failed! Please report a bug and attach $HOME/git-annex-install.log"+		fi+	fi+}++run () {+	# As good a start point as any.+	cd "$HOME"++	PATH="$base/bin:$PATH"+	export PATH+	+	ORIG_GIT_EXEC_PATH="$GIT_EXEC_PATH"+	export ORIG_GIT_EXEC_PATH+	GIT_EXEC_PATH=$base/libexec/git-core+	export GIT_EXEC_PATH+	+	ORIG_GIT_TEMPLATE_DIR="$GIT_TEMPLATE_DIR"+	export ORIG_GIT_TEMPLATE_DIR+	GIT_TEMPLATE_DIR="$base/templates"+	export GIT_TEMPLATE_DIR+	+	# Indicate which variables were exported above.+	GIT_ANNEX_STANDLONE_ENV="GIT_EXEC_PATH GIT_TEMPLATE_DIR"+	export GIT_ANNEX_STANDLONE_ENV+	+	# This is a temporary directory on a non-crippled filesystem.+	# This needs to be as short a path as possible.+	GIT_ANNEX_TMP_DIR=$base/tmp+	export GIT_ANNEX_TMP_DIR+	+	if $cmd test "$1"; then+		cmd="$1"+		shift 1+		exec "$cmd" "$@"+	else+		if $cmd test -e "$HOME/.config/git-annex/autostart; then+			git annex assistant --autostart || $cmd true+		fi+		/system/bin/sh+	fi+}++if ! prep; then+	$cmd echo "prep failed. Please report a bug."+	read line fi+if ! install; then+	$cmd echo "install failed. Please report a bug."+	read line+fi+run
+ standalone/android/start.c view
@@ -0,0 +1,51 @@+/* Installed as lib.start.so, this bootstraps a working busybox and uses+ * it to run lib.runshell.so. */++#include <unistd.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <sys/types.h>+#include <sys/stat.h>++void chopdir (char *s) {+	char *p=strrchr(s, '/');+	if (p == NULL) {+		fprintf(stderr, "cannot find directory in %s", s);+		exit(1);+	}+	p[0] = '\0';+}++main () {+	char buf[1024];+	char *p;+	struct stat st_buf;++	/* Get something like /data/data/ga.androidterm/lib/lib.start.so */+	int n=readlink("/proc/self/exe", buf, 1023);+	if (n < 1) {+		fprintf(stderr, "failed to find own name");+		exit(1);+	}+	buf[n] = '\0';++	/* Change directory to something like /data/data/ga.androidterm */+	chopdir(buf);+	chopdir(buf);+	if (chdir(buf) != 0) {+		perror("chdir");+		exit(1);+	}++	/* If this is the first run, set up busybox link. */+	if (stat("busybox", &st_buf) != 0) {+		if (link("lib/lib.busybox.so", "busybox") != 0) {+			perror("link busybox");+			exit(1);+		}+	}++	execl("./busybox", "./busybox", "sh", "lib/lib.runshell.so", NULL);+	perror("error running busybox sh");+}
+ standalone/android/term.patch view
@@ -0,0 +1,60 @@+diff --git a/tools/build-debug b/tools/build-debug+index 1f15cd2..e611956 100755+--- a/tools/build-debug++++ b/tools/build-debug+@@ -34,4 +34,4 @@ fi+ + rm -rf `find . -name bin -o -name obj -prune`+ cd jni+-$ANDROID_NDK_ROOT/ndk-build && cd .. && ant debug++$ANDROID_NDK_ROOT/ndk-build && cd ..+diff --git a/tools/update.sh b/tools/update.sh+index 57219c3..79b45ef 100755+--- a/tools/update.sh++++ b/tools/update.sh+@@ -18,7 +18,7 @@ command -v "$ANDROID" >/dev/null 2>&1 || { echo >&2 "The $ANDROID tool is not fo+ + # Make sure target-11 is installed+ +-$ANDROID update sdk -u -t android-11++$ANDROID update sdk -u -t android-17+ + DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"+ ATE_ROOT="$( cd $DIR/.. && pwd )"+@@ -31,5 +31,5 @@ for PROJECT_FILE in $PROJECT_FILES+ do+     PROJECT_DIR="$( dirname "$PROJECT_FILE" )"+     echo "Updating $PROJECT_FILE"+-    $ANDROID update project -p "$PROJECT_DIR" --target android-11++    $ANDROID update project -p "$PROJECT_DIR" --target android-17+ done+diff --git a/examples/widget/src/jackpal/androidterm/sample/telnet/TermActivity.java b/examples/widget/src/jackpal/androidterm/sample/telnet/TermActivity.java+index f6952f0..4b2aa5f 100644+--- a/examples/widget/src/jackpal/androidterm/sample/telnet/TermActivity.java++++ b/examples/widget/src/jackpal/androidterm/sample/telnet/TermActivity.java+@@ -166,7 +166,7 @@ public class TermActivity extends Activity+         /* ... create a process ... */+         String execPath = LaunchActivity.getDataDir(this) + "/bin/execpty";+         ProcessBuilder execBuild =+-                new ProcessBuilder(execPath, "/system/bin/sh", "-");++                new ProcessBuilder(execPath, "/data/data/ga.androidterm/lib/lib.start.so", "");+         execBuild.redirectErrorStream(true);+         Process exec = null;+         try {+diff --git a/res/values/defaults.xml b/res/values/defaults.xml+index 67287b2..1f9afa1 100644+--- a/res/values/defaults.xml++++ b/res/values/defaults.xml+@@ -13,10 +13,10 @@+    <string name="pref_fnkey_default">4</string>+    <string name="pref_ime_default">0</string>+    <bool name="pref_alt_sends_esc_default">false</bool>+-   <string name="pref_shell_default">/system/bin/sh -</string>++   <string name="pref_shell_default">/data/data/ga.androidterm/lib/lib.start.so</string>+    <string name="pref_initialcommand_default"></string>+    <string name="pref_termtype_default">screen</string>+-   <bool name="pref_close_window_on_process_exit_default">true</bool>++   <bool name="pref_close_window_on_process_exit_default">false</bool>+    <bool name="pref_verify_path_default">true</bool>+    <bool name="pref_do_path_extensions_default">true</bool>+    <bool name="pref_allow_prepend_path_default">true</bool>
standalone/licences.gz view

binary file changed (56750 → 59505 bytes)

templates/configurators/newrepository.hamlet view
@@ -1,15 +1,7 @@ <div .span9 .hero-unit>   <h2>-    Add another repository-  <p>-    The form below will make a separate repository, that is not synced #-    with your existing repository. You can use the new repository for #-    different sorts of files, that are synced and shared with other #-    devices and users.+    Add another local repository   <p>+    Where do you want to put this new repository?     <form .form-inline enctype=#{enctype}>       ^{form}-  <p>-    <i .icon-asterisk></i> #-    Do you want to add another repository that is kept in sync with #-    the current one? If so, <a href="@{RepositoriesR}">go here</a>.
+ templates/configurators/newrepository/combine.hamlet view
@@ -0,0 +1,17 @@+<div .span9 .hero-unit>+  <h2>+    Combine repositories?+  <p>+    You have created a new repository at #{newrepo}.+    <br>+    Do you want to combine it with your existing repository at #{mainrepo}?+  <p>+    <a .btn href="@{CombineRepositoryR newrepopath newrepouuid}">+      <i .icon-resize-small></i> Combine the repositories #+    The combined repositories will sync and share their files.+  <p>+    -or-+  <p>+    <a .btn href="@{SwitchToRepositoryR newrepopath}">+      <i .icon-resize-full></i> Keep the repositories separate #+    Files placed in one will not be synced to the other.
templates/configurators/repositories/misc.hamlet view
@@ -15,9 +15,7 @@ <p>   Pair with a computer to automatically keep files in sync #   over your local network.- <p>-   For easy sharing with friends and devices in the same location.  <h3>@@ -30,6 +28,12 @@ <p>    For easy sharing with friends and devices, over the internet.++<h3>+  <a href="@{NewRepositoryR}">+    <i .icon-plus-sign></i> Add a local repository+<p>+  Make another repository on your computer.  <h3>   <i .icon-plus-sign></i> Phone
templates/documentation/about.hamlet view
@@ -20,7 +20,7 @@       <a href="http://git-annex.branchable.com/license">         this page.     <p>-    Development git-annex was made possible by #+    Development of git-annex is made possible by #     <a href="http://git-annex.branchable.com/assistant/thanks/">       many excellent people     . &hearts;
− test.hs
@@ -1,1010 +0,0 @@-{- git-annex test suite- -- - Copyright 2010-2012 Joey Hess <joey@kitenet.net>- -- - Licensed under the GNU GPL version 3 or higher.- -}--{-# OPTIONS_GHC -fno-warn-orphans #-}--import Test.HUnit-import Test.HUnit.Tools-import Test.QuickCheck-import Test.QuickCheck.Instances ()--import System.Posix.Directory (changeWorkingDirectory)-import System.Posix.Files-import System.Posix.Env-import Control.Exception.Extensible-import qualified Data.Map as M-import System.IO.HVFS (SystemFS(..))-import Text.JSON--import Common-import Utility.QuickCheck ()--import qualified Utility.SafeCommand-import qualified Annex-import qualified Annex.UUID-import qualified Backend-import qualified Git.CurrentRepo-import qualified Git.Filename-import qualified Locations-import qualified Types.KeySource-import qualified Types.Backend-import qualified Types.TrustLevel-import qualified Types-import qualified GitAnnex-import qualified Logs.UUIDBased-import qualified Logs.Trust-import qualified Logs.Remote-import qualified Logs.Unused-import qualified Logs.Transfer-import qualified Logs.Presence-import qualified Remote-import qualified Types.Key-import qualified Types.Messages-import qualified Config-import qualified Crypto-import qualified Utility.Path-import qualified Utility.FileMode-import qualified Utility.Gpg-import qualified Build.SysConfig-import qualified Utility.Format-import qualified Utility.Verifiable-import qualified Utility.Process-import qualified Utility.Misc-import qualified Utility.InodeCache---- instances for quickcheck-instance Arbitrary Types.Key.Key where-	arbitrary = Types.Key.Key-		<$> arbitrary-		<*> (listOf1 $ elements ['A'..'Z']) -- BACKEND-		<*> ((abs <$>) <$> arbitrary) -- size cannot be negative-		<*> arbitrary--instance Arbitrary Logs.Transfer.TransferInfo where-	arbitrary = Logs.Transfer.TransferInfo-		<$> arbitrary-		<*> arbitrary-		<*> pure Nothing -- cannot generate a ThreadID-		<*> pure Nothing -- remote not needed-		<*> arbitrary-		-- associated file cannot be empty (but can be Nothing)-		<*> arbitrary `suchThat` (/= Just "")-		<*> arbitrary--instance Arbitrary Utility.InodeCache.InodeCache where-	arbitrary = Utility.InodeCache.InodeCache-		<$> arbitrary-		<*> arbitrary-		<*> arbitrary--instance Arbitrary Logs.Presence.LogLine where-	arbitrary = Logs.Presence.LogLine-		<$> arbitrary-		<*> elements [minBound..maxBound]-		<*> arbitrary `suchThat` ('\n' `notElem`)--main :: IO ()-main = do-	prepare-	r <- runVerboseTests $ TestList [quickcheck, blackbox]-	cleanup tmpdir-	propigate r--propigate :: (Counts, Int) -> IO ()-propigate (Counts { errors = e , failures = f }, _)-	| e+f > 0 = error "failed"-	| otherwise = return ()--quickcheck :: Test-quickcheck = TestLabel "quickcheck" $ TestList-	[ qctest "prop_idempotent_deencode_git" Git.Filename.prop_idempotent_deencode-	, qctest "prop_idempotent_deencode" Utility.Format.prop_idempotent_deencode-	, qctest "prop_idempotent_fileKey" Locations.prop_idempotent_fileKey-	, qctest "prop_idempotent_key_encode" Types.Key.prop_idempotent_key_encode-	, qctest "prop_idempotent_shellEscape" Utility.SafeCommand.prop_idempotent_shellEscape-	, qctest "prop_idempotent_shellEscape_multiword" Utility.SafeCommand.prop_idempotent_shellEscape_multiword-	, qctest "prop_idempotent_configEscape" Logs.Remote.prop_idempotent_configEscape-	, qctest "prop_parse_show_Config" Logs.Remote.prop_parse_show_Config-	, qctest "prop_parentDir_basics" Utility.Path.prop_parentDir_basics-	, qctest "prop_relPathDirToFile_basics" Utility.Path.prop_relPathDirToFile_basics-	, qctest "prop_relPathDirToFile_regressionTest" Utility.Path.prop_relPathDirToFile_regressionTest-	, qctest "prop_cost_sane" Config.prop_cost_sane-	, qctest "prop_hmacWithCipher_sane" Crypto.prop_hmacWithCipher_sane-	, qctest "prop_TimeStamp_sane" Logs.UUIDBased.prop_TimeStamp_sane-	, qctest "prop_addLog_sane" Logs.UUIDBased.prop_addLog_sane-	, qctest "prop_verifiable_sane" Utility.Verifiable.prop_verifiable_sane-	, qctest "prop_segment_regressionTest" Utility.Misc.prop_segment_regressionTest-	, qctest "prop_read_write_transferinfo" Logs.Transfer.prop_read_write_transferinfo-	, qctest "prop_read_show_inodecache" Utility.InodeCache.prop_read_show_inodecache-	, qctest "prop_parse_show_log" Logs.Presence.prop_parse_show_log-	, qctest "prop_read_show_TrustLevel" Types.TrustLevel.prop_read_show_TrustLevel-	, qctest "prop_parse_show_TrustLog" Logs.Trust.prop_parse_show_TrustLog-	]--blackbox :: Test-blackbox = TestLabel "blackbox" $ TestList-	-- test order matters, later tests may rely on state from earlier-	[ test_init-	, test_add-	, test_reinject-	, test_unannex-	, test_drop-	, test_get-	, test_move-	, test_copy-	, test_lock-	, test_edit-	, test_fix-	, test_trust-	, test_fsck-	, test_migrate-	, test_unused-	, test_describe-	, test_find-	, test_merge-	, test_status-	, test_version-	, test_sync-	, test_sync_regression-	, test_map-	, test_uninit-	, test_upgrade-	, test_whereis-	, test_hook_remote-	, test_directory_remote-	, test_rsync_remote-	, test_bup_remote-	, test_crypto-	]--test_init :: Test-test_init = "git-annex init" ~: TestCase $ innewrepo $ do-	git_annex "init" [reponame] @? "init failed"-  where-	reponame = "test repo"--test_add :: Test-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-	basic = TestCase $ inmainrepo $ do-		writeFile annexedfile $ content annexedfile-		git_annex "add" [annexedfile] @? "add failed"-		annexed_present annexedfile-		writeFile sha1annexedfile $ content sha1annexedfile-		git_annex "add" [sha1annexedfile, "--backend=SHA1"] @? "add with SHA1 failed"-		annexed_present sha1annexedfile-		checkbackend sha1annexedfile backendSHA1-		writeFile wormannexedfile $ content wormannexedfile-		git_annex "add" [wormannexedfile, "--backend=WORM"] @? "add with WORM failed"-		annexed_present wormannexedfile-		checkbackend wormannexedfile backendWORM-		boolSystem "git" [Params "rm --force -q", File wormannexedfile] @? "git rm failed"-		writeFile ingitfile $ content ingitfile-		boolSystem "git" [Param "add", File ingitfile] @? "git add failed"-		boolSystem "git" [Params "commit -q -a -m commit"] @? "git commit failed"-		git_annex "add" [ingitfile] @? "add ingitfile should be no-op"-		unannexed ingitfile-	sha1dup = TestCase $ intmpclonerepo $ do-		writeFile sha1annexedfiledup $ content sha1annexedfiledup-		git_annex "add" [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" ["dir"] @? "add of subdir failed"-		createDirectory "dir2"-		writeFile "dir2/foo" $ content annexedfile-		changeWorkingDirectory "dir"-		git_annex "add" ["../dir2"] @? "add of ../subdir failed"--test_reinject :: Test-test_reinject = "git-annex reinject/fromkey" ~: TestCase $ intmpclonerepo $ do-	git_annex "drop" ["--force", sha1annexedfile] @? "drop failed"-	writeFile tmp $ content sha1annexedfile-	r <- annexeval $ Types.Backend.getKey backendSHA1 $-		Types.KeySource.KeySource { Types.KeySource.keyFilename = tmp, Types.KeySource.contentLocation = tmp, Types.KeySource.inodeCache = Nothing }-	let key = Types.Key.key2file $ fromJust r-	git_annex "reinject" [tmp, sha1annexedfile] @? "reinject failed"-	git_annex "fromkey" [key, sha1annexedfiledup] @? "fromkey failed"-	annexed_present sha1annexedfiledup-  where-	tmp = "tmpfile"--test_unannex :: Test-test_unannex = "git-annex unannex" ~: TestList [nocopy, withcopy]-  where-	nocopy = "no content" ~: intmpclonerepo $ do-		annexed_notpresent annexedfile-		git_annex "unannex" [annexedfile] @? "unannex failed with no copy"-		annexed_notpresent annexedfile-	withcopy = "with content" ~: intmpclonerepo $ do-		git_annex "get" [annexedfile] @? "get failed"-		annexed_present annexedfile-		git_annex "unannex" [annexedfile, sha1annexedfile] @? "unannex failed"-		unannexed annexedfile-		git_annex "unannex" [annexedfile] @? "unannex failed on non-annexed file"-		unannexed annexedfile-		git_annex "unannex" [ingitfile] @? "unannex ingitfile should be no-op"-		unannexed ingitfile--test_drop :: Test-test_drop = "git-annex drop" ~: TestList [noremote, withremote, untrustedremote]-  where-	noremote = "no remotes" ~: TestCase $ intmpclonerepo $ do-		git_annex "get" [annexedfile] @? "get failed"-		boolSystem "git" [Params "remote rm origin"]-			@? "git remote rm origin failed"-		not <$> git_annex "drop" [annexedfile] @? "drop wrongly succeeded with no known copy of file"-		annexed_present annexedfile-		git_annex "drop" ["--force", annexedfile] @? "drop --force failed"-		annexed_notpresent annexedfile-		git_annex "drop" [annexedfile] @? "drop of dropped file failed"-		git_annex "drop" [ingitfile] @? "drop ingitfile should be no-op"-		unannexed ingitfile-	withremote = "with remote" ~: TestCase $ intmpclonerepo $ do-		git_annex "get" [annexedfile] @? "get failed"-		annexed_present annexedfile-		git_annex "drop" [annexedfile] @? "drop failed though origin has copy"-		annexed_notpresent annexedfile-		inmainrepo $ annexed_present annexedfile-	untrustedremote = "untrusted remote" ~: TestCase $ intmpclonerepo $ do-		git_annex "untrust" ["origin"] @? "untrust of origin failed"-		git_annex "get" [annexedfile] @? "get failed"-		annexed_present annexedfile-		not <$> git_annex "drop" [annexedfile] @? "drop wrongly suceeded with only an untrusted copy of the file"-		annexed_present annexedfile-		inmainrepo $ annexed_present annexedfile--test_get :: Test-test_get = "git-annex get" ~: TestCase $ intmpclonerepo $ do-	inmainrepo $ annexed_present annexedfile-	annexed_notpresent annexedfile-	git_annex "get" [annexedfile] @? "get of file failed"-	inmainrepo $ annexed_present annexedfile-	annexed_present annexedfile-	git_annex "get" [annexedfile] @? "get of file already here failed"-	inmainrepo $ annexed_present annexedfile-	annexed_present annexedfile-	inmainrepo $ unannexed ingitfile-	unannexed ingitfile-	git_annex "get" [ingitfile] @? "get ingitfile should be no-op"-	inmainrepo $ unannexed ingitfile-	unannexed ingitfile--test_move :: Test-test_move = "git-annex move" ~: TestCase $ intmpclonerepo $ do-	annexed_notpresent annexedfile-	inmainrepo $ annexed_present annexedfile-	git_annex "move" ["--from", "origin", annexedfile] @? "move --from of file failed"-	annexed_present annexedfile-	inmainrepo $ annexed_notpresent annexedfile-	git_annex "move" ["--from", "origin", annexedfile] @? "move --from of file already here failed"-	annexed_present annexedfile-	inmainrepo $ annexed_notpresent annexedfile-	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file failed"-	inmainrepo $ annexed_present annexedfile-	annexed_notpresent annexedfile-	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed"-	inmainrepo $ annexed_present annexedfile-	annexed_notpresent annexedfile-	unannexed ingitfile-	inmainrepo $ unannexed ingitfile-	git_annex "move" ["--to", "origin", ingitfile] @? "move of ingitfile should be no-op"-	unannexed ingitfile-	inmainrepo $ unannexed ingitfile-	git_annex "move" ["--from", "origin", ingitfile] @? "move of ingitfile should be no-op"-	unannexed ingitfile-	inmainrepo $ unannexed ingitfile--test_copy :: Test-test_copy = "git-annex copy" ~: TestCase $ intmpclonerepo $ do-	annexed_notpresent annexedfile-	inmainrepo $ annexed_present annexedfile-	git_annex "copy" ["--from", "origin", annexedfile] @? "copy --from of file failed"-	annexed_present annexedfile-	inmainrepo $ annexed_present annexedfile-	git_annex "copy" ["--from", "origin", annexedfile] @? "copy --from of file already here failed"-	annexed_present annexedfile-	inmainrepo $ annexed_present annexedfile-	git_annex "copy" ["--to", "origin", annexedfile] @? "copy --to of file already there failed"-	annexed_present annexedfile-	inmainrepo $ annexed_present annexedfile-	git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed"-	annexed_notpresent annexedfile-	inmainrepo $ annexed_present annexedfile-	unannexed ingitfile-	inmainrepo $ unannexed ingitfile-	git_annex "copy" ["--to", "origin", ingitfile] @? "copy of ingitfile should be no-op"-	unannexed ingitfile-	inmainrepo $ unannexed ingitfile-	git_annex "copy" ["--from", "origin", ingitfile] @? "copy of ingitfile should be no-op"-	checkregularfile ingitfile-	checkcontent ingitfile--test_lock :: Test-test_lock = "git-annex unlock/lock" ~: intmpclonerepo $ do-	-- regression test: unlock of not present file should skip it-	annexed_notpresent annexedfile-	not <$> git_annex "unlock" [annexedfile] @? "unlock failed to fail with not present file"-	annexed_notpresent annexedfile--	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "unlock" [annexedfile] @? "unlock failed"		-	unannexed annexedfile-	-- write different content, to verify that lock-	-- throws it away-	changecontent annexedfile-	writeFile annexedfile $ content annexedfile ++ "foo"-	git_annex "lock" [annexedfile] @? "lock failed"-	annexed_present annexedfile-	git_annex "unlock" [annexedfile] @? "unlock failed"		-	unannexed annexedfile-	changecontent annexedfile-	git_annex "add" [annexedfile] @? "add of modified file failed"-	runchecks [checklink, checkunwritable] annexedfile-	c <- readFile annexedfile-	assertEqual "content of modified file" c (changedcontent annexedfile)-	r' <- git_annex "drop" [annexedfile]-	not r' @? "drop wrongly succeeded with no known copy of modified file"--test_edit :: Test-test_edit = "git-annex edit/commit" ~: TestList [t False, t True]-  where t precommit = TestCase $ intmpclonerepo $ do-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "edit" [annexedfile] @? "edit failed"-	unannexed annexedfile-	changecontent annexedfile-	if precommit-		then do-			-- pre-commit depends on the file being-			-- staged, normally git commit does this-			boolSystem "git" [Param "add", File annexedfile]-				@? "git add of edited file failed"-			git_annex "pre-commit" []-				@? "pre-commit failed"-		else do-			boolSystem "git" [Params "commit -q -a -m contentchanged"]-				@? "git commit of edited file failed"-	runchecks [checklink, checkunwritable] annexedfile-	c <- readFile annexedfile-	assertEqual "content of modified file" c (changedcontent annexedfile)-	not <$> git_annex "drop" [annexedfile] @? "drop wrongly succeeded with no known copy of modified file"--test_fix :: Test-test_fix = "git-annex fix" ~: intmpclonerepo $ do-	annexed_notpresent annexedfile-	git_annex "fix" [annexedfile] @? "fix of not present failed"-	annexed_notpresent annexedfile-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "fix" [annexedfile] @? "fix of present file failed"-	annexed_present annexedfile-	createDirectory subdir-	boolSystem "git" [Param "mv", File annexedfile, File subdir]-		@? "git mv failed"-	git_annex "fix" [newfile] @? "fix of moved file failed"-	runchecks [checklink, checkunwritable] newfile-	c <- readFile newfile-	assertEqual "content of moved file" c (content annexedfile)-  where-	subdir = "s"-	newfile = subdir ++ "/" ++ annexedfile--test_trust :: Test-test_trust = "git-annex trust/untrust/semitrust/dead" ~: intmpclonerepo $ do-	git_annex "trust" [repo] @? "trust failed"-	trustcheck Logs.Trust.Trusted "trusted 1"-	git_annex "trust" [repo] @? "trust of trusted failed"-	trustcheck Logs.Trust.Trusted "trusted 2"-	git_annex "untrust" [repo] @? "untrust failed"-	trustcheck Logs.Trust.UnTrusted "untrusted 1"-	git_annex "untrust" [repo] @? "untrust of untrusted failed"-	trustcheck Logs.Trust.UnTrusted "untrusted 2"-	git_annex "dead" [repo] @? "dead failed"-	trustcheck Logs.Trust.DeadTrusted "deadtrusted 1"-	git_annex "dead" [repo] @? "dead of dead failed"-	trustcheck Logs.Trust.DeadTrusted "deadtrusted 2"-	git_annex "semitrust" [repo] @? "semitrust failed"-	trustcheck Logs.Trust.SemiTrusted "semitrusted 1"-	git_annex "semitrust" [repo] @? "semitrust of semitrusted failed"-	trustcheck Logs.Trust.SemiTrusted "semitrusted 2"-  where-	repo = "origin"-	trustcheck expected msg = do-		present <- annexeval $ do-			l <- Logs.Trust.trustGet expected-			u <- Remote.nameToUUID repo-			return $ u `elem` l-		assertBool msg present--test_fsck :: Test-test_fsck = "git-annex fsck" ~: TestList [basicfsck, barefsck, withlocaluntrusted, withremoteuntrusted]-  where-	basicfsck = TestCase $ intmpclonerepo $ do-		git_annex "fsck" [] @? "fsck failed"-		boolSystem "git" [Params "config annex.numcopies 2"] @? "git config failed"-		fsck_should_fail "numcopies unsatisfied"-		boolSystem "git" [Params "config annex.numcopies 1"] @? "git config failed"-		corrupt annexedfile-		corrupt sha1annexedfile-	barefsck = TestCase $ intmpbareclonerepo $ do-		git_annex "fsck" [] @? "fsck failed"-	withlocaluntrusted = TestCase $ intmpclonerepo $ do-		git_annex "get" [annexedfile] @? "get failed"-		git_annex "untrust" ["origin"] @? "untrust of origin repo failed"-		git_annex "untrust" ["."] @? "untrust of current repo failed"-		fsck_should_fail "content only available in untrusted (current) repository"-		git_annex "trust" ["."] @? "trust of current repo failed"-		git_annex "fsck" [annexedfile] @? "fsck failed on file present in trusted repo"-	withremoteuntrusted = TestCase $ intmpclonerepo $ do-		boolSystem "git" [Params "config annex.numcopies 2"] @? "git config failed"-		git_annex "get" [annexedfile] @? "get failed"-		git_annex "get" [sha1annexedfile] @? "get failed"-		git_annex "fsck" [] @? "fsck failed with numcopies=2 and 2 copies"-		git_annex "untrust" ["origin"] @? "untrust of origin failed"-		fsck_should_fail "content not replicated to enough non-untrusted repositories"--	corrupt f = do-		git_annex "get" [f] @? "get of file failed"-		Utility.FileMode.allowWrite f-		writeFile f (changedcontent f)-		not <$> git_annex "fsck" [] @? "fsck failed to fail with corrupted file content"-		git_annex "fsck" [] @? "fsck unexpectedly failed again; previous one did not fix problem with " ++ f-	fsck_should_fail m = do-		not <$> git_annex "fsck" [] @? "fsck failed to fail with " ++ m--test_migrate :: Test-test_migrate = "git-annex migrate" ~: TestList [t False, t True]-  where t usegitattributes = TestCase $ intmpclonerepo $ do-	annexed_notpresent annexedfile-	annexed_notpresent sha1annexedfile-	git_annex "migrate" [annexedfile] @? "migrate of not present failed"-	git_annex "migrate" [sha1annexedfile] @? "migrate of not present failed"-	git_annex "get" [annexedfile] @? "get of file failed"-	git_annex "get" [sha1annexedfile] @? "get of file failed"-	annexed_present annexedfile-	annexed_present sha1annexedfile-	if usegitattributes-		then do-			writeFile ".gitattributes" $ "* annex.backend=SHA1"-			git_annex "migrate" [sha1annexedfile]-				@? "migrate sha1annexedfile failed"-			git_annex "migrate" [annexedfile]-				@? "migrate annexedfile failed"-		else do-			git_annex "migrate" [sha1annexedfile, "--backend", "SHA1"]-				@? "migrate sha1annexedfile failed"-			git_annex "migrate" [annexedfile, "--backend", "SHA1"]-				@? "migrate annexedfile failed"-	annexed_present annexedfile-	annexed_present sha1annexedfile-	checkbackend annexedfile backendSHA1-	checkbackend sha1annexedfile backendSHA1--	-- check that reversing a migration works-	writeFile ".gitattributes" $ "* annex.backend=SHA256"-	git_annex "migrate" [sha1annexedfile]-		@? "migrate sha1annexedfile failed"-	git_annex "migrate" [annexedfile]-		@? "migrate annexedfile failed"-	annexed_present annexedfile-	annexed_present sha1annexedfile-	checkbackend annexedfile backendSHA256-	checkbackend sha1annexedfile backendSHA256--test_unused :: Test-test_unused = "git-annex unused/dropunused" ~: intmpclonerepo $ do-	-- keys have to be looked up before files are removed-	annexedfilekey <- annexeval $ findkey annexedfile-	sha1annexedfilekey <- annexeval $ findkey sha1annexedfile-	git_annex "get" [annexedfile] @? "get of file failed"-	git_annex "get" [sha1annexedfile] @? "get of file failed"-	checkunused [] "after get"-	boolSystem "git" [Params "rm -q", File annexedfile] @? "git rm failed"-	checkunused [] "after rm"-	boolSystem "git" [Params "commit -q -m foo"] @? "git commit failed"-	checkunused [] "after commit"-	-- unused checks origin/master; once it's gone it is really unused-	boolSystem "git" [Params "remote rm origin"] @? "git remote rm origin failed"-	checkunused [annexedfilekey] "after origin branches are gone"-	boolSystem "git" [Params "rm -q", File sha1annexedfile] @? "git rm failed"-	boolSystem "git" [Params "commit -q -m foo"] @? "git commit failed"-	checkunused [annexedfilekey, sha1annexedfilekey] "after rm sha1annexedfile"--	-- good opportunity to test dropkey also-	git_annex "dropkey" ["--force", Types.Key.key2file annexedfilekey]-		@? "dropkey failed"-	checkunused [sha1annexedfilekey] ("after dropkey --force " ++ Types.Key.key2file annexedfilekey)--	git_annex "dropunused" ["1", "2"] @? "dropunused failed"-	checkunused [] "after dropunused"-	git_annex "dropunused" ["10", "501"] @? "dropunused failed on bogus numbers"--  where-	checkunused expectedkeys desc = do-		git_annex "unused" [] @? "unused failed"-		unusedmap <- annexeval $ Logs.Unused.readUnusedLog ""-		let unusedkeys = M.elems unusedmap-		assertEqual ("unused keys differ " ++ desc)-			(sort expectedkeys) (sort unusedkeys)-	findkey f = do-		r <- Backend.lookupFile f-		return $ fst $ fromJust r--test_describe :: Test-test_describe = "git-annex describe" ~: intmpclonerepo $ do-	git_annex "describe" [".", "this repo"] @? "describe 1 failed"-	git_annex "describe" ["origin", "origin repo"] @? "describe 2 failed"--test_find :: Test-test_find = "git-annex find" ~: intmpclonerepo $ do-	annexed_notpresent annexedfile-	git_annex_expectoutput "find" [] []-	git_annex "get" [annexedfile] @? "get failed"-	annexed_present annexedfile-	annexed_notpresent sha1annexedfile-	git_annex_expectoutput "find" [] [annexedfile]-	git_annex_expectoutput "find" ["--exclude", annexedfile, "--and", "--exclude", sha1annexedfile] []-	git_annex_expectoutput "find" ["--include", annexedfile] [annexedfile]-	git_annex_expectoutput "find" ["--not", "--in", "origin"] []-	git_annex_expectoutput "find" ["--copies", "1", "--and", "--not", "--copies", "2"] [sha1annexedfile]-	git_annex_expectoutput "find" ["--inbackend", "SHA1"] [sha1annexedfile]-	git_annex_expectoutput "find" ["--inbackend", "WORM"] []--test_merge :: Test-test_merge = "git-annex merge" ~: intmpclonerepo $ do-	git_annex "merge" [] @? "merge failed"--test_status :: Test-test_status = "git-annex status" ~: intmpclonerepo $ do-	json <- git_annex_output "status" ["--json"]-	case Text.JSON.decodeStrict json :: Text.JSON.Result (JSObject JSValue) of-		Ok _ -> return ()-		Error e -> assertFailure e--test_version :: Test-test_version = "git-annex version" ~: intmpclonerepo $ do-	git_annex "version" [] @? "version failed"--test_sync :: Test-test_sync = "git-annex sync" ~: intmpclonerepo $ do-	git_annex "sync" [] @? "sync failed"--{- Regression test for sync merge bug fixed in- - 0214e0fb175a608a49b812d81b4632c081f63027 -}-test_sync_regression :: Test-test_sync_regression = "git-annex sync_regression" ~:-	{- We need 3 repos to see this bug. -}-	withtmpclonerepo False $ \r1 -> do-		withtmpclonerepo False $ \r2 -> do-			withtmpclonerepo False $ \r3 -> do-				forM_ [r1, r2, r3] $ \r -> indir r $ do-					when (r /= r1) $-						boolSystem "git" [Params "remote add r1", File ("../../" ++ r1)] @? "remote add"-					when (r /= r2) $-						boolSystem "git" [Params "remote add r2", File ("../../" ++ r2)] @? "remote add"-					when (r /= r3) $-						boolSystem "git" [Params "remote add r3", File ("../../" ++ r3)] @? "remote add"-					git_annex "get" [annexedfile] @? "get failed"-					boolSystem "git" [Params "remote rm origin"] @? "remote rm"-				forM_ [r3, r2, r1] $ \r -> indir r $-					git_annex "sync" [] @? "sync failed"-				forM_ [r3, r2] $ \r -> indir r $-					git_annex "drop" ["--force", annexedfile] @? "drop failed"-				indir r1 $ do-					git_annex "sync" [] @? "sync failed in r1"-					git_annex_expectoutput "find" ["--in", "r3"] []-					{- This was the bug. The sync-					 - mangled location log data and it-					 - thought the file was still in r2 -}-					git_annex_expectoutput "find" ["--in", "r2"] []--test_map :: Test-test_map = "git-annex map" ~: intmpclonerepo $ do-	-- set descriptions, that will be looked for in the map-	git_annex "describe" [".", "this repo"] @? "describe 1 failed"-	git_annex "describe" ["origin", "origin repo"] @? "describe 2 failed"-	-- --fast avoids it running graphviz, not a build dependency-	git_annex "map" ["--fast"] @? "map failed"--test_uninit :: Test-test_uninit = "git-annex uninit" ~: intmpclonerepo $ do-	git_annex "get" [] @? "get failed"-	annexed_present annexedfile-	boolSystem "git" [Params "checkout git-annex"] @? "git checkout git-annex"-	not <$> git_annex "uninit" [] @? "uninit failed to fail when git-annex branch was checked out"-	boolSystem "git" [Params "checkout master"] @? "git checkout master"-	_ <- git_annex "uninit" [] -- exit status not checked; does abnormal exit-	checkregularfile annexedfile-	doesDirectoryExist ".git" @? ".git vanished in uninit"-	not <$> doesDirectoryExist ".git/annex" @? ".git/annex still present after uninit"--test_upgrade :: Test-test_upgrade = "git-annex upgrade" ~: intmpclonerepo $ do-	git_annex "upgrade" [] @? "upgrade from same version failed"--test_whereis :: Test-test_whereis = "git-annex whereis" ~: intmpclonerepo $ do-	annexed_notpresent annexedfile-	git_annex "whereis" [annexedfile] @? "whereis on non-present file failed"-	git_annex "untrust" ["origin"] @? "untrust failed"-	not <$> git_annex "whereis" [annexedfile] @? "whereis on non-present file only present in untrusted repo failed to fail"-	git_annex "get" [annexedfile] @? "get failed"-	annexed_present annexedfile-	git_annex "whereis" [annexedfile] @? "whereis on present file failed"--test_hook_remote :: Test-test_hook_remote = "git-annex hook remote" ~: intmpclonerepo $ do-	git_annex "initremote" (words "foo type=hook encryption=none hooktype=foo") @? "initremote failed"-	createDirectory dir-	git_config "annex.foo-store-hook" $-		"cp $ANNEX_FILE " ++ loc-	git_config "annex.foo-retrieve-hook" $-		"cp " ++ loc ++ " $ANNEX_FILE"-	git_config "annex.foo-remove-hook" $-		"rm -f " ++ loc-	git_config "annex.foo-checkpresent-hook" $-		"if [ -e " ++ loc ++ " ]; then echo $ANNEX_KEY; fi"-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to hook remote failed"-	annexed_present annexedfile-	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"-	annexed_notpresent annexedfile-	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from hook remote failed"-	annexed_present annexedfile-	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"-	annexed_present annexedfile-  where-	dir = "dir"-	loc = dir ++ "/$ANNEX_KEY"-	git_config k v = boolSystem "git" [Param "config", Param k, Param v]-		@? "git config failed"--test_directory_remote :: Test-test_directory_remote = "git-annex directory remote" ~: intmpclonerepo $ do-	createDirectory "dir"-	git_annex "initremote" (words $ "foo type=directory encryption=none directory=dir") @? "initremote failed"-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to directory remote failed"-	annexed_present annexedfile-	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"-	annexed_notpresent annexedfile-	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from directory remote failed"-	annexed_present annexedfile-	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"-	annexed_present annexedfile--test_rsync_remote :: Test-test_rsync_remote = "git-annex rsync remote" ~: intmpclonerepo $ do-	createDirectory "dir"-	git_annex "initremote" (words $ "foo type=rsync encryption=none rsyncurl=dir") @? "initremote failed"-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to rsync remote failed"-	annexed_present annexedfile-	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"-	annexed_notpresent annexedfile-	git_annex "move" [annexedfile, "--from", "foo"] @? "move --from rsync remote failed"-	annexed_present annexedfile-	not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"-	annexed_present annexedfile--test_bup_remote :: Test-test_bup_remote = "git-annex bup remote" ~: intmpclonerepo $ when Build.SysConfig.bup $ do-	dir <- absPath "dir" -- bup special remote needs an absolute path-	createDirectory dir-	git_annex "initremote" (words $ "foo type=bup encryption=none buprepo="++dir) @? "initremote failed"-	git_annex "get" [annexedfile] @? "get of file failed"-	annexed_present annexedfile-	git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to bup remote failed"-	annexed_present annexedfile-	git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"-	annexed_notpresent annexedfile-	git_annex "copy" [annexedfile, "--from", "foo"] @? "copy --from bup remote failed"-	annexed_present annexedfile-	not <$> git_annex "move" [annexedfile, "--from", "foo"] @? "move --from bup remote failed to fail"-	annexed_present annexedfile---- gpg is not a build dependency, so only test when it's available-test_crypto :: Test-test_crypto = "git-annex crypto" ~: intmpclonerepo $ when Build.SysConfig.gpg $ do-	-- force gpg into batch mode for the tests-	setEnv "GPG_BATCH" "1" True-	Utility.Gpg.testTestHarness @? "test harness self-test failed"-	Utility.Gpg.testHarness $ do-		createDirectory "dir"-		let initremote = git_annex "initremote"-			[ "foo"-			, "type=directory"-			, "encryption=" ++ Utility.Gpg.testKeyId-			, "directory=dir"-			]-		initremote @? "initremote failed"-		initremote @? "initremote failed when run twice in a row"-		git_annex "get" [annexedfile] @? "get of file failed"-		annexed_present annexedfile-		git_annex "copy" [annexedfile, "--to", "foo"] @? "copy --to encrypted remote failed"-		annexed_present annexedfile-		git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed"-		annexed_notpresent annexedfile-		git_annex "move" [annexedfile, "--from", "foo"] @? "move --from encrypted remote failed"-		annexed_present annexedfile-		not <$> git_annex "drop" [annexedfile, "--numcopies=2"] @? "drop failed to fail"-		annexed_present annexedfile	---- This is equivilant to running git-annex, but it's all run in-process--- so test coverage collection works.-git_annex :: String -> [String] -> IO Bool-git_annex command params = do-	-- catch all errors, including normally fatal errors-	r <- try (run)::IO (Either SomeException ())-	case r of-		Right _ -> return True-		Left _ -> return False-  where-	run = GitAnnex.run (command:"-q":params)--{- Runs git-annex and returns its output. -}-git_annex_output :: String -> [String] -> IO String-git_annex_output command params = do-	got <- Utility.Process.readProcess "git-annex" (command:params)-	-- XXX since the above is a separate process, code coverage stats are-	-- not gathered for things run in it.-	-- Run same command again, to get code coverage.-	_ <- git_annex command params-	return got--git_annex_expectoutput :: String -> [String] -> [String] -> IO ()-git_annex_expectoutput command params expected = do-	got <- lines <$> git_annex_output command params-	got == expected @? ("unexpected value running " ++ command ++ " " ++ show params ++ " -- got: " ++ show got ++ " expected: " ++ show expected)---- Runs an action in the current annex. Note that shutdown actions--- are not run; this should only be used for actions that query state.-annexeval :: Types.Annex a -> IO a-annexeval a = do-	s <- Annex.new =<< Git.CurrentRepo.get-	Annex.eval s $ do-		Annex.setOutput Types.Messages.QuietOutput-		a--innewrepo :: Assertion -> Assertion-innewrepo a = withgitrepo $ \r -> indir r a--inmainrepo :: Assertion -> Assertion-inmainrepo a = indir mainrepodir a--intmpclonerepo :: Assertion -> Assertion-intmpclonerepo a = withtmpclonerepo False $ \r -> indir r a--intmpbareclonerepo :: Assertion -> Assertion-intmpbareclonerepo a = withtmpclonerepo True $ \r -> indir r a--withtmpclonerepo :: Bool -> (FilePath -> Assertion) -> Assertion-withtmpclonerepo bare a = do-	dir <- tmprepodir-	bracket (clonerepo mainrepodir dir bare) cleanup a--withgitrepo :: (FilePath -> Assertion) -> Assertion-withgitrepo = bracket (setuprepo mainrepodir) return--indir :: FilePath -> Assertion -> Assertion-indir dir a = do-	cwd <- getCurrentDirectory-	-- Assertion failures throw non-IO errors; catch-	-- any type of error and change back to cwd before-	-- rethrowing.-	r <- bracket_ (changeToTmpDir dir) (changeWorkingDirectory cwd)-		(try (a)::IO (Either SomeException ()))-	case r of-		Right () -> return ()-		Left e -> throw e--setuprepo :: FilePath -> IO FilePath-setuprepo dir = do-	cleanup dir-	ensuretmpdir-	boolSystem "git" [Params "init -q", File dir] @? "git init failed"-	indir dir $ do-		boolSystem "git" [Params "config user.name", Param "Test User"] @? "git config failed"-		boolSystem "git" [Params "config user.email test@example.com"] @? "git config failed"-	return dir---- clones are always done as local clones; we cannot test ssh clones-clonerepo :: FilePath -> FilePath -> Bool -> IO FilePath-clonerepo old new bare = do-	cleanup new-	ensuretmpdir-	let b = if bare then " --bare" else ""-	boolSystem "git" [Params ("clone -q" ++ b), File old, File new] @? "git clone failed"-	indir new $ git_annex "init" ["-q", new] @? "git annex init failed"-	return new-	-ensuretmpdir :: IO ()-ensuretmpdir = do-	e <- doesDirectoryExist tmpdir-	unless e $-		createDirectory tmpdir--cleanup :: FilePath -> IO ()-cleanup dir = do-	e <- doesDirectoryExist dir-	when e $ do-		-- git-annex prevents annexed file content from being-		-- removed via directory permissions; undo-		recurseDir SystemFS dir >>=-			filterM doesDirectoryExist >>=-			mapM_ Utility.FileMode.allowWrite-		removeDirectoryRecursive dir-	-checklink :: FilePath -> Assertion-checklink f = do-	s <- getSymbolicLinkStatus f-	isSymbolicLink s @? f ++ " is not a symlink"--checkregularfile :: FilePath -> Assertion-checkregularfile f = do-	s <- getSymbolicLinkStatus f-	isRegularFile s @? f ++ " is not a normal file"-	return ()--checkcontent :: FilePath -> Assertion-checkcontent f = do-	c <- readFile f-	assertEqual ("checkcontent " ++ f) c (content f)--checkunwritable :: FilePath -> Assertion-checkunwritable f = do-	-- Look at permissions bits rather than trying to write or using-	-- fileAccess because if run as root, any file can be modified-	-- despite permissions.-	s <- getFileStatus f-	let mode = fileMode s-	if (mode == mode `unionFileModes` ownerWriteMode)-		then assertFailure $ "able to modify annexed file's " ++ f ++ " content"-		else return ()--checkwritable :: FilePath -> Assertion-checkwritable f = do-	r <- tryIO $ writeFile f $ content f-	case r of-		Left _ -> assertFailure $ "unable to modify " ++ f-		Right _ -> return ()--checkdangling :: FilePath -> Assertion-checkdangling f = do-	r <- tryIO $ readFile f-	case r of-		Left _ -> return () -- expected; dangling link-		Right _ -> assertFailure $ f ++ " was not a dangling link as expected"--checklocationlog :: FilePath -> Bool -> Assertion-checklocationlog f expected = do-	thisuuid <- annexeval Annex.UUID.getUUID-	r <- annexeval $ Backend.lookupFile f-	case r of-		Just (k, _) -> do-			uuids <- annexeval $ Remote.keyLocations k-			assertEqual ("bad content in location log for " ++ f ++ " key " ++ (Types.Key.key2file k) ++ " uuid " ++ show thisuuid)-				expected (thisuuid `elem` uuids)-		_ -> assertFailure $ f ++ " failed to look up key"--checkbackend :: FilePath -> Types.Backend -> Assertion-checkbackend file expected = do-	r <- annexeval $ Backend.lookupFile file-	let b = snd $ fromJust r-	assertEqual ("backend for " ++ file) expected b--inlocationlog :: FilePath -> Assertion-inlocationlog f = checklocationlog f True--notinlocationlog :: FilePath -> Assertion-notinlocationlog f = checklocationlog f False--runchecks :: [FilePath -> Assertion] -> FilePath -> Assertion-runchecks [] _ = return ()-runchecks (a:as) f = do-	a f-	runchecks as f--annexed_notpresent :: FilePath -> Assertion-annexed_notpresent = runchecks-	[checklink, checkdangling, notinlocationlog]--annexed_present :: FilePath -> Assertion-annexed_present = runchecks-	[checklink, checkcontent, checkunwritable, inlocationlog]--unannexed :: FilePath -> Assertion-unannexed = runchecks [checkregularfile, checkcontent, checkwritable]--prepare :: IO ()-prepare = do-	-- While PATH is mostly avoided, the commit hook does run it,-	-- and so does git_annex_output. Make sure that the just-built-	-- git annex is used.-	cwd <- getCurrentDirectory-	p <- getEnvDefault  "PATH" ""-	setEnv "PATH" (cwd ++ ":" ++ p) True-	setEnv "TOPDIR" cwd True-	-- Avoid git complaining if it cannot determine the user's email-	-- address, or exploding if it doesn't know the user's name.-	setEnv "GIT_AUTHOR_EMAIL" "test@example.com" True-	setEnv "GIT_AUTHOR_NAME" "git-annex test" True-	setEnv "GIT_COMMITTER_EMAIL" "test@example.com" True-	setEnv "GIT_COMMITTER_NAME" "git-annex test" True--changeToTmpDir :: FilePath -> IO ()-changeToTmpDir t = do-	-- Hack alert. Threading state to here was too much bother.-	topdir <- getEnvDefault "TOPDIR" ""-	changeWorkingDirectory $ topdir ++ "/" ++ t--tmpdir :: String-tmpdir = ".t"--mainrepodir :: FilePath-mainrepodir = tmpdir ++ "/repo"--tmprepodir :: IO FilePath-tmprepodir = go (0 :: Int)-  where-	go n = do-		let d = tmpdir ++ "/tmprepo" ++ show n-		ifM (doesDirectoryExist d)-			( go $ n + 1-			, return d-			)--annexedfile :: String-annexedfile = "foo"--wormannexedfile :: String-wormannexedfile = "apple"--sha1annexedfile :: String-sha1annexedfile = "sha1foo"--sha1annexedfiledup :: String-sha1annexedfiledup = "sha1foodup"--ingitfile :: String-ingitfile = "bar"--content :: FilePath -> String		-content f-	| f == annexedfile = "annexed file content"-	| f == ingitfile = "normal file content"-	| f == sha1annexedfile ="sha1 annexed file content"-	| f == sha1annexedfiledup = content sha1annexedfile-	| f == wormannexedfile = "worm annexed file content"-	| otherwise = "unknown file " ++ f--changecontent :: FilePath -> IO ()-changecontent f = writeFile f $ changedcontent f--changedcontent :: FilePath -> String-changedcontent f = (content f) ++ " (modified)"--backendSHA1 :: Types.Backend-backendSHA1 = backend_ "SHA1"--backendSHA256 :: Types.Backend-backendSHA256 = backend_ "SHA256"--backendWORM :: Types.Backend-backendWORM = backend_ "WORM"--backend_ :: String -> Types.Backend-backend_ name = Backend.lookupBackendName name