@@ -46,6 +46,8 @@ import Distribution.Client.ProjectPlanning
46
46
( ElaboratedSharedConfig (.. ), ElaboratedInstallPlan )
47
47
import Distribution.Client.ProjectPlanning.Types
48
48
( elabOrderExeDependencies )
49
+ import Distribution.Client.ScriptUtils
50
+ ( getScriptCacheDirectory , isLiterate , readScriptBlockFromScript )
49
51
import Distribution.Client.Setup
50
52
( GlobalFlags , ConfigFlags (.. ) )
51
53
import qualified Distribution.Client.Setup as Client
@@ -85,6 +87,8 @@ import Distribution.Types.PackageDescription
85
87
( PackageDescription (.. ), emptyPackageDescription )
86
88
import Distribution.Types.PackageName.Magic
87
89
( fakePackageId )
90
+ import Distribution.Types.Executable
91
+ ( Executable (.. ), emptyExecutable )
88
92
import Distribution.Types.Library
89
93
( Library (.. ), emptyLibrary )
90
94
import Distribution.Types.Version
@@ -93,6 +97,8 @@ import Distribution.Types.VersionRange
93
97
( anyVersion )
94
98
import Distribution.Utils.Generic
95
99
( safeHead )
100
+ import Distribution.Utils.Path
101
+ ( unsafeMakeSymbolicPath )
96
102
import Distribution.Verbosity
97
103
( normal , lessVerbose )
98
104
import Distribution.Simple.Utils
@@ -102,14 +108,18 @@ import Language.Haskell.Extension
102
108
import Distribution.CabalSpecVersion
103
109
( CabalSpecVersion (.. ) )
104
110
111
+ import Control.Monad
112
+ ( (<=<) )
113
+ import qualified Data.ByteString.Char8 as BS
105
114
import Data.List
106
115
( (\\) )
107
116
import qualified Data.Map as Map
108
117
import qualified Data.Set as Set
109
118
import System.Directory
110
- ( getCurrentDirectory , getTemporaryDirectory , removeDirectoryRecursive )
119
+ ( getCurrentDirectory , getTemporaryDirectory , removeDirectoryRecursive
120
+ , doesFileExist , canonicalizePath )
111
121
import System.FilePath
112
- ( (</>) )
122
+ ( (</>) , joinPath , splitPath , pathSeparator , takeFileName )
113
123
114
124
data EnvFlags = EnvFlags
115
125
{ envPackages :: [Dependency ]
@@ -345,43 +355,68 @@ withProject cliConfig verbosity targetStrings = do
345
355
withoutProject :: ProjectConfig -> Verbosity -> [String ]
346
356
-> IO (ProjectBaseContext , [TargetSelector ], IO () , ReplType )
347
357
withoutProject config verbosity extraArgs = do
348
- unless (null extraArgs) $
349
- die' verbosity $ " 'repl' doesn't take any extra arguments when outside a project: " ++ unwords extraArgs
358
+ maybeScript <- case extraArgs of
359
+ [] -> return Nothing
360
+ [script] -> do
361
+ exists <- doesFileExist script
362
+ if exists
363
+ then return $ Just script
364
+ else die' verbosity $ " 'repl' argument is not an script file: " ++ unwords extraArgs
365
+ _ -> die' verbosity $ " 'repl' takes a single script argument: " ++ unwords extraArgs
350
366
351
- globalTmp <- getTemporaryDirectory
352
- tempDir <- createTempDirectory globalTmp " cabal-repl."
367
+
368
+ let
369
+ mkTmpDir = do
370
+ globalTmp <- getTemporaryDirectory
371
+ createTempDirectory globalTmp " cabal-repl."
372
+ readExec script =
373
+ fmap fst . readScriptBlockFromScript verbosity (isLiterate script) =<< BS. readFile script
374
+
375
+ dir <- maybe mkTmpDir (getScriptCacheDirectory . (" repl:" ++ )) maybeScript
376
+ scriptExecutable <- maybe (return emptyExecutable) readExec maybeScript
377
+ -- For scripts, we want to use cwd in hs-source-dirs, but hs-source-dirs wants a relative path
378
+ backtocwd <- relativePathBackToCurrentDirectory dir
353
379
354
380
-- We need to create a dummy package that lives in our dummy project.
355
381
let
356
382
sourcePackage = SourcePackage
357
383
{ srcpkgPackageId = pkgId
358
384
, srcpkgDescription = genericPackageDescription
359
- , srcpkgSource = LocalUnpackedPackage tempDir
385
+ , srcpkgSource = LocalUnpackedPackage dir
360
386
, srcpkgDescrOverride = Nothing
361
387
}
362
388
genericPackageDescription = emptyGenericPackageDescription
363
389
& L. packageDescription .~ packageDescription
364
- & L. condLibrary .~ Just (CondNode library [baseDep] [] )
390
+ & ( if isNothing maybeScript
391
+ then L. condLibrary .~ Just (CondNode library [baseDep] [] )
392
+ else L. condExecutables .~ [(" script" , CondNode executable (targetBuildDepends eBuildInfo) [] )] )
365
393
packageDescription = emptyPackageDescription
366
394
{ package = pkgId
367
395
, specVersion = CabalSpecV2_2
368
396
, licenseRaw = Left SPDX. NONE
369
397
}
370
- library = emptyLibrary { libBuildInfo = buildInfo }
371
- buildInfo = emptyBuildInfo
398
+ pkgId = fakePackageId
399
+
400
+ library = emptyLibrary { libBuildInfo = lBuildInfo }
401
+ lBuildInfo = emptyBuildInfo
372
402
{ targetBuildDepends = [baseDep]
373
403
, defaultLanguage = Just Haskell2010
374
404
}
375
405
baseDep = Dependency " base" anyVersion mainLibSet
376
- pkgId = fakePackageId
377
406
378
- writeGenericPackageDescription (tempDir </> " fake-package.cabal" ) genericPackageDescription
379
-
380
- let ghciScriptPath = tempDir </> " setcwd.ghci"
381
- cwd <- getCurrentDirectory
382
- writeFile ghciScriptPath (" :cd " ++ cwd)
407
+ executable = scriptExecutable
408
+ { modulePath = maybe " " takeFileName maybeScript
409
+ , buildInfo = eBuildInfo
410
+ { defaultLanguage =
411
+ case defaultLanguage eBuildInfo of
412
+ just@ (Just _) -> just
413
+ Nothing -> Just Haskell2010
414
+ , hsSourceDirs = [unsafeMakeSymbolicPath backtocwd]
415
+ }
416
+ }
417
+ eBuildInfo = buildInfo scriptExecutable
383
418
384
- distDirLayout <- establishDummyDistDirLayout verbosity config tempDir
419
+ distDirLayout <- establishDummyDistDirLayout verbosity config dir
385
420
baseCtx <-
386
421
establishDummyProjectBaseContext
387
422
verbosity
@@ -390,12 +425,26 @@ withoutProject config verbosity extraArgs = do
390
425
[SpecificSourcePackage sourcePackage]
391
426
OtherCommand
392
427
428
+ writeGenericPackageDescription (dir </> " fake-package.cabal" ) genericPackageDescription
429
+ maybe (return () ) (writeFile (dir </> " scriptlocation" ) <=< canonicalizePath) maybeScript
430
+
431
+ let ghciScriptPath = dir </> " setcwd.ghci"
432
+ cwd <- getCurrentDirectory
433
+ writeFile ghciScriptPath (" :cd " ++ cwd)
434
+
393
435
let
394
436
targetSelectors = [TargetPackage TargetExplicitNamed [pkgId] Nothing ]
395
- finalizer = handleDoesNotExist () (removeDirectoryRecursive tempDir)
437
+ finalizer | isNothing maybeScript = handleDoesNotExist () (removeDirectoryRecursive dir)
438
+ | otherwise = return ()
396
439
397
440
return (baseCtx, targetSelectors, finalizer, GlobalRepl ghciScriptPath)
398
441
442
+ relativePathBackToCurrentDirectory :: FilePath -> IO FilePath
443
+ relativePathBackToCurrentDirectory d = do
444
+ toRoot <- joinPath . map (const " .." ) . splitPath . dropWhile (== pathSeparator) <$> canonicalizePath d
445
+ cwd <- dropWhile (== pathSeparator) <$> getCurrentDirectory
446
+ return $ toRoot </> cwd
447
+
399
448
addDepsToProjectTarget :: [Dependency ]
400
449
-> PackageId
401
450
-> ProjectBaseContext
0 commit comments