diff options
author | James Crayne <jim.crayne@gmail.com> | 2017-11-04 01:54:06 +0000 |
---|---|---|
committer | James Crayne <jim.crayne@gmail.com> | 2017-11-04 02:00:20 +0000 |
commit | feea4fe4d229dc9507b7a96b9eb324af3b7da1fa (patch) | |
tree | c94b2d4a7afad4acd6065e6c354e12cb692ca76a |
initial commit
-rw-r--r-- | Setup.hs | 2 | ||||
-rw-r--r-- | sensible-directory.cabal | 30 | ||||
-rw-r--r-- | src/SensibleDir.hs | 121 |
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 @@ | |||
1 | import Distribution.Simple | ||
2 | main = 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 @@ | |||
1 | name: sensible-directory | ||
2 | version: 0.1.0.0 | ||
3 | -- synopsis: | ||
4 | description: Try to guess the appropriate cache directory. | ||
5 | license: BSD3 | ||
6 | license-file: LICENSE | ||
7 | author: James Crayne | ||
8 | maintainer: jim.crayne@gmail.com | ||
9 | -- copyright: | ||
10 | -- category: | ||
11 | build-type: Custom | ||
12 | -- extra-source-files: | ||
13 | cabal-version: >=1.10 | ||
14 | |||
15 | Flag dirxdg | ||
16 | description: compat layer for old directory package | ||
17 | default: False | ||
18 | |||
19 | library | ||
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 #-} | ||
3 | module SensibleDir where | ||
4 | |||
5 | import Paths_testcabaldir | ||
6 | import System.Directory | ||
7 | #ifdef VERSION_directory_xdg | ||
8 | import System.DirectoryXdg | ||
9 | #endif | ||
10 | import System.FilePath | ||
11 | import System.IO | ||
12 | import System.Info | ||
13 | import System.Environment | ||
14 | import Control.Arrow | ||
15 | import Control.Applicative | ||
16 | import Data.List | ||
17 | |||
18 | installScenario = NotInstalled | ||
19 | doit = 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 | |||
39 | runningInBuildDir :: IO Bool | ||
40 | runningInBuildDir = any (=="build") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath | ||
41 | |||
42 | runningInCabalDir :: IO Bool | ||
43 | runningInCabalDir = any (==".cabal") . take 2 . reverse . splitDirectories . takeDirectory <$> getExecutablePath | ||
44 | |||
45 | runningInSysBin = 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 | |||
55 | runningInLocalBin = 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 | ||
66 | data 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. | ||
81 | detectLikelyInstall :: IO InstallScenario | ||
82 | detectLikelyInstall = 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 | |||
91 | isUnix 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) | ||
96 | sensibleCacheDir 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 | ||
119 | sensibleCacheDirCreateIfMissing suffix = do | ||
120 | dir <- sensibleCacheDir suffix | ||
121 | createDirectoryIfMissing True dir | ||