diff options
Diffstat (limited to 'Annex')
-rw-r--r-- | Annex/AdjustedBranch.hs | 6 | ||||
-rw-r--r-- | Annex/Branch.hs | 6 | ||||
-rw-r--r-- | Annex/CatFile.hs | 1 | ||||
-rw-r--r-- | Annex/ChangedRefs.hs | 108 | ||||
-rw-r--r-- | Annex/Content.hs | 4 | ||||
-rw-r--r-- | Annex/Content/Direct.hs | 6 | ||||
-rw-r--r-- | Annex/DirHashes.hs | 1 | ||||
-rw-r--r-- | Annex/FileMatcher.hs | 2 | ||||
-rw-r--r-- | Annex/Init.hs | 2 | ||||
-rw-r--r-- | Annex/Journal.hs | 3 | ||||
-rw-r--r-- | Annex/Link.hs | 2 | ||||
-rw-r--r-- | Annex/Locations.hs | 5 | ||||
-rw-r--r-- | Annex/Notification.hs | 6 | ||||
-rw-r--r-- | Annex/SpecialRemote.hs | 3 | ||||
-rw-r--r-- | Annex/Ssh.hs | 40 | ||||
-rw-r--r-- | Annex/Transfer.hs | 5 | ||||
-rw-r--r-- | Annex/VariantFile.hs | 1 | ||||
-rw-r--r-- | Annex/View.hs | 4 |
18 files changed, 146 insertions, 59 deletions
diff --git a/Annex/AdjustedBranch.hs b/Annex/AdjustedBranch.hs index 4caf637c7..72c07a5bc 100644 --- a/Annex/AdjustedBranch.hs +++ b/Annex/AdjustedBranch.hs @@ -596,7 +596,7 @@ checkAdjustedClone = ifM isBareRepo aps <- fmap commitParent <$> findAdjustingCommit (AdjBranch currbranch) case aps of Just [p] -> setBasisBranch basis p - _ -> error $ "Unable to clean up from clone of adjusted branch; perhaps you should check out " ++ Git.Ref.describe origbranch + _ -> giveup $ "Unable to clean up from clone of adjusted branch; perhaps you should check out " ++ Git.Ref.describe origbranch ifM versionSupportsUnlockedPointers ( return InAdjustedClone , return NeedUpgradeForAdjustedClone @@ -610,6 +610,6 @@ isGitVersionSupported = not <$> Git.Version.older "2.2.0" checkVersionSupported :: Annex () checkVersionSupported = do unlessM versionSupportsAdjustedBranch $ - error "Adjusted branches are only supported in v6 or newer repositories." + giveup "Adjusted branches are only supported in v6 or newer repositories." unlessM (liftIO isGitVersionSupported) $ - error "Your version of git is too old; upgrade it to 2.2.0 or newer to use adjusted branches." + giveup "Your version of git is too old; upgrade it to 2.2.0 or newer to use adjusted branches." diff --git a/Annex/Branch.hs b/Annex/Branch.hs index a426c76d8..c90958ab0 100644 --- a/Annex/Branch.hs +++ b/Annex/Branch.hs @@ -61,6 +61,7 @@ import qualified Annex.Queue import Annex.Branch.Transitions import qualified Annex import Annex.Hook +import Utility.FileSystemEncoding {- Name of the branch that is used to store git-annex's information. -} name :: Git.Ref @@ -225,7 +226,7 @@ getHistorical date file = -- This check avoids some ugly error messages when the reflog -- is empty. ifM (null <$> inRepo (Git.RefLog.get' [Param (fromRef fullname), Param "-n1"])) - ( error ("No reflog for " ++ fromRef fullname) + ( giveup ("No reflog for " ++ fromRef fullname) , getRef (Git.Ref.dateRef fullname date) file ) @@ -436,7 +437,6 @@ stageJournal jl = withIndex $ do g <- gitRepo let dir = gitAnnexJournalDir g (jlogf, jlogh) <- openjlog - liftIO $ fileEncoding jlogh h <- hashObjectHandle withJournalHandle $ \jh -> Git.UpdateIndex.streamUpdateIndex g @@ -574,7 +574,7 @@ checkBranchDifferences ref = do <$> catFile ref differenceLog mydiffs <- annexDifferences <$> Annex.getGitConfig when (theirdiffs /= mydiffs) $ - error "Remote repository is tuned in incompatable way; cannot be merged with local repository." + giveup "Remote repository is tuned in incompatable way; cannot be merged with local repository." ignoreRefs :: [Git.Sha] -> Annex () ignoreRefs rs = do diff --git a/Annex/CatFile.hs b/Annex/CatFile.hs index b1d8fba28..25952dfec 100644 --- a/Annex/CatFile.hs +++ b/Annex/CatFile.hs @@ -33,6 +33,7 @@ import Git.FilePath import Git.Index import qualified Git.Ref import Annex.Link +import Utility.FileSystemEncoding catFile :: Git.Branch -> FilePath -> Annex L.ByteString catFile branch file = do diff --git a/Annex/ChangedRefs.hs b/Annex/ChangedRefs.hs new file mode 100644 index 000000000..1f2372c04 --- /dev/null +++ b/Annex/ChangedRefs.hs @@ -0,0 +1,108 @@ +{- Waiting for changed git refs + - + - Copyright 2014-216 Joey Hess <id@joeyh.name> + - + - Licensed under the GNU GPL version 3 or higher. + -} + +module Annex.ChangedRefs + ( ChangedRefs(..) + , ChangedRefsHandle + , waitChangedRefs + , drainChangedRefs + , stopWatchingChangedRefs + , watchChangedRefs + ) where + +import Annex.Common +import Utility.DirWatcher +import Utility.DirWatcher.Types +import qualified Git +import Git.Sha +import qualified Utility.SimpleProtocol as Proto + +import Control.Concurrent +import Control.Concurrent.STM +import Control.Concurrent.STM.TBMChan + +newtype ChangedRefs = ChangedRefs [Git.Ref] + deriving (Show) + +instance Proto.Serializable ChangedRefs where + serialize (ChangedRefs l) = unwords $ map Git.fromRef l + deserialize = Just . ChangedRefs . map Git.Ref . words + +data ChangedRefsHandle = ChangedRefsHandle DirWatcherHandle (TBMChan Git.Sha) + +-- | Wait for one or more git refs to change. +-- +-- When possible, coalesce ref writes that occur closely together +-- in time. Delay up to 0.05 seconds to get more ref writes. +waitChangedRefs :: ChangedRefsHandle -> IO ChangedRefs +waitChangedRefs (ChangedRefsHandle _ chan) = do + v <- atomically $ readTBMChan chan + case v of + Nothing -> return $ ChangedRefs [] + Just r -> do + threadDelay 50000 + rs <- atomically $ loop [] + return $ ChangedRefs (r:rs) + where + loop rs = do + v <- tryReadTBMChan chan + case v of + Just (Just r) -> loop (r:rs) + _ -> return rs + +-- | Remove any changes that might be buffered in the channel, +-- without waiting for any new changes. +drainChangedRefs :: ChangedRefsHandle -> IO () +drainChangedRefs (ChangedRefsHandle _ chan) = atomically go + where + go = do + v <- tryReadTBMChan chan + case v of + Just (Just _) -> go + _ -> return () + +stopWatchingChangedRefs :: ChangedRefsHandle -> IO () +stopWatchingChangedRefs h@(ChangedRefsHandle wh chan) = do + stopWatchDir wh + atomically $ closeTBMChan chan + drainChangedRefs h + +watchChangedRefs :: Annex (Maybe ChangedRefsHandle) +watchChangedRefs = do + -- This channel is used to accumulate notifications, + -- because the DirWatcher might have multiple threads that find + -- changes at the same time. It is bounded to allow a watcher + -- to be started once and reused, without too many changes being + -- buffered in memory. + chan <- liftIO $ newTBMChanIO 100 + + g <- gitRepo + let refdir = Git.localGitDir g </> "refs" + liftIO $ createDirectoryIfMissing True refdir + + let notifyhook = Just $ notifyHook chan + let hooks = mkWatchHooks + { addHook = notifyhook + , modifyHook = notifyhook + } + + if canWatch + then do + h <- liftIO $ watchDir refdir (const False) True hooks id + return $ Just $ ChangedRefsHandle h chan + else return Nothing + +notifyHook :: TBMChan Git.Sha -> FilePath -> Maybe FileStatus -> IO () +notifyHook chan reffile _ + | ".lock" `isSuffixOf` reffile = noop + | otherwise = void $ do + sha <- catchDefaultIO Nothing $ + extractSha <$> readFile reffile + -- When the channel is full, there is probably no reader + -- running, or ref changes have been occuring very fast, + -- so it's ok to not write the change to it. + maybe noop (void . atomically . tryWriteTBMChan chan) sha diff --git a/Annex/Content.hs b/Annex/Content.hs index cb96a0068..e879e4eeb 100644 --- a/Annex/Content.hs +++ b/Annex/Content.hs @@ -268,8 +268,8 @@ lockContentUsing locker key a = do (unlock lockfile) (const a) where - alreadylocked = error "content is locked" - failedtolock e = error $ "failed to lock content: " ++ show e + alreadylocked = giveup "content is locked" + failedtolock e = giveup $ "failed to lock content: " ++ show e lock contentfile lockfile = (maybe alreadylocked return diff --git a/Annex/Content/Direct.hs b/Annex/Content/Direct.hs index 2007360e3..734a0c1b9 100644 --- a/Annex/Content/Direct.hs +++ b/Annex/Content/Direct.hs @@ -52,8 +52,7 @@ associatedFiles key = do associatedFilesRelative :: Key -> Annex [FilePath] associatedFilesRelative key = do mapping <- calcRepo $ gitAnnexMapping key - liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h -> do - fileEncoding h + liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h -> -- Read strictly to ensure the file is closed -- before changeAssociatedFiles tries to write to it. -- (Especially needed on Windows.) @@ -68,8 +67,7 @@ changeAssociatedFiles key transform = do let files' = transform files when (files /= files') $ modifyContent mapping $ - liftIO $ viaTmp writeFileAnyEncoding mapping $ - unlines files' + liftIO $ viaTmp writeFile mapping $ unlines files' top <- fromRepo Git.repoPath return $ map (top </>) files' diff --git a/Annex/DirHashes.hs b/Annex/DirHashes.hs index 004536ca7..ed20cfb8a 100644 --- a/Annex/DirHashes.hs +++ b/Annex/DirHashes.hs @@ -26,6 +26,7 @@ import Common import Types.Key import Types.GitConfig import Types.Difference +import Utility.FileSystemEncoding type Hasher = Key -> FilePath diff --git a/Annex/FileMatcher.hs b/Annex/FileMatcher.hs index fa46e64b1..654c5a960 100644 --- a/Annex/FileMatcher.hs +++ b/Annex/FileMatcher.hs @@ -165,7 +165,7 @@ largeFilesMatcher = go =<< annexLargeFiles <$> Annex.getGitConfig mkmatcher expr = do parser <- mkLargeFilesParser either badexpr return $ parsedToMatcher $ parser expr - badexpr e = error $ "bad annex.largefiles configuration: " ++ e + badexpr e = giveup $ "bad annex.largefiles configuration: " ++ e simply :: MatchFiles Annex -> ParseResult simply = Right . Operation diff --git a/Annex/Init.hs b/Annex/Init.hs index 5aff4cf39..8a208fe2b 100644 --- a/Annex/Init.hs +++ b/Annex/Init.hs @@ -129,7 +129,7 @@ ensureInitialized = getVersion >>= maybe needsinit checkUpgrade where needsinit = ifM Annex.Branch.hasSibling ( initialize Nothing Nothing - , error "First run: git-annex init" + , giveup "First run: git-annex init" ) {- Checks if a repository is initialized. Does not check version for ugrade. -} diff --git a/Annex/Journal.hs b/Annex/Journal.hs index e4faa4865..184bb0ab0 100644 --- a/Annex/Journal.hs +++ b/Annex/Journal.hs @@ -37,7 +37,6 @@ setJournalFile _jl file content = do let tmpfile = tmp </> takeFileName jfile liftIO $ do withFile tmpfile WriteMode $ \h -> do - fileEncoding h #ifdef mingw32_HOST_OS hSetNewlineMode h noNewlineTranslation #endif @@ -53,7 +52,7 @@ getJournalFile _jl = getJournalFileStale - changes. -} getJournalFileStale :: FilePath -> Annex (Maybe String) getJournalFileStale file = inRepo $ \g -> catchMaybeIO $ - readFileStrictAnyEncoding $ journalFile file g + readFileStrict $ journalFile file g {- List of files that have updated content in the journal. -} getJournalledFiles :: JournalLocked -> Annex [FilePath] diff --git a/Annex/Link.hs b/Annex/Link.hs index 90312a04a..fcc300bee 100644 --- a/Annex/Link.hs +++ b/Annex/Link.hs @@ -24,6 +24,7 @@ import Git.Types import Git.FilePath import Annex.HashObject import Utility.FileMode +import Utility.FileSystemEncoding import qualified Data.ByteString.Lazy as L @@ -63,7 +64,6 @@ getAnnexLinkTarget' file coresymlinks = if coresymlinks Nothing -> fallback probefilecontent f = withFile f ReadMode $ \h -> do - fileEncoding h -- The first 8k is more than enough to read; link -- files are small. s <- take 8192 <$> hGetContents h diff --git a/Annex/Locations.hs b/Annex/Locations.hs index 9f829fda1..a6af4d417 100644 --- a/Annex/Locations.hs +++ b/Annex/Locations.hs @@ -63,7 +63,6 @@ module Annex.Locations ( gitAnnexUrlFile, gitAnnexTmpCfgFile, gitAnnexSshDir, - gitAnnexSshConfig, gitAnnexRemotesDir, gitAnnexAssistantDefaultDir, HashLevels(..), @@ -403,10 +402,6 @@ gitAnnexTmpCfgFile r = gitAnnexDir r </> "config.tmp" gitAnnexSshDir :: Git.Repo -> FilePath gitAnnexSshDir r = addTrailingPathSeparator $ gitAnnexDir r </> "ssh" -{- .git/annex/ssh.config is used to configure ssh. -} -gitAnnexSshConfig :: Git.Repo -> FilePath -gitAnnexSshConfig r = gitAnnexDir r </> "ssh.config" - {- .git/annex/remotes/ is used for remote-specific state. -} gitAnnexRemotesDir :: Git.Repo -> FilePath gitAnnexRemotesDir r = addTrailingPathSeparator $ gitAnnexDir r </> "remotes" diff --git a/Annex/Notification.hs b/Annex/Notification.hs index 4f492878b..e61b362ad 100644 --- a/Annex/Notification.hs +++ b/Annex/Notification.hs @@ -7,7 +7,7 @@ {-# LANGUAGE CPP #-} -module Annex.Notification (NotifyWitness, notifyTransfer, notifyDrop) where +module Annex.Notification (NotifyWitness, noNotification, notifyTransfer, notifyDrop) where import Annex.Common import Types.Transfer @@ -21,6 +21,10 @@ import qualified DBus.Client -- Witness that notification has happened. data NotifyWitness = NotifyWitness +-- Only use when no notification should be done. +noNotification :: NotifyWitness +noNotification = NotifyWitness + {- Wrap around an action that performs a transfer, which may run multiple - attempts. Displays notification when supported and when the user asked - for it. -} diff --git a/Annex/SpecialRemote.hs b/Annex/SpecialRemote.hs index 02799db85..0fd24f023 100644 --- a/Annex/SpecialRemote.hs +++ b/Annex/SpecialRemote.hs @@ -13,12 +13,11 @@ import Types.Remote (RemoteConfig, RemoteConfigKey, typename, setup) import Logs.Remote import Logs.Trust import qualified Git.Config +import Git.Types (RemoteName) import qualified Data.Map as M import Data.Ord -type RemoteName = String - {- See if there's an existing special remote with this name. - - Prefer remotes that are not dead when a name appears multiple times. -} diff --git a/Annex/Ssh.hs b/Annex/Ssh.hs index 4377de4c5..512f0375c 100644 --- a/Annex/Ssh.hs +++ b/Annex/Ssh.hs @@ -33,7 +33,7 @@ import qualified Git.Url import Config import Annex.Path import Utility.Env -import Utility.Tmp +import Utility.FileSystemEncoding import Types.CleanupActions import Git.Env #ifndef mingw32_HOST_OS @@ -50,37 +50,13 @@ sshOptions (host, port) gc opts = go =<< sshCachingInfo (host, port) go (Just socketfile, params) = do prepSocket socketfile ret params - ret ps = do - overideconfigfile <- fromRepo gitAnnexSshConfig - -- We assume that the file content does not change. - -- If it did, a more expensive test would be needed. - liftIO $ unlessM (doesFileExist overideconfigfile) $ - viaTmp writeFile overideconfigfile $ unlines - -- Make old version of ssh that does - -- not know about Include ignore those - -- entries. - [ "IgnoreUnknown Include" - -- ssh expands "~" - , "Include ~/.ssh/config" - -- ssh will silently skip the file - -- if it does not exist - , "Include /etc/ssh/ssh_config" - -- Everything below this point is only - -- used if there's no setting for it in - -- the above files. - -- - -- Make sure that ssh detects stalled - -- connections. - , "ServerAliveInterval 60" - ] - return $ concat - [ ps - , [Param "-F", File overideconfigfile] - , map Param (remoteAnnexSshOptions gc) - , opts - , portParams port - , [Param "-T"] - ] + ret ps = return $ concat + [ ps + , map Param (remoteAnnexSshOptions gc) + , opts + , portParams port + , [Param "-T"] + ] {- Returns a filename to use for a ssh connection caching socket, and - parameters to enable ssh connection caching. -} diff --git a/Annex/Transfer.hs b/Annex/Transfer.hs index 323600e96..b33dace4a 100644 --- a/Annex/Transfer.hs +++ b/Annex/Transfer.hs @@ -45,6 +45,11 @@ instance Observable (Bool, Verification) where observeBool = fst observeFailure = (False, UnVerified) +instance Observable (Either e Bool) where + observeBool (Left _) = False + observeBool (Right b) = b + observeFailure = Right False + upload :: Observable v => UUID -> Key -> AssociatedFile -> RetryDecider -> (MeterUpdate -> Annex v) -> NotifyWitness -> Annex v upload u key f d a _witness = guardHaveUUID u $ runTransfer (Transfer Upload u key) f d a diff --git a/Annex/VariantFile.hs b/Annex/VariantFile.hs index 9bf027b5c..17658a9c6 100644 --- a/Annex/VariantFile.hs +++ b/Annex/VariantFile.hs @@ -8,6 +8,7 @@ module Annex.VariantFile where import Annex.Common +import Utility.FileSystemEncoding import Data.Hash.MD5 diff --git a/Annex/View.hs b/Annex/View.hs index 7d2b43e60..d865c8f78 100644 --- a/Annex/View.hs +++ b/Annex/View.hs @@ -110,7 +110,7 @@ refineView origview = checksize . calc Unchanged origview in (view', Narrowing) checksize r@(v, _) - | viewTooLarge v = error $ "View is too large (" ++ show (visibleViewSize v) ++ " levels of subdirectories)" + | viewTooLarge v = giveup $ "View is too large (" ++ show (visibleViewSize v) ++ " levels of subdirectories)" | otherwise = r updateViewComponent :: ViewComponent -> MetaField -> ViewFilter -> Writer [ViewChange] ViewComponent @@ -424,4 +424,4 @@ genViewBranch view = withViewIndex $ do return branch withCurrentView :: (View -> Annex a) -> Annex a -withCurrentView a = maybe (error "Not in a view.") a =<< currentView +withCurrentView a = maybe (giveup "Not in a view.") a =<< currentView |