|
| 1 | +module PlanJson where |
| 2 | + |
| 3 | +import Control.Monad (unless) |
| 4 | +import System.FilePath |
| 5 | +import System.Directory |
| 6 | + |
| 7 | +findPlanJson |
| 8 | + :: FilePath |
| 9 | + -> IO FilePath |
| 10 | +findPlanJson fp = do |
| 11 | + planJsonFn <- do |
| 12 | + mRoot <- findProjectRoot fp |
| 13 | + case mRoot of |
| 14 | + Nothing -> fail ("missing project root relative to: " ++ fp) |
| 15 | + Just dir -> fromBuilddir $ dir </> "dist-newstyle" |
| 16 | + |
| 17 | + havePlanJson <- doesFileExist planJsonFn |
| 18 | + |
| 19 | + unless havePlanJson $ |
| 20 | + fail "missing 'plan.json' file; do you need to run 'cabal new-build'?" |
| 21 | + |
| 22 | + return planJsonFn |
| 23 | + where |
| 24 | + fromBuilddir distFolder = do |
| 25 | + haveDistFolder <- doesDirectoryExist distFolder |
| 26 | + |
| 27 | + unless haveDistFolder $ |
| 28 | + fail ("missing " ++ show distFolder ++ " folder; do you need to run 'cabal new-build'?") |
| 29 | + |
| 30 | + return $ distFolder </> "cache" </> "plan.json" |
| 31 | + |
| 32 | + |
| 33 | +-- | Find project root relative to a directory, this emulates cabal's current |
| 34 | +-- heuristic, but is slightly more liberal. If no cabal.project is found, |
| 35 | +-- cabal-install looks for *.cabal files in the specified directory only. This |
| 36 | +-- function also considers *.cabal files in directories higher up in the |
| 37 | +-- hierarchy. |
| 38 | +findProjectRoot :: FilePath -> IO (Maybe FilePath) |
| 39 | +findProjectRoot dir = do |
| 40 | + normalisedPath <- canonicalizePath dir |
| 41 | + let checkCabalProject d = do |
| 42 | + ex <- doesFileExist fn |
| 43 | + return $ if ex then Just d else Nothing |
| 44 | + where |
| 45 | + fn = d </> "cabal.project" |
| 46 | + |
| 47 | + checkCabal d = do |
| 48 | + files <- listDirectory' d |
| 49 | + return $ if any (isExtensionOf' ".cabal") files |
| 50 | + then Just d |
| 51 | + else Nothing |
| 52 | + |
| 53 | + result <- walkUpFolders checkCabalProject normalisedPath |
| 54 | + case result of |
| 55 | + Just rootDir -> pure $ Just rootDir |
| 56 | + Nothing -> walkUpFolders checkCabal normalisedPath |
| 57 | + where |
| 58 | + isExtensionOf' :: String -> FilePath -> Bool |
| 59 | + isExtensionOf' ext fp = ext == takeExtension fp |
| 60 | + |
| 61 | + listDirectory' :: FilePath -> IO [FilePath] |
| 62 | + listDirectory' fp = filter isSpecialDir <$> getDirectoryContents fp |
| 63 | + where |
| 64 | + isSpecialDir f = f /= "." && f /= ".." |
| 65 | + |
| 66 | +walkUpFolders :: (FilePath -> IO (Maybe a)) -> FilePath -> IO (Maybe a) |
| 67 | +walkUpFolders dtest d0 = do |
| 68 | + home <- getHomeDirectory |
| 69 | + |
| 70 | + let go d | d == home = pure Nothing |
| 71 | + | isDrive d = pure Nothing |
| 72 | + | otherwise = do |
| 73 | + t <- dtest d |
| 74 | + case t of |
| 75 | + Nothing -> go $ takeDirectory d |
| 76 | + x@Just{} -> pure x |
| 77 | + |
| 78 | + go d0 |
| 79 | + |
0 commit comments