Skip to content

Commit 2e03231

Browse files
authored
Merge pull request #6576 from phadej/issue-6369-install-pkgname-exename
Resolve #6369 and #6393: Allow cabal v2-install pkgname:exename or http://example.com/package.tar.gz(#sha256=abcde...)
2 parents 097ee37 + c5f777c commit 2e03231

File tree

7 files changed

+228
-80
lines changed

7 files changed

+228
-80
lines changed

cabal-install/Distribution/Client/CmdInstall.hs

Lines changed: 53 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ module Distribution.Client.CmdInstall (
1515
TargetProblem(..),
1616
selectPackageTargets,
1717
selectComponentTarget,
18+
-- * Internals exposed for CmdRepl + CmdRun
19+
establishDummyDistDirLayout,
1820
establishDummyProjectBaseContext
1921
) where
2022

@@ -28,6 +30,7 @@ import Distribution.Client.CmdErrorMessages
2830
import Distribution.Client.CmdSdist
2931

3032
import Distribution.Client.CmdInstall.ClientInstallFlags
33+
import Distribution.Client.CmdInstall.ClientInstallTargetSelector
3134

3235
import Distribution.Client.Setup
3336
( GlobalFlags(..), ConfigFlags(..), ConfigExFlags, InstallFlags(..)
@@ -43,6 +46,10 @@ import Distribution.Package
4346
( Package(..), PackageName, mkPackageName, unPackageName )
4447
import Distribution.Types.PackageId
4548
( PackageIdentifier(..) )
49+
import Distribution.Client.ProjectConfig
50+
( ProjectPackageLocation(..)
51+
, fetchAndReadSourcePackages
52+
)
4653
import Distribution.Client.ProjectConfig.Types
4754
( ProjectConfig(..), ProjectConfigShared(..)
4855
, ProjectConfigBuildOnly(..), PackageConfig(..)
@@ -135,6 +142,7 @@ import Data.Ord
135142
import qualified Data.Map as Map
136143
import Distribution.Utils.NubList
137144
( fromNubList )
145+
import Network.URI (URI)
138146
import System.Directory
139147
( getHomeDirectory, doesFileExist, createDirectoryIfMissing
140148
, getTemporaryDirectory, makeAbsolute, doesDirectoryExist
@@ -261,7 +269,7 @@ installAction ( configFlags, configExFlags, installFlags
261269
targetFilter = if installLibs then Just LibKind else Just ExeKind
262270
targetStrings' = if null targetStrings then ["."] else targetStrings
263271

264-
withProject :: IO ([PackageSpecifier UnresolvedSourcePackage], [TargetSelector], ProjectConfig)
272+
withProject :: IO ([PackageSpecifier UnresolvedSourcePackage], [URI], [TargetSelector], ProjectConfig)
265273
withProject = do
266274
let verbosity' = lessVerbose verbosity
267275

@@ -291,7 +299,7 @@ installAction ( configFlags, configExFlags, installFlags
291299
flip TargetPackageNamed targetFilter . pkgName <$> packageIds
292300

293301
if null targetStrings'
294-
then return (packageSpecifiers, packageTargets, projectConfig localBaseCtx)
302+
then return (packageSpecifiers, [], packageTargets, projectConfig localBaseCtx)
295303
else do
296304
targetSelectors <-
297305
either (reportTargetSelectorProblems verbosity) return
@@ -396,16 +404,13 @@ installAction ( configFlags, configExFlags, installFlags
396404
else return (local ++ hackagePkgs, targets' ++ hackageTargets)
397405

398406
return ( specs ++ packageSpecifiers
407+
, []
399408
, selectors ++ packageTargets
400409
, projectConfig localBaseCtx )
401410

402-
withoutProject :: ProjectConfig -> IO ([PackageSpecifier pkg], [TargetSelector], ProjectConfig)
411+
withoutProject :: ProjectConfig -> IO ([PackageSpecifier pkg], [URI], [TargetSelector], ProjectConfig)
403412
withoutProject globalConfig = do
404-
let
405-
parsePkg pkgName
406-
| Just (pkg :: PackageId) <- simpleParse pkgName = return pkg
407-
| otherwise = die' verbosity ("Invalid package ID: " ++ pkgName)
408-
packageIds <- mapM parsePkg targetStrings'
413+
tss <- mapM (parseWithoutProjectTargetSelector verbosity) targetStrings'
409414

410415
cabalDir <- getCabalDir
411416
let
@@ -431,31 +436,28 @@ installAction ( configFlags, configExFlags, installFlags
431436
verbosity buildSettings
432437
(getSourcePackages verbosity)
433438

434-
for_ targetStrings' $ \case
435-
name
436-
| null (lookupPackageName packageIndex (mkPackageName name))
437-
, xs@(_:_) <- searchByName packageIndex name ->
438-
die' verbosity . concat $
439-
[ "Unknown package \"", name, "\". "
440-
, "Did you mean any of the following?\n"
441-
, unlines (("- " ++) . unPackageName . fst <$> xs)
442-
]
443-
_ -> return ()
439+
for_ (concatMap woPackageNames tss) $ \name -> do
440+
when (null (lookupPackageName packageIndex name)) $ do
441+
let xs = searchByName packageIndex (unPackageName name)
442+
let emptyIf True _ = []
443+
emptyIf False zs = zs
444+
die' verbosity $ concat $
445+
[ "Unknown package \"", unPackageName name, "\". "
446+
] ++ emptyIf (null xs)
447+
[ "Did you mean any of the following?\n"
448+
, unlines (("- " ++) . unPackageName . fst <$> xs)
449+
]
444450

445451
let
446-
packageSpecifiers = flip fmap packageIds $ \case
447-
PackageIdentifier{..}
448-
| pkgVersion == nullVersion -> NamedPackage pkgName []
449-
| otherwise -> NamedPackage pkgName
450-
[PackagePropertyVersion
451-
(thisVersion pkgVersion)]
452-
packageTargets = flip TargetPackageNamed Nothing . pkgName <$> packageIds
453-
return (packageSpecifiers, packageTargets, projectConfig)
452+
(uris, packageSpecifiers) = partitionEithers $ map woPackageSpecifiers tss
453+
packageTargets = map woPackageTargets tss
454+
455+
return (packageSpecifiers, uris, packageTargets, projectConfig)
454456

455457
let
456458
ignoreProject = fromFlagOrDefault False (cinstIgnoreProject clientInstallFlags)
457459

458-
(specs, selectors, config) <-
460+
(specs, uris, selectors, config) <-
459461
withProjectOrGlobalConfigIgn ignoreProject verbosity globalConfigFlag withProject withoutProject
460462

461463
home <- getHomeDirectory
@@ -558,16 +560,21 @@ installAction ( configFlags, configExFlags, installFlags
558560
envSpecs' | installLibs = envSpecs
559561
| otherwise = []
560562

561-
withTempDirectory
562-
verbosity
563-
globalTmp
564-
"cabal-install."
565-
$ \tmpDir -> do
563+
withTempDirectory verbosity globalTmp "cabal-install." $ \tmpDir -> do
564+
distDirLayout <- establishDummyDistDirLayout verbosity config tmpDir
565+
566+
uriSpecs <- runRebuild tmpDir $ fetchAndReadSourcePackages
567+
verbosity
568+
distDirLayout
569+
(projectConfigShared config)
570+
(projectConfigBuildOnly config)
571+
[ ProjectPackageRemoteTarball uri | uri <- uris ]
572+
566573
baseCtx <- establishDummyProjectBaseContext
567574
verbosity
568575
config
569-
tmpDir
570-
(envSpecs' ++ specs)
576+
distDirLayout
577+
(envSpecs' ++ specs ++ uriSpecs)
571578
InstallCommand
572579

573580
buildCtx <-
@@ -874,21 +881,15 @@ entriesForLibraryComponents = Map.foldrWithKey' (\k v -> mappend (go k v)) []
874881
establishDummyProjectBaseContext
875882
:: Verbosity
876883
-> ProjectConfig
877-
-> FilePath
884+
-> DistDirLayout
878885
-- ^ Where to put the dist directory
879886
-> [PackageSpecifier UnresolvedSourcePackage]
880887
-- ^ The packages to be included in the project
881888
-> CurrentCommand
882889
-> IO ProjectBaseContext
883-
establishDummyProjectBaseContext verbosity cliConfig tmpDir
884-
localPackages currentCommand = do
890+
establishDummyProjectBaseContext verbosity cliConfig distDirLayout localPackages currentCommand = do
885891
cabalDir <- getCabalDir
886892

887-
-- Create the dist directories
888-
createDirectoryIfMissingVerbose verbosity True $ distDirectory distDirLayout
889-
createDirectoryIfMissingVerbose verbosity True $
890-
distProjectCacheDirectory distDirLayout
891-
892893
globalConfig <- runRebuild ""
893894
$ readGlobalConfig verbosity
894895
$ projectConfigConfigFile
@@ -919,13 +920,21 @@ establishDummyProjectBaseContext verbosity cliConfig tmpDir
919920
buildSettings,
920921
currentCommand
921922
}
923+
924+
establishDummyDistDirLayout :: Verbosity -> ProjectConfig -> FilePath -> IO DistDirLayout
925+
establishDummyDistDirLayout verbosity cliConfig tmpDir = do
926+
let distDirLayout = defaultDistDirLayout projectRoot mdistDirectory
927+
928+
-- Create the dist directories
929+
createDirectoryIfMissingVerbose verbosity True $ distDirectory distDirLayout
930+
createDirectoryIfMissingVerbose verbosity True $ distProjectCacheDirectory distDirLayout
931+
932+
return distDirLayout
922933
where
923934
mdistDirectory = flagToMaybe
924935
$ projectConfigDistDir
925936
$ projectConfigShared cliConfig
926937
projectRoot = ProjectRootImplicit tmpDir
927-
distDirLayout = defaultDistDirLayout projectRoot
928-
mdistDirectory
929938

930939
-- | This defines what a 'TargetSelector' means for the @bench@ command.
931940
-- It selects the 'AvailableTarget's that the 'TargetSelector' refers to,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
module Distribution.Client.CmdInstall.ClientInstallTargetSelector (
2+
WithoutProjectTargetSelector (..),
3+
parseWithoutProjectTargetSelector,
4+
woPackageNames,
5+
woPackageTargets,
6+
woPackageSpecifiers,
7+
) where
8+
9+
import Distribution.Client.Compat.Prelude
10+
import Prelude ()
11+
12+
import Network.URI (URI, parseURI)
13+
14+
import Distribution.Client.TargetSelector
15+
import Distribution.Client.Types
16+
import Distribution.Compat.CharParsing (char, optional)
17+
import Distribution.Package
18+
import Distribution.Parsec
19+
import Distribution.Simple.LocalBuildInfo (ComponentName (CExeName))
20+
import Distribution.Simple.Utils (die')
21+
import Distribution.Solver.Types.PackageConstraint (PackageProperty (..))
22+
import Distribution.Verbosity (Verbosity)
23+
import Distribution.Version
24+
25+
data WithoutProjectTargetSelector
26+
= WoPackageId PackageId
27+
| WoPackageComponent PackageId ComponentName
28+
| WoURI URI
29+
deriving (Show)
30+
31+
parseWithoutProjectTargetSelector :: Verbosity -> String -> IO WithoutProjectTargetSelector
32+
parseWithoutProjectTargetSelector verbosity input =
33+
case explicitEitherParsec parser input of
34+
Right ts -> return ts
35+
Left err -> case parseURI input of
36+
Just uri -> return (WoURI uri)
37+
Nothing -> die' verbosity $ "Invalid package ID: " ++ input ++ "\n" ++ err
38+
where
39+
parser :: ParsecParser WithoutProjectTargetSelector
40+
parser = do
41+
pid <- parsec
42+
cn <- optional (char ':' *> parsec)
43+
return $ case cn of
44+
Nothing -> WoPackageId pid
45+
Just cn' -> WoPackageComponent pid (CExeName cn')
46+
47+
woPackageNames :: WithoutProjectTargetSelector -> [PackageName]
48+
woPackageNames (WoPackageId pid) = [pkgName pid]
49+
woPackageNames (WoPackageComponent pid _) = [pkgName pid]
50+
woPackageNames (WoURI _) = []
51+
52+
woPackageTargets :: WithoutProjectTargetSelector -> TargetSelector
53+
woPackageTargets (WoPackageId pid) =
54+
TargetPackageNamed (pkgName pid) Nothing
55+
woPackageTargets (WoPackageComponent pid cn) =
56+
TargetComponentUnknown (pkgName pid) (Right cn) WholeComponent
57+
woPackageTargets (WoURI _) =
58+
TargetAllPackages (Just ExeKind)
59+
60+
woPackageSpecifiers :: WithoutProjectTargetSelector -> Either URI (PackageSpecifier pkg)
61+
woPackageSpecifiers (WoPackageId pid) = Right (pidPackageSpecifiers pid)
62+
woPackageSpecifiers (WoPackageComponent pid _) = Right (pidPackageSpecifiers pid)
63+
woPackageSpecifiers (WoURI uri) = Left uri
64+
65+
pidPackageSpecifiers :: PackageId -> PackageSpecifier pkg
66+
pidPackageSpecifiers pid
67+
| pkgVersion pid == nullVersion = NamedPackage (pkgName pid) []
68+
| otherwise = NamedPackage (pkgName pid)
69+
[ PackagePropertyVersion (thisVersion (pkgVersion pid))
70+
]

cabal-install/Distribution/Client/CmdRepl.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ import qualified Distribution.Types.Lens as L
2525

2626
import Distribution.Client.CmdErrorMessages
2727
import Distribution.Client.CmdInstall
28-
( establishDummyProjectBaseContext )
28+
( establishDummyDistDirLayout
29+
, establishDummyProjectBaseContext
30+
)
2931
import qualified Distribution.Client.InstallPlan as InstallPlan
3032
import Distribution.Client.ProjectBuilding
3133
( rebuildTargetsDryRun, improveInstallPlanWithUpToDatePackages )
@@ -419,11 +421,12 @@ withoutProject config verbosity extraArgs = do
419421
cwd <- getCurrentDirectory
420422
writeFile ghciScriptPath (":cd " ++ cwd)
421423

424+
distDirLayout <- establishDummyDistDirLayout verbosity config tempDir
422425
baseCtx <-
423426
establishDummyProjectBaseContext
424427
verbosity
425428
config
426-
tempDir
429+
distDirLayout
427430
[SpecificSourcePackage sourcePackage]
428431
OtherCommand
429432

cabal-install/Distribution/Client/CmdRun.hs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ import Distribution.Simple.Utils
4747
( wrapText, warn, die', ordNub, info
4848
, createTempDirectory, handleDoesNotExist )
4949
import Distribution.Client.CmdInstall
50-
( establishDummyProjectBaseContext )
50+
( establishDummyDistDirLayout
51+
, establishDummyProjectBaseContext )
5152
import Distribution.Client.ProjectConfig
5253
( ProjectConfig(..), ProjectConfigShared(..)
5354
, withProjectOrGlobalConfigIgn )
@@ -200,13 +201,14 @@ runAction ( configFlags, configExFlags, installFlags
200201
, clientRunFlags )
201202
targetStrings globalFlags = do
202203
globalTmp <- getTemporaryDirectory
203-
tempDir <- createTempDirectory globalTmp "cabal-repl."
204+
tmpDir <- createTempDirectory globalTmp "cabal-repl."
204205

205206
let
206207
with =
207208
establishProjectBaseContext verbosity cliConfig OtherCommand
208-
without config =
209-
establishDummyProjectBaseContext verbosity (config <> cliConfig) tempDir [] OtherCommand
209+
without config = do
210+
distDirLayout <- establishDummyDistDirLayout verbosity (config <> cliConfig) tmpDir
211+
establishDummyProjectBaseContext verbosity (config <> cliConfig) distDirLayout [] OtherCommand
210212

211213
let
212214
ignoreProject = fromFlagOrDefault False (crunIgnoreProject clientRunFlags)
@@ -219,7 +221,7 @@ runAction ( configFlags, configExFlags, installFlags
219221
let pol | takeExtension script == ".lhs" = LiterateHaskell
220222
| otherwise = PlainHaskell
221223
if exists
222-
then BS.readFile script >>= handleScriptCase verbosity pol baseCtx tempDir
224+
then BS.readFile script >>= handleScriptCase verbosity pol baseCtx tmpDir
223225
else reportTargetSelectorProblems verbosity err
224226

225227
(baseCtx', targetSelectors) <-
@@ -337,7 +339,7 @@ runAction ( configFlags, configExFlags, installFlags
337339
elaboratedPlan
338340
}
339341

340-
handleDoesNotExist () (removeDirectoryRecursive tempDir)
342+
handleDoesNotExist () (removeDirectoryRecursive tmpDir)
341343
where
342344
verbosity = fromFlagOrDefault normal (configVerbosity configFlags)
343345
cliConfig = commandLineFlagsToProjectConfig
@@ -441,7 +443,7 @@ handleScriptCase
441443
-> FilePath
442444
-> BS.ByteString
443445
-> IO (ProjectBaseContext, [TargetSelector])
444-
handleScriptCase verbosity pol baseCtx tempDir scriptContents = do
446+
handleScriptCase verbosity pol baseCtx tmpDir scriptContents = do
445447
(executable, contents') <- readScriptBlockFromScript verbosity pol scriptContents
446448

447449
-- We need to create a dummy package that lives in our dummy project.
@@ -453,7 +455,7 @@ handleScriptCase verbosity pol baseCtx tempDir scriptContents = do
453455
sourcePackage = SourcePackage
454456
{ packageInfoId = pkgId
455457
, SP.packageDescription = genericPackageDescription
456-
, packageSource = LocalUnpackedPackage tempDir
458+
, packageSource = LocalUnpackedPackage tmpDir
457459
, packageDescrOverride = Nothing
458460
}
459461
genericPackageDescription = emptyGenericPackageDescription
@@ -477,8 +479,8 @@ handleScriptCase verbosity pol baseCtx tempDir scriptContents = do
477479
}
478480
pkgId = fakePackageId
479481

480-
writeGenericPackageDescription (tempDir </> "fake-package.cabal") genericPackageDescription
481-
BS.writeFile (tempDir </> mainName) contents'
482+
writeGenericPackageDescription (tmpDir </> "fake-package.cabal") genericPackageDescription
483+
BS.writeFile (tmpDir </> mainName) contents'
482484

483485
let
484486
baseCtx' = baseCtx

0 commit comments

Comments
 (0)