Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 6dc7d43

Browse files
committed
Move finding the package for a filepath
Currently, hie-wrapper uses the cradle type to find the ghc version to use on the project. Cabal-Helper does not only return the cradle type but also initialises the packages of the project, which may take a long time since it starts building dependencies. Moreover, it causes hie-wrapper to take way longer than necessary to find the project type, and thus, the ghc version to use on the project. This violates the isolation of the cradle, some work happens before loading the options for a filepath, some during it. This commit unifies the behaviour with hie-bios: * All the work happens during loading the options for the given filepath. It speeds up the initial start-up of hie if users use the implicit cradle discovery mechanism. It makes the implementation a bit less hacky. While there are behavioural changes, nothing should change for everyday users.
1 parent 16d1a63 commit 6dc7d43

File tree

1 file changed

+73
-71
lines changed

1 file changed

+73
-71
lines changed

hie-plugin-api/Haskell/Ide/Engine/Cradle.hs

+73-71
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ import Distribution.Helper (Package, projectPackages, pUnits,
1414
unChModuleName, Ex(..), ProjLoc(..),
1515
QueryEnv, mkQueryEnv, runQuery,
1616
Unit, unitInfo, uiComponents,
17-
ChEntrypoint(..), UnitInfo(..))
17+
ChEntrypoint(..), UnitInfo(..),
18+
pPackageName)
1819
import Distribution.Helper.Discover (findProjects, getDefaultDistDir)
1920
import Data.Function ((&))
20-
import Data.List (isPrefixOf, sortOn, find)
21+
import Data.List (isPrefixOf, sortOn, find, intercalate)
2122
import qualified Data.List.NonEmpty as NonEmpty
2223
import Data.List.NonEmpty (NonEmpty)
2324
import qualified Data.Map as Map
@@ -304,18 +305,23 @@ FilePath is part of and decide which unit to load when 'runCradle' is executed.
304305
Thus, to find the options required to compile and load the given FilePath,
305306
we have to do the following:
306307
307-
1. Identify the package that contains the FilePath (should be unique)
308+
1. Find the project type of the project.
308309
Happens in 'cabalHelperCradle'
309-
2. Find the unit that that contains the FilePath (May be non-unique)
310+
2. Identify the package that contains the FilePath (should be unique).
310311
Happens in 'cabalHelperAction'
311-
3. Find the component that exposes the FilePath (May be non-unique)
312+
3. Find the unit that that contains the FilePath (May be non-unique).
313+
Happens in 'cabalHelperAction'
314+
4. Find the component that exposes the FilePath (May be non-unique).
312315
Happens in 'cabalHelperAction'
313316
314-
=== Identify the package that contains the FilePath
317+
=== Find the project type of the project.
315318
316319
The function 'cabalHelperCradle' does the first step only.
317320
It starts by querying Cabal-Helper to find the project's root.
318321
See 'findCabalHelperEntryPoint' for details how this is done.
322+
323+
=== Identify the package that contains the FilePath
324+
319325
Once the root of the project is defined, we query Cabal-Helper for all packages
320326
that are defined in the project and match by the packages source directory
321327
which package the given FilePath is most likely to be a part of.
@@ -479,43 +485,16 @@ cabalHelperCradle file = do
479485
debugm $ "Cabal-Helper dirs: " ++ show [root, file]
480486
let dist_dir = getDefaultDistDir proj
481487
env <- mkQueryEnv proj dist_dir
482-
packages <- runQuery projectPackages env
483-
-- Find the package the given file may belong to.
484-
-- If it does not belong to any package, create a none-cradle.
485-
-- We might want to find a cradle without actually loading anything.
486-
-- Useful if we only want to determine a ghc version to use.
487-
case packages `findPackageFor` file of
488-
Nothing -> do
489-
debugm $ "Could not find a package for the file: " ++ file
490-
debugm
491-
"This is perfectly fine if we only want to determine the GHC version."
492-
return
493-
Cradle { cradleRootDir = root
494-
, cradleOptsProg =
495-
CradleAction { actionName = Bios.Other (projectNoneType proj)
496-
, runCradle = \_ _ -> return CradleNone
497-
}
498-
}
499-
Just realPackage -> do
500-
debugm $ "Cabal-Helper cradle package: " ++ show realPackage
501-
-- Field `pSourceDir` often has the form `<cwd>/./plugin`
502-
-- but we only want `<cwd>/plugin`
503-
normalisedPackageLocation <- canonicalizePath $ pSourceDir realPackage
504-
debugm
505-
$ "Cabal-Helper normalisedPackageLocation: "
506-
++ normalisedPackageLocation
507-
return
508-
Cradle { cradleRootDir = normalisedPackageLocation
509-
, cradleOptsProg =
510-
CradleAction { actionName = Bios.Other actionNameSuffix
511-
, runCradle = \_ fp -> cabalHelperAction
512-
(Ex proj)
513-
env
514-
realPackage
515-
normalisedPackageLocation
516-
fp
517-
}
518-
}
488+
return
489+
Cradle { cradleRootDir = root
490+
, cradleOptsProg =
491+
CradleAction { actionName = Bios.Other actionNameSuffix
492+
, runCradle = \_ fp -> cabalHelperAction
493+
(Ex proj)
494+
env
495+
fp
496+
}
497+
}
519498

520499
-- | Cradle Action to query for the ComponentOptions that are needed
521500
-- to load the given FilePath.
@@ -526,36 +505,59 @@ cabalHelperAction :: Ex ProjLoc -- ^ Project location, can be used
526505
-- agnostic error messages.
527506
-> QueryEnv v -- ^ Query Env created by 'mkQueryEnv'
528507
-- with the appropriate 'distdir'
529-
-> Package v -- ^ Package this cradle is part for.
530-
-> FilePath -- ^ Root directory of the cradle
531-
-- this action belongs to.
532508
-> FilePath -- ^ FilePath to load, expected to be an absolute path.
533509
-> IO (CradleLoadResult ComponentOptions)
534-
cabalHelperAction proj env package root fp = do
535-
-- Get all unit infos the given FilePath may belong to
536-
let units = pUnits package
537-
-- make the FilePath to load relative to the root of the cradle.
538-
let relativeFp = makeRelative root fp
539-
debugm $ "Relative Module FilePath: " ++ relativeFp
540-
getComponent proj env (toList units) relativeFp
541-
>>= \case
542-
Right comp -> do
543-
let fs' = getFlags comp
544-
let fs = map (fixImportDirs root) fs'
545-
let targets = getTargets comp relativeFp
546-
let ghcOptions = removeRTS (fs ++ targets)
547-
debugm $ "Flags for \"" ++ fp ++ "\": " ++ show ghcOptions
548-
debugm $ "Component Infos: " ++ show comp
549-
return
550-
$ CradleSuccess
551-
ComponentOptions { componentOptions = ghcOptions
552-
, componentDependencies = []
553-
}
554-
Left err -> return
555-
$ CradleFail
556-
$ CradleError
557-
(ExitFailure 2)
558-
err
510+
cabalHelperAction proj env fp = do
511+
-- This builds all packages in the project.
512+
packages <- runQuery projectPackages env
513+
-- Find the package the given file may belong to.
514+
-- If it does not belong to any package, fail the loading process
515+
case packages `findPackageFor` fp of
516+
Nothing -> do
517+
debugm $ "Failed to find a package for: " ++ fp
518+
return $ CradleFail $
519+
CradleError
520+
(ExitFailure 1)
521+
[ "Failed to find a package for: " ++ fp,
522+
"No Prefix matched.",
523+
"Following packages were searched: "
524+
++ intercalate "; "
525+
(map
526+
(\p -> pPackageName p ++ "(" ++ pSourceDir p ++ ")")
527+
$ NonEmpty.toList packages)
528+
]
529+
Just package -> do
530+
debugm $ "Cabal-Helper cradle package: " ++ show package
531+
-- Field `pSourceDir` often has the form `<cwd>/./plugin`
532+
-- but we only want `<cwd>/plugin`
533+
packageRoot <- canonicalizePath $ pSourceDir package
534+
debugm
535+
$ "Cabal-Helper normalisedPackageLocation: "
536+
++ packageRoot
537+
-- Get all unit infos the given FilePath may belong to
538+
let units = pUnits package
539+
-- make the FilePath to load relative to the root of the cradle.
540+
let relativeFp = makeRelative packageRoot fp
541+
debugm $ "Relative Module FilePath: " ++ relativeFp
542+
getComponent proj env (toList units) relativeFp
543+
>>= \case
544+
Right comp -> do
545+
let fs' = getFlags comp
546+
let fs = map (fixImportDirs packageRoot) fs'
547+
let targets = getTargets comp relativeFp
548+
let ghcOptions = removeRTS (fs ++ targets)
549+
debugm $ "Flags for \"" ++ fp ++ "\": " ++ show ghcOptions
550+
debugm $ "Component Infos: " ++ show comp
551+
return
552+
$ CradleSuccess
553+
ComponentOptions { componentOptions = ghcOptions
554+
, componentDependencies = []
555+
}
556+
Left err -> return
557+
$ CradleFail
558+
$ CradleError
559+
(ExitFailure 2)
560+
err
559561
where
560562
-- | Strip out any ["+RTS", ..., "-RTS"] sequences in the command string list.
561563
removeRTS :: [String] -> [String]

0 commit comments

Comments
 (0)