summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-01-23 15:09:43 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-01-23 15:09:43 -0400
commitc860d9e9716510d257a6f348e1740ff1a4fa3a56 (patch)
tree9342e115f644e7711b40be5b2655ce715b856cda
parentc071d676dce87ae6092100f6cde56faa6a462916 (diff)
add webapp UI to manage unused files
-rw-r--r--Assistant/Alert.hs2
-rw-r--r--Assistant/Threads/SanityChecker.hs56
-rw-r--r--Assistant/Unused.hs86
-rw-r--r--Logs/Unused.hs8
-rw-r--r--Utility/HumanTime.hs15
-rw-r--r--doc/assistant/unused.pngbin0 -> 49957 bytes
6 files changed, 116 insertions, 51 deletions
diff --git a/Assistant/Alert.hs b/Assistant/Alert.hs
index b5ee706b8..58264cfbf 100644
--- a/Assistant/Alert.hs
+++ b/Assistant/Alert.hs
@@ -1,6 +1,6 @@
{- git-annex assistant alerts
-
- - Copyright 2012, 2013 Joey Hess <joey@kitenet.net>
+ - Copyright 2012-2014 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
diff --git a/Assistant/Threads/SanityChecker.hs b/Assistant/Threads/SanityChecker.hs
index bdde1726d..8a513a43b 100644
--- a/Assistant/Threads/SanityChecker.hs
+++ b/Assistant/Threads/SanityChecker.hs
@@ -21,7 +21,6 @@ import Assistant.Ssh
import Assistant.TransferQueue
import Assistant.Types.UrlRenderer
import qualified Annex.Branch
-import qualified Git
import qualified Git.LsFiles
import qualified Git.Command
import qualified Git.Config
@@ -30,25 +29,21 @@ import qualified Assistant.Threads.Watcher as Watcher
import Utility.LogFile
import Utility.Batch
import Utility.NotificationBroadcaster
-import Utility.DiskFree
import Config
import Utility.HumanTime
-import Utility.DataUnits
+import Utility.Tense
import Git.Repair
import Git.Index
+import Assistant.Unused
import Logs.Unused
-import Logs.Location
import Logs.Transfer
-import Annex.Content
import Config.Files
-import Types.Key
import qualified Annex
#ifdef WITH_WEBAPP
import Assistant.WebApp.Types
#endif
import Data.Time.Clock.POSIX
-import qualified Data.Map as M
import qualified Data.Text as T
{- This thread runs once at startup, and most other threads wait for it
@@ -226,56 +221,19 @@ oneDay = 24 * oneHour
- for the specified duration, and remove them.
-
- Otherwise, check to see if unused keys are piling up, and let the user
- - know. This uses heuristics: 1000 unused keys, or more unused keys
- - than the remaining free disk space, or more than 1/10th the total
- - disk space being unused keys all suggest a problem. -}
+ - know. -}
checkOldUnused :: UrlRenderer -> Assistant ()
checkOldUnused urlrenderer = go =<< annexExpireUnused <$> liftAnnex Annex.getGitConfig
where
go (Just Nothing) = noop
- go (Just (Just expireunused)) = do
- m <- liftAnnex $ readUnusedLog ""
- now <- liftIO getPOSIXTime
- let duration = durationToPOSIXTime expireunused
- let oldkeys = M.keys $ M.filter (tooold now duration) m
- forM_ oldkeys $ \k -> do
- debug ["removing old unused key", key2file k]
- liftAnnex $ do
- removeAnnex k
- logStatus k InfoMissing
- go Nothing = maybe noop prompt
- =<< toobig =<< liftAnnex (readUnusedLog "")
-
- tooold now duration (_, mt) =
- maybe False (\t -> now - t >= duration) mt
-
- toobig m = do
- let num = M.size m
- let diskused = foldl' sumkeysize 0 (M.keys m)
- df <- forpath getDiskFree
- disksize <- forpath getDiskSize
- return $ if moreused df diskused || tenthused disksize diskused
- then Just $ roughSize storageUnits False diskused ++
- " is used by old files"
- else if num > 1000
- then Just $ show num ++ " old files exist"
- else Nothing
-
- moreused Nothing _ = False
- moreused (Just df) used = df <= used
-
- tenthused Nothing _ = False
- tenthused (Just disksize) used = used >= disksize `div` 10
-
- sumkeysize s k = s + fromMaybe 0 (keySize k)
-
- forpath a = liftAnnex $ inRepo $ liftIO . a . Git.repoPath
+ go (Just (Just expireunused)) = expireUnused (Just expireunused)
+ go Nothing = maybe noop prompt =<< describeUnusedWhenBig
prompt msg =
#ifdef WITH_WEBAPP
do
- button <- mkAlertButton True (T.pack "Fix This") urlrenderer ConfigUnusedR
- void $ addAlert $ unusedFilesAlert [button] msg
+ button <- mkAlertButton True (T.pack "Configure") urlrenderer ConfigUnusedR
+ void $ addAlert $ unusedFilesAlert [button] $ T.unpack $ renderTense Present msg
#else
debug [msg]
#endif
diff --git a/Assistant/Unused.hs b/Assistant/Unused.hs
new file mode 100644
index 000000000..3ad98c12e
--- /dev/null
+++ b/Assistant/Unused.hs
@@ -0,0 +1,86 @@
+{- git-annex assistant unused files
+ -
+ - Copyright 2014 Joey Hess <joey@kitenet.net>
+ -
+ - Licensed under the GNU GPL version 3 or higher.
+ -}
+
+{-# LANGUAGE OverloadedStrings #-}
+
+module Assistant.Unused where
+
+import qualified Data.Map as M
+
+import Assistant.Common
+import qualified Git
+import Types.Key
+import Logs.Unused
+import Logs.Location
+import Annex.Content
+import Utility.DataUnits
+import Utility.DiskFree
+import Utility.HumanTime
+import Utility.Tense
+
+import Data.Time.Clock.POSIX
+import qualified Data.Text as T
+
+describeUnused :: Assistant (Maybe TenseText)
+describeUnused = describeUnused' False
+
+describeUnusedWhenBig :: Assistant (Maybe TenseText)
+describeUnusedWhenBig = describeUnused' True
+
+{- This uses heuristics: 1000 unused keys, or more unused keys
+ - than the remaining free disk space, or more than 1/10th the total
+ - disk space being unused keys all suggest a problem. -}
+describeUnused' :: Bool -> Assistant (Maybe TenseText)
+describeUnused' whenbig = liftAnnex $ go =<< readUnusedLog ""
+ where
+ go m = do
+ let num = M.size m
+ let diskused = foldl' sumkeysize 0 (M.keys m)
+ df <- forpath getDiskFree
+ disksize <- forpath getDiskSize
+ return $ if num == 0
+ then Nothing
+ else if not whenbig || moreused df diskused || tenthused disksize diskused
+ then Just $ tenseWords
+ [ UnTensed $ T.pack $ roughSize storageUnits False diskused
+ , Tensed "are" "were"
+ , "taken up by unused files"
+ ]
+ else if num > 1000
+ then Just $ tenseWords
+ [ UnTensed $ T.pack $ show num ++ " unused files"
+ , Tensed "exist" "existed"
+ ]
+ else Nothing
+
+ moreused Nothing _ = False
+ moreused (Just df) used = df <= used
+
+ tenthused Nothing _ = False
+ tenthused (Just disksize) used = used >= disksize `div` 10
+
+ sumkeysize s k = s + fromMaybe 0 (keySize k)
+
+ forpath a = inRepo $ liftIO . a . Git.repoPath
+
+{- With a duration, expires all unused files that are older.
+ - With Nothing, expires *all* unused files. -}
+expireUnused :: Maybe Duration -> Assistant ()
+expireUnused duration = do
+ m <- liftAnnex $ readUnusedLog ""
+ now <- liftIO getPOSIXTime
+ let oldkeys = M.keys $ M.filter (tooold now) m
+ forM_ oldkeys $ \k -> do
+ debug ["removing old unused key", key2file k]
+ liftAnnex $ do
+ removeAnnex k
+ logStatus k InfoMissing
+ where
+ boundry = durationToPOSIXTime <$> duration
+ tooold now (_, mt) = case boundry of
+ Nothing -> True
+ Just b -> maybe False (\t -> now - t >= b) mt
diff --git a/Logs/Unused.hs b/Logs/Unused.hs
index cdfcd2165..0af319f04 100644
--- a/Logs/Unused.hs
+++ b/Logs/Unused.hs
@@ -20,9 +20,10 @@ module Logs.Unused (
updateUnusedLog,
readUnusedLog,
readUnusedMap,
+ dateUnusedLog,
unusedKeys,
+ unusedKeys',
setUnusedKeys,
- unusedKeys'
) where
import qualified Data.Map as M
@@ -88,6 +89,11 @@ readUnusedLog prefix = do
readUnusedMap :: FilePath -> Annex UnusedMap
readUnusedMap = log2map <$$> readUnusedLog
+dateUnusedLog :: FilePath -> Annex (Maybe UTCTime)
+dateUnusedLog prefix = do
+ f <- fromRepo $ gitAnnexUnusedLog prefix
+ liftIO $ catchMaybeIO $ getModificationTime f
+
{- Set of unused keys. This is cached for speed. -}
unusedKeys :: Annex (S.Set Key)
unusedKeys = maybe (setUnusedKeys =<< unusedKeys') return
diff --git a/Utility/HumanTime.hs b/Utility/HumanTime.hs
index 644e6fbab..297b2bd97 100644
--- a/Utility/HumanTime.hs
+++ b/Utility/HumanTime.hs
@@ -7,7 +7,10 @@
module Utility.HumanTime (
Duration(..),
+ durationSince,
durationToPOSIXTime,
+ durationToDays,
+ daysToDuration,
parseDuration,
fromDuration,
prop_duration_roundtrips
@@ -17,6 +20,7 @@ import Utility.PartialPrelude
import Utility.Applicative
import Utility.QuickCheck
+import Data.Time.Clock
import Data.Time.Clock.POSIX (POSIXTime)
import Data.Char
import Control.Applicative
@@ -25,9 +29,20 @@ import qualified Data.Map as M
newtype Duration = Duration { durationSeconds :: Integer }
deriving (Eq, Ord, Read, Show)
+durationSince :: UTCTime -> IO Duration
+durationSince pasttime = do
+ now <- getCurrentTime
+ return $ Duration $ round $ diffUTCTime now pasttime
+
durationToPOSIXTime :: Duration -> POSIXTime
durationToPOSIXTime = fromIntegral . durationSeconds
+durationToDays :: Duration -> Integer
+durationToDays d = durationSeconds d `div` dsecs
+
+daysToDuration :: Integer -> Duration
+daysToDuration i = Duration $ i * dsecs
+
{- Parses a human-input time duration, of the form "5h", "1m", "5h1m", etc -}
parseDuration :: String -> Maybe Duration
parseDuration = Duration <$$> go 0
diff --git a/doc/assistant/unused.png b/doc/assistant/unused.png
new file mode 100644
index 000000000..b0ace763c
--- /dev/null
+++ b/doc/assistant/unused.png
Binary files differ