summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Crayne <jim.crayne@gmail.com>2017-11-04 01:54:06 +0000
committerJames Crayne <jim.crayne@gmail.com>2017-11-04 02:00:20 +0000
commitfeea4fe4d229dc9507b7a96b9eb324af3b7da1fa (patch)
treec94b2d4a7afad4acd6065e6c354e12cb692ca76a
initial commit
-rw-r--r--Setup.hs2
-rw-r--r--sensible-directory.cabal30
-rw-r--r--src/SensibleDir.hs121
3 files changed, 153 insertions, 0 deletions
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
1import Distribution.Simple
2main = defaultMain
diff --git a/sensible-directory.cabal b/sensible-directory.cabal
new file mode 100644
index 0000000..13929c0
--- /dev/null
+++ b/sensible-directory.cabal
@@ -0,0 +1,30 @@
1name: sensible-directory
2version: 0.1.0.0
3-- synopsis:
4description: Try to guess the appropriate cache directory.
5license: BSD3
6license-file: LICENSE
7author: James Crayne
8maintainer: jim.crayne@gmail.com
9-- copyright:
10-- category:
11build-type: Custom
12-- extra-source-files:
13cabal-version: >=1.10
14
15Flag dirxdg
16 description: compat layer for old directory package
17 default: False
18
19library
20 exposed-modules: SensibleDir
21 -- other-modules:
22 -- other-extensions:
23 build-depends: base, filepath
24 if flag(dirxdg) || impl(ghc < 8)
25 build-depends: directory >= 1.2.2, directory-xdg
26 else
27 build-depends: directory >= 1.2.3
28 hs-source-dirs: src
29 default-language: Haskell2010
30
diff --git a/src/SensibleDir.hs b/src/SensibleDir.hs
new file mode 100644
index 0000000..c5f9ae1
--- /dev/null
+++ b/src/SensibleDir.hs
@@ -0,0 +1,121 @@
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE TupleSections #-}
3module SensibleDir where
4
5import Paths_testcabaldir
6import System.Directory
7#ifdef VERSION_directory_xdg
8import System.DirectoryXdg
9#endif
10import System.FilePath
11import System.IO
12import System.Info
13import System.Environment
14import Control.Arrow
15import Control.Applicative
16import Data.List
17
18installScenario = NotInstalled
19doit = do
20 ddir <- getDataDir
21 ldir <- getLibDir
22 pname <- getProgName
23 ppath <- getExecutablePath
24 sysconfdir <- getSysconfDir
25 putStrLn ("ddir = " ++ ddir);
26 putStrLn ("ldir = " ++ ldir);
27 putStrLn ("sysconfdir = " ++ sysconfdir);
28 putStrLn ("pname = " ++ pname);
29 putStr "runningInBuildDir = "
30 print =<< runningInBuildDir
31 putStr "detectLikelyInstall = "
32 print =<< detectLikelyInstall
33 putStrLn "---------------------"
34 putStr "sensibleCacheDir = "
35 print =<< sensibleCacheDir pname
36 -- putStr "sensibleConfigDir = "
37 -- print =<< sensibleConfigDir pname
38
39runningInBuildDir :: IO Bool
40runningInBuildDir = any (=="build") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath
41
42runningInCabalDir :: IO Bool
43runningInCabalDir = any (==".cabal") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath
44
45runningInSysBin = do
46 exedir <- splitDirectories . takeDirectory <$> getExecutablePath
47 return $
48 case take 3 (drop 1 exedir) of
49 ["bin"] -> True
50 ["sbin"] -> True
51 ["usr","bin"] -> True
52 ["usr","sbin"] -> True
53 _ -> False
54
55runningInLocalBin = do
56 exedir <- splitDirectories . takeDirectory <$> getExecutablePath
57 putStr "exedir = "
58 print exedir
59 return $
60 case take 3 (drop 1 exedir) of
61 ["usr","local","bin"] -> True
62 ["usr","local","sbin"] -> True
63 _ -> False
64
65-- scenarios
66data InstallScenario = PrefixInstall
67 -- ^ installed in /opt or some other prefix, or running inside source folder
68 | SystemInstall
69 -- ^ installed system wide
70 | LocalInstall
71 -- ^ installed in /usr/local/
72 | UserInstall
73 -- ^ installed for a given user
74 | NotInstalled
75 -- ^ not installed, built by cabal or make, running from dist folder
76 deriving (Show,Enum,Eq)
77
78-- | careful, assumes unix-style FHS
79-- windows aware contributions welcome
80-- Detects the likely install scenario based on the path to the exectuable.
81detectLikelyInstall :: IO InstallScenario
82detectLikelyInstall = do
83 bBuildDir <- fmap (,NotInstalled) runningInBuildDir
84 bCabalDir <- fmap (,UserInstall) runningInCabalDir
85 bLocalDir <- fmap (,LocalInstall) runningInLocalBin
86 bSysDir <- fmap (,SystemInstall) runningInSysBin
87 case dropWhile (not . fst) [bBuildDir,bCabalDir,bLocalDir,bSysDir] of
88 (True,scenario):_ -> return scenario
89 _ -> return PrefixInstall
90
91isUnix os = not $ "mingw" `isPrefixOf` os
92
93-- | Try to get the cache directory appropriate to the install scenario.
94-- On windows it just calls getAppUserDataDirectory and appends "cache".
95-- (windows behavior subject to change, contributions welcome)
96sensibleCacheDir suffix = do
97 let ifunix x = if isUnix os then x
98 else PrefixInstall
99 install <- ifunix <$> detectLikelyInstall
100 case install of
101 PrefixInstall -> do
102 if isUnix os
103 then do
104 dir <- splitDirectories . takeDirectory <$> getExecutablePath
105 let rdir = reverse dir
106 case take 1 rdir of
107 ["bin"] -> return $ (foldl1 combine $ reverse (drop 1 rdir)) </> "cache" </> suffix
108 _ -> fmap ((</> suffix) . (</> "cache") . takeDirectory) getExecutablePath
109 else getAppUserDataDirectory ("cache" </> suffix)
110 SystemInstall -> return ("/var/cache" </> suffix)
111 LocalInstall -> return ("/var/local/cache" </> suffix)
112 UserInstall -> getXdgDirectory XdgCache suffix
113 NotInstalled -> do
114 dir <- splitDirectories . takeDirectory <$> getExecutablePath
115 let rdir = reverse dir
116 return . foldl1 combine $ reverse ("cache": drop 2 rdir)
117
118-- | like 'sensibleCacheDir', but creates it if needed
119sensibleCacheDirCreateIfMissing suffix = do
120 dir <- sensibleCacheDir suffix
121 createDirectoryIfMissing True dir