module Darcs.Repository.Identify
( maybeIdentifyRepository
, identifyRepository
, identifyRepositoryFor
, IdentifyRepo(..)
, ReadingOrWriting(..)
, findRepository
, amInRepository
, amNotInRepository
, amInHashedRepository
, seekRepo
, findAllReposInDir
) where
import Darcs.Prelude
import Control.Monad ( forM )
import Darcs.Repository.Format ( tryIdentifyRepoFormat
, readProblem
, transferProblem
)
import System.Directory ( doesDirectoryExist
, setCurrentDirectory
, createDirectoryIfMissing
, doesFileExist
, listDirectory
)
import System.FilePath.Posix ( (</>) )
import System.IO ( hPutStrLn, stderr )
import System.IO.Error ( catchIOError )
import Data.Maybe ( fromMaybe )
import Darcs.Repository.Old ( oldRepoFailMsg )
import Darcs.Repository.Flags ( UseCache(..), WorkRepo (..) )
import Darcs.Util.Path
( toFilePath
, ioAbsoluteOrRemote
, toPath
)
import Darcs.Util.Exception ( catchall )
import Darcs.Util.URL ( isValidLocalPath )
import Darcs.Util.Workaround
( getCurrentDirectory
)
import Darcs.Repository.Paths
( hashedInventoryPath
, oldCurrentDirPath
, oldPristineDirPath
)
import Darcs.Repository.Prefs ( getCaches )
import Darcs.Repository.InternalTypes( Repository
, PristineType(..)
, mkRepo
, repoFormat
, repoPristineType
)
import Darcs.Util.Global ( darcsdir )
import System.Mem( performGC )
data IdentifyRepo rt p wR wU wT
= BadRepository String
| NonRepository String
| GoodRepository (Repository rt p wR wU wT)
maybeIdentifyRepository :: UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository :: forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
useCache String
"." =
do Bool
darcs <- String -> IO Bool
doesDirectoryExist String
darcsdir
if Bool -> Bool
not Bool
darcs
then forall (m :: * -> *) a. Monad m => a -> m a
return (forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String -> IdentifyRepo rt p wR wU wT
NonRepository forall a b. (a -> b) -> a -> b
$ String
"Missing " forall a. [a] -> [a] -> [a]
++ String
darcsdir forall a. [a] -> [a] -> [a]
++ String
" directory")
else do
Either String RepoFormat
repoFormatOrError <- String -> IO (Either String RepoFormat)
tryIdentifyRepoFormat String
"."
String
here <- forall a. FilePathOrURL a => a -> String
toPath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` String -> IO AbsoluteOrRemotePath
ioAbsoluteOrRemote String
"."
case Either String RepoFormat
repoFormatOrError of
Left String
err -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String -> IdentifyRepo rt p wR wU wT
NonRepository String
err
Right RepoFormat
rf ->
case RepoFormat -> Maybe String
readProblem RepoFormat
rf of
Just String
err -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String -> IdentifyRepo rt p wR wU wT
BadRepository String
err
Maybe String
Nothing -> do PristineType
pris <- IO PristineType
identifyPristine
Cache
cs <- UseCache -> String -> IO Cache
getCaches UseCache
useCache String
here
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> IdentifyRepo rt p wR wU wT
GoodRepository forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String
-> RepoFormat -> PristineType -> Cache -> Repository rt p wR wU wT
mkRepo String
here RepoFormat
rf PristineType
pris Cache
cs
maybeIdentifyRepository UseCache
useCache String
url' =
do String
url <- forall a. FilePathOrURL a => a -> String
toPath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` String -> IO AbsoluteOrRemotePath
ioAbsoluteOrRemote String
url'
Either String RepoFormat
repoFormatOrError <- String -> IO (Either String RepoFormat)
tryIdentifyRepoFormat String
url
case Either String RepoFormat
repoFormatOrError of
Left String
e -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String -> IdentifyRepo rt p wR wU wT
NonRepository String
e
Right RepoFormat
rf -> case RepoFormat -> Maybe String
readProblem RepoFormat
rf of
Just String
err -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String -> IdentifyRepo rt p wR wU wT
BadRepository String
err
Maybe String
Nothing -> do Cache
cs <- UseCache -> String -> IO Cache
getCaches UseCache
useCache String
url
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> IdentifyRepo rt p wR wU wT
GoodRepository forall a b. (a -> b) -> a -> b
$ forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
String
-> RepoFormat -> PristineType -> Cache -> Repository rt p wR wU wT
mkRepo String
url RepoFormat
rf PristineType
NoPristine Cache
cs
identifyPristine :: IO PristineType
identifyPristine :: IO PristineType
identifyPristine =
do Bool
pristine <- String -> IO Bool
doesDirectoryExist String
oldPristineDirPath
Bool
current <- String -> IO Bool
doesDirectoryExist String
oldCurrentDirPath
Bool
hashinv <- String -> IO Bool
doesFileExist String
hashedInventoryPath
case (Bool
pristine Bool -> Bool -> Bool
|| Bool
current, Bool
hashinv) of
(Bool
False, Bool
False) -> forall (m :: * -> *) a. Monad m => a -> m a
return PristineType
NoPristine
(Bool
True, Bool
False) -> forall (m :: * -> *) a. Monad m => a -> m a
return PristineType
PlainPristine
(Bool
False, Bool
True ) -> forall (m :: * -> *) a. Monad m => a -> m a
return PristineType
HashedPristine
(Bool, Bool)
_ -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Multiple pristine trees."
identifyRepository :: UseCache -> String -> IO (Repository rt p wR wU wT)
identifyRepository :: forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (Repository rt p wR wU wT)
identifyRepository UseCache
useCache String
url =
do IdentifyRepo rt p wR wU wT
er <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
useCache String
url
case IdentifyRepo rt p wR wU wT
er of
BadRepository String
s -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s
NonRepository String
s -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
s
GoodRepository Repository rt p wR wU wT
r -> forall (m :: * -> *) a. Monad m => a -> m a
return Repository rt p wR wU wT
r
data ReadingOrWriting = Reading | Writing
identifyRepositoryFor :: ReadingOrWriting
-> Repository rt p wR wU wT
-> UseCache
-> String
-> IO (Repository rt p vR vU vT)
identifyRepositoryFor :: forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT vR vU vT.
ReadingOrWriting
-> Repository rt p wR wU wT
-> UseCache
-> String
-> IO (Repository rt p vR vU vT)
identifyRepositoryFor ReadingOrWriting
what Repository rt p wR wU wT
us UseCache
useCache String
them_loc = do
Repository rt p vR vU vT
them <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (Repository rt p wR wU wT)
identifyRepository UseCache
useCache String
them_loc
case
case ReadingOrWriting
what of
ReadingOrWriting
Reading -> RepoFormat -> RepoFormat -> Maybe String
transferProblem (forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> RepoFormat
repoFormat Repository rt p vR vU vT
them) (forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> RepoFormat
repoFormat Repository rt p wR wU wT
us)
ReadingOrWriting
Writing -> RepoFormat -> RepoFormat -> Maybe String
transferProblem (forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> RepoFormat
repoFormat Repository rt p wR wU wT
us) (forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> RepoFormat
repoFormat Repository rt p vR vU vT
them)
of
Just String
e -> forall (m :: * -> *) a. MonadFail m => String -> m a
fail forall a b. (a -> b) -> a -> b
$ String
"Incompatibility with repository " forall a. [a] -> [a] -> [a]
++ String
them_loc forall a. [a] -> [a] -> [a]
++ String
":\n" forall a. [a] -> [a] -> [a]
++ String
e
Maybe String
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return Repository rt p vR vU vT
them
amInRepository :: WorkRepo -> IO (Either String ())
amInRepository :: WorkRepo -> IO (Either String ())
amInRepository (WorkRepoDir String
d) =
do
String -> IO ()
setCurrentDirectory String
d
IdentifyRepo Any Any Any Any Any
status <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
YesUseCache String
"."
case IdentifyRepo Any Any Any Any Any
status of
GoodRepository Repository Any Any Any Any Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. b -> Either a b
Right ())
BadRepository String
e -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"While " forall a. [a] -> [a] -> [a]
++ String
d forall a. [a] -> [a] -> [a]
++ String
" looks like a repository directory, we have a problem with it:\n" forall a. [a] -> [a] -> [a]
++ String
e)
NonRepository String
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left String
"You need to be in a repository directory to run this command.")
forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError`
\IOError
e -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left (forall a. Show a => a -> String
show IOError
e))
amInRepository WorkRepo
_ =
forall a. a -> Maybe a -> a
fromMaybe (forall a b. a -> Either a b
Left String
"You need to be in a repository directory to run this command.") forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Maybe (Either String ()))
seekRepo
amInHashedRepository :: WorkRepo -> IO (Either String ())
amInHashedRepository :: WorkRepo -> IO (Either String ())
amInHashedRepository WorkRepo
wd
= do Either String ()
inrepo <- WorkRepo -> IO (Either String ())
amInRepository WorkRepo
wd
case Either String ()
inrepo of
Right ()
_ -> do PristineType
pristine <- IO PristineType
identifyPristine
case PristineType
pristine of
PristineType
HashedPristine -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. b -> Either a b
Right ())
PristineType
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left String
oldRepoFailMsg)
Either String ()
left -> forall (m :: * -> *) a. Monad m => a -> m a
return Either String ()
left
seekRepo :: IO (Maybe (Either String ()))
seekRepo :: IO (Maybe (Either String ()))
seekRepo = IO String
getCurrentDirectory forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO (Maybe (Either String ()))
helper where
helper :: String -> IO (Maybe (Either String ()))
helper String
startpwd = do
IdentifyRepo Any Any Any Any Any
status <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
YesUseCache String
"."
case IdentifyRepo Any Any Any Any Any
status of
GoodRepository Repository Any Any Any Any Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
BadRepository String
e -> forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left String
e
NonRepository String
_ ->
forall a. IO a -> (IOError -> IO a) -> IO a
catchIOError
(do String
cd <- forall a. FilePathLike a => a -> String
toFilePath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO String
getCurrentDirectory
String -> IO ()
setCurrentDirectory String
".."
String
cd' <- forall a. FilePathLike a => a -> String
toFilePath forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO String
getCurrentDirectory
if String
cd' forall a. Eq a => a -> a -> Bool
/= String
cd
then String -> IO (Maybe (Either String ()))
helper String
startpwd
else do
String -> IO ()
setCurrentDirectory String
startpwd
forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing)
(\IOError
e -> do
Handle -> String -> IO ()
hPutStrLn Handle
stderr (String
"Warning: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show IOError
e)
forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing)
amNotInRepository :: WorkRepo -> IO (Either String ())
amNotInRepository :: WorkRepo -> IO (Either String ())
amNotInRepository (WorkRepoDir String
d) = do
Bool -> String -> IO ()
createDirectoryIfMissing Bool
False String
d
forall a. IO a -> IO a -> IO a
`catchall` (IO ()
performGC forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> String -> IO ()
createDirectoryIfMissing Bool
False String
d)
String -> IO ()
setCurrentDirectory String
d
WorkRepo -> IO (Either String ())
amNotInRepository WorkRepo
WorkRepoCurrentDir
amNotInRepository WorkRepo
_ = do
IdentifyRepo Any Any Any Any Any
status <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
YesUseCache String
"."
case IdentifyRepo Any Any Any Any Any
status of
GoodRepository Repository Any Any Any Any Any
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left String
"You may not run this command in a repository.")
BadRepository String
e -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"You may not run this command in a repository.\nBy the way, we have a problem with it:\n" forall a. [a] -> [a] -> [a]
++ String
e)
NonRepository String
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. b -> Either a b
Right ())
findRepository :: WorkRepo -> IO (Either String ())
findRepository :: WorkRepo -> IO (Either String ())
findRepository WorkRepo
workrepo =
case WorkRepo
workrepo of
WorkRepoPossibleURL String
d | String -> Bool
isValidLocalPath String
d -> do
String -> IO ()
setCurrentDirectory String
d
WorkRepo -> IO (Either String ())
findRepository WorkRepo
WorkRepoCurrentDir
WorkRepoDir String
d -> do
String -> IO ()
setCurrentDirectory String
d
WorkRepo -> IO (Either String ())
findRepository WorkRepo
WorkRepoCurrentDir
WorkRepo
_ -> forall a. a -> Maybe a -> a
fromMaybe (forall a b. b -> Either a b
Right ()) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO (Maybe (Either String ()))
seekRepo
forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError` \IOError
e ->
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. a -> Either a b
Left (forall a. Show a => a -> String
show IOError
e))
findAllReposInDir :: FilePath -> IO [FilePath]
findAllReposInDir :: String -> IO [String]
findAllReposInDir String
topDir = do
Bool
isDir <- String -> IO Bool
doesDirectoryExist String
topDir
if Bool
isDir
then do
IdentifyRepo Any Any Any Any Any
status <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
UseCache -> String -> IO (IdentifyRepo rt p wR wU wT)
maybeIdentifyRepository UseCache
NoUseCache String
topDir
case IdentifyRepo Any Any Any Any Any
status of
GoodRepository Repository Any Any Any Any Any
repo
| PristineType
HashedPristine <- forall (rt :: RepoType) (p :: * -> * -> *) wR wU wT.
Repository rt p wR wU wT -> PristineType
repoPristineType Repository Any Any Any Any Any
repo -> forall (m :: * -> *) a. Monad m => a -> m a
return [String
topDir]
| Bool
otherwise -> forall (m :: * -> *) a. Monad m => a -> m a
return []
IdentifyRepo Any Any Any Any Any
_ -> String -> IO [String]
getRecursiveDarcsRepos' String
topDir
else forall (m :: * -> *) a. Monad m => a -> m a
return []
where
getRecursiveDarcsRepos' :: String -> IO [String]
getRecursiveDarcsRepos' String
d = do
[String]
names <- String -> IO [String]
listDirectory String
d
[[String]]
paths <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
names forall a b. (a -> b) -> a -> b
$ \String
name -> do
let path :: String
path = String
d String -> String -> String
</> String
name
String -> IO [String]
findAllReposInDir String
path
forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]]
paths)