summaryrefslogtreecommitdiff
path: root/src/SensibleDir.hs
blob: c5f9ae1f34975a9895dce8ab335a7bd5a45a34c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
module SensibleDir where

import Paths_testcabaldir
import System.Directory
#ifdef VERSION_directory_xdg
import System.DirectoryXdg
#endif
import System.FilePath
import System.IO
import System.Info
import System.Environment
import Control.Arrow
import Control.Applicative
import Data.List

installScenario = NotInstalled
doit = do
    ddir <- getDataDir
    ldir <- getLibDir
    pname <- getProgName
    ppath <- getExecutablePath
    sysconfdir <- getSysconfDir
    putStrLn ("ddir = " ++ ddir);
    putStrLn ("ldir = " ++ ldir);
    putStrLn ("sysconfdir = " ++ sysconfdir);
    putStrLn ("pname = " ++ pname);
    putStr "runningInBuildDir = "
    print =<< runningInBuildDir
    putStr "detectLikelyInstall = "
    print =<< detectLikelyInstall
    putStrLn "---------------------"
    putStr "sensibleCacheDir = "
    print =<< sensibleCacheDir pname
    -- putStr "sensibleConfigDir = "
    -- print =<< sensibleConfigDir pname

runningInBuildDir :: IO Bool
runningInBuildDir = any (=="build") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath
    
runningInCabalDir :: IO Bool
runningInCabalDir = any (==".cabal") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath

runningInSysBin = do
    exedir <- splitDirectories . takeDirectory <$> getExecutablePath
    return $ 
      case take 3 (drop 1 exedir) of
        ["bin"]                -> True
        ["sbin"]               -> True
        ["usr","bin"]          -> True
        ["usr","sbin"]         -> True
        _ -> False

runningInLocalBin = do
    exedir <- splitDirectories . takeDirectory <$> getExecutablePath
    putStr "exedir = "
    print exedir
    return $ 
      case take 3 (drop 1 exedir) of
        ["usr","local","bin"]  -> True
        ["usr","local","sbin"] -> True
        _ -> False

-- scenarios
data InstallScenario = PrefixInstall
                     -- ^ installed in /opt or some other prefix, or running inside source folder
                     | SystemInstall
                     -- ^ installed system wide
                     | LocalInstall
                     -- ^ installed in /usr/local/
                     | UserInstall
                     -- ^ installed for a given user
                     | NotInstalled
                     -- ^ not installed, built by cabal or make, running from dist folder
    deriving (Show,Enum,Eq)

-- | careful, assumes unix-style FHS
--   windows aware contributions welcome
--   Detects the likely install scenario based on the path to the exectuable.
detectLikelyInstall :: IO InstallScenario
detectLikelyInstall = do
    bBuildDir <- fmap (,NotInstalled) runningInBuildDir
    bCabalDir <- fmap (,UserInstall)  runningInCabalDir
    bLocalDir <- fmap (,LocalInstall) runningInLocalBin
    bSysDir   <- fmap (,SystemInstall) runningInSysBin
    case dropWhile (not . fst) [bBuildDir,bCabalDir,bLocalDir,bSysDir] of
        (True,scenario):_ -> return scenario
        _                 -> return PrefixInstall

isUnix os = not $ "mingw" `isPrefixOf` os

-- | Try to get the cache directory appropriate to the install scenario.
--   On windows it just calls getAppUserDataDirectory and appends "cache". 
--   (windows behavior subject to change, contributions welcome)
sensibleCacheDir suffix = do
    let ifunix x = if isUnix os then x
                                else PrefixInstall
    install <- ifunix <$> detectLikelyInstall
    case install of
        PrefixInstall -> do
          if isUnix os
           then do
            dir <- splitDirectories . takeDirectory <$> getExecutablePath
            let rdir = reverse dir
            case take 1 rdir of
                ["bin"] -> return $ (foldl1 combine $ reverse (drop 1 rdir)) </> "cache" </> suffix
                _ -> fmap ((</> suffix) . (</> "cache") . takeDirectory) getExecutablePath
           else getAppUserDataDirectory ("cache" </> suffix)
        SystemInstall -> return ("/var/cache" </> suffix)
        LocalInstall  -> return ("/var/local/cache" </> suffix)
        UserInstall  -> getXdgDirectory XdgCache suffix
        NotInstalled -> do
            dir <- splitDirectories . takeDirectory <$> getExecutablePath
            let rdir = reverse dir
            return . foldl1 combine $ reverse ("cache": drop 2 rdir)

-- | like 'sensibleCacheDir', but creates it if needed
sensibleCacheDirCreateIfMissing suffix = do
    dir <- sensibleCacheDir suffix
    createDirectoryIfMissing True dir