From feea4fe4d229dc9507b7a96b9eb324af3b7da1fa Mon Sep 17 00:00:00 2001 From: James Crayne Date: Sat, 4 Nov 2017 01:54:06 +0000 Subject: initial commit --- Setup.hs | 2 + sensible-directory.cabal | 30 ++++++++++++ src/SensibleDir.hs | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 Setup.hs create mode 100644 sensible-directory.cabal create mode 100644 src/SensibleDir.hs diff --git a/Setup.hs b/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +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 @@ +name: sensible-directory +version: 0.1.0.0 +-- synopsis: +description: Try to guess the appropriate cache directory. +license: BSD3 +license-file: LICENSE +author: James Crayne +maintainer: jim.crayne@gmail.com +-- copyright: +-- category: +build-type: Custom +-- extra-source-files: +cabal-version: >=1.10 + +Flag dirxdg + description: compat layer for old directory package + default: False + +library + exposed-modules: SensibleDir + -- other-modules: + -- other-extensions: + build-depends: base, filepath + if flag(dirxdg) || impl(ghc < 8) + build-depends: directory >= 1.2.2, directory-xdg + else + build-depends: directory >= 1.2.3 + hs-source-dirs: src + default-language: Haskell2010 + 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 @@ +{-# 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 -- cgit v1.2.3