2010-11-06 21:06:19 +00:00
|
|
|
{- git-annex command
|
|
|
|
-
|
|
|
|
- Copyright 2010 Joey Hess <joey@kitenet.net>
|
|
|
|
-
|
|
|
|
- Licensed under the GNU GPL version 3 or higher.
|
|
|
|
-}
|
|
|
|
|
|
|
|
module Command.Fsck where
|
|
|
|
|
2010-11-07 22:22:25 +00:00
|
|
|
import qualified Data.Map as M
|
|
|
|
import System.Directory
|
|
|
|
import System.Posix.Files
|
|
|
|
import Monad (filterM)
|
|
|
|
import Control.Monad.State (liftIO)
|
|
|
|
import Data.Maybe
|
|
|
|
|
2010-11-06 21:06:19 +00:00
|
|
|
import Command
|
|
|
|
import Types
|
|
|
|
import Core
|
2010-11-07 22:22:25 +00:00
|
|
|
import Locations
|
|
|
|
import qualified Annex
|
|
|
|
import qualified GitRepo as Git
|
|
|
|
import qualified Backend
|
2010-11-06 21:06:19 +00:00
|
|
|
|
|
|
|
{- Checks the whole annex for problems. -}
|
|
|
|
start :: SubCmdStart
|
|
|
|
start = do
|
|
|
|
showStart "fsck" ""
|
|
|
|
return $ Just perform
|
|
|
|
|
|
|
|
perform :: SubCmdPerform
|
|
|
|
perform = do
|
|
|
|
ok <- checkUnused
|
|
|
|
if (ok)
|
|
|
|
then return $ Just $ return True
|
|
|
|
else do
|
|
|
|
showLongNote "Possible problems detected."
|
|
|
|
return Nothing
|
|
|
|
|
|
|
|
checkUnused :: Annex Bool
|
|
|
|
checkUnused = do
|
|
|
|
showNote "checking for unused data..."
|
2010-11-07 21:26:21 +00:00
|
|
|
unused <- unusedKeys
|
|
|
|
if (null unused)
|
|
|
|
then return True
|
|
|
|
else do
|
|
|
|
showLongNote $ w unused
|
|
|
|
return False
|
|
|
|
where
|
|
|
|
w u = unlines $ [
|
2010-11-07 22:22:25 +00:00
|
|
|
"Some annexed data is no longer pointed to by any files in the repository.",
|
2010-11-07 21:26:21 +00:00
|
|
|
"If this data is no longer needed, it can be removed using git-annex dropkey:"
|
2010-11-07 22:22:25 +00:00
|
|
|
] ++ map (\k -> " " ++ show k) u
|
2010-11-07 21:26:21 +00:00
|
|
|
|
2010-11-07 22:22:25 +00:00
|
|
|
{- Finds keys whose content is present, but that do not seem to be used
|
|
|
|
- by any files in the git repo. -}
|
2010-11-07 21:26:21 +00:00
|
|
|
unusedKeys :: Annex [Key]
|
|
|
|
unusedKeys = do
|
|
|
|
present <- getKeysPresent
|
|
|
|
referenced <- getKeysReferenced
|
|
|
|
|
|
|
|
-- Constructing a single map, of the set that tends to be smaller,
|
|
|
|
-- appears more efficient in both memory and CPU than constructing
|
|
|
|
-- and taking the M.difference of two maps.
|
|
|
|
let present_m = existsMap present
|
|
|
|
let unused_m = remove referenced present_m
|
|
|
|
return $ M.keys unused_m
|
|
|
|
where
|
|
|
|
remove [] m = m
|
|
|
|
remove (x:xs) m = remove xs $ M.delete x m
|
|
|
|
|
|
|
|
existsMap :: Ord k => [k] -> M.Map k Int
|
|
|
|
existsMap l = M.fromList $ map (\k -> (k, 1)) l
|
|
|
|
|
|
|
|
getKeysPresent :: Annex [Key]
|
|
|
|
getKeysPresent = do
|
2010-11-07 22:22:25 +00:00
|
|
|
g <- Annex.gitRepo
|
|
|
|
let top = annexDir g
|
|
|
|
contents <- liftIO $ getDirectoryContents top
|
|
|
|
files <- liftIO $ filterM (isreg top) contents
|
|
|
|
return $ map fileKey files
|
|
|
|
where
|
|
|
|
isreg top f = do
|
|
|
|
s <- getFileStatus $ top ++ "/" ++ f
|
|
|
|
return $ isRegularFile s
|
2010-11-07 21:26:21 +00:00
|
|
|
|
|
|
|
getKeysReferenced :: Annex [Key]
|
|
|
|
getKeysReferenced = do
|
2010-11-07 22:22:25 +00:00
|
|
|
g <- Annex.gitRepo
|
|
|
|
files <- liftIO $ Git.inRepo g $ Git.workTree g
|
|
|
|
keypairs <- mapM Backend.lookupFile files
|
|
|
|
return $ map fst $ catMaybes keypairs
|