Skip to content

Commit 71b9a54

Browse files
committed
Make check work on actual TARGETs
1 parent e4053d7 commit 71b9a54

File tree

25 files changed

+275
-83
lines changed

25 files changed

+275
-83
lines changed

cabal-install/cabal-install.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ library
8787
Distribution.Client.Check
8888
Distribution.Client.CmdBench
8989
Distribution.Client.CmdBuild
90+
Distribution.Client.CmdCheck
9091
Distribution.Client.CmdClean
9192
Distribution.Client.CmdConfigure
9293
Distribution.Client.CmdErrorMessages

cabal-install/src/Distribution/Client/Check.hs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
-- Check a package for common mistakes
1717
module Distribution.Client.Check
1818
( check
19+
, multiCheck
1920
) where
2021

2122
import Distribution.Client.Compat.Prelude
2223
import Prelude ()
2324

2425
import Distribution.Client.Utils.Parsec (renderParseError)
25-
import Distribution.PackageDescription (GenericPackageDescription)
26+
import Distribution.PackageDescription (GenericPackageDescription, PackageName)
2627
import Distribution.PackageDescription.Check
2728
import Distribution.PackageDescription.Parsec
2829
( parseGenericPackageDescription
@@ -37,37 +38,37 @@ import qualified Data.ByteString as BS
3738
import qualified Data.Function as F
3839
import qualified Data.List as L
3940
import qualified Data.List.NonEmpty as NE
40-
import Distribution.Client.Errors
41+
import qualified Distribution.Client.Errors as E
42+
import qualified Distribution.Types.PackageName as PN
4143
import qualified System.Directory as Dir
4244

4345
readGenericPackageDescriptionCheck :: Verbosity -> FilePath -> IO ([PWarning], GenericPackageDescription)
4446
readGenericPackageDescriptionCheck verbosity fpath = do
4547
exists <- Dir.doesFileExist fpath
4648
unless exists $
4749
dieWithException verbosity $
48-
FileDoesntExist fpath
50+
E.FileDoesntExist fpath
4951
bs <- BS.readFile fpath
5052
let (warnings, result) = runParseResult (parseGenericPackageDescription bs)
5153
case result of
5254
Left (_, errors) -> do
5355
traverse_ (warn verbosity . showPError fpath) errors
5456
hPutStr stderr $ renderParseError fpath bs errors warnings
55-
dieWithException verbosity ParseError
57+
dieWithException verbosity E.ParseError
5658
Right x -> return (warnings, x)
5759

5860
-- | Checks a packge for common errors. Returns @True@ if the package
5961
-- is fit to upload to Hackage, @False@ otherwise.
60-
-- Note: must be called with the CWD set to the directory containing
61-
-- the '.cabal' file.
6262
check
6363
:: Verbosity
64+
-> Maybe PackageName
6465
-> [CheckExplanationIDString]
6566
-- ^ List of check-ids in String form
6667
-- (e.g. @invalid-path-win@) to ignore.
6768
-> FilePath
6869
-- ^ Folder to check (where `.cabal` file is).
6970
-> IO Bool
70-
check verbosity ignores checkDir = do
71+
check verbosity mPkgName ignores checkDir = do
7172
epdf <- findPackageDesc checkDir
7273
pdfile <- case epdf of
7374
Right cf -> return cf
@@ -80,6 +81,9 @@ check verbosity ignores checkDir = do
8081
(packageChecks, unrecs) = filterPackageChecksByIdString packageChecksPrim ignores
8182

8283
CM.mapM_ (\s -> warn verbosity ("Unrecognised ignore \"" ++ s ++ "\"")) unrecs
84+
case mPkgName of
85+
(Just pn) -> notice verbosity $ "*** " ++ PN.unPackageName pn
86+
Nothing -> return ()
8387

8488
CM.mapM_ (outputGroupCheck verbosity) (groupChecks packageChecks)
8589

@@ -93,6 +97,29 @@ check verbosity ignores checkDir = do
9397

9498
return (null errors)
9599

100+
-- | Same as 'check', but with output adjusted for multiple targets.
101+
multiCheck
102+
:: Verbosity
103+
-> [CheckExplanationIDString]
104+
-- ^ List of check-ids in String form
105+
-- (e.g. @invalid-path-win@) to ignore.
106+
-> [(PackageName, FilePath)]
107+
-- ^ Folder to check (where `.cabal` file is).
108+
-> IO Bool
109+
multiCheck verbosity _ [] = do
110+
notice verbosity "check: no targets, nothing to do."
111+
return True
112+
multiCheck verbosity ignores [(_, checkDir)] = do
113+
-- Only one target, do not print header with package name.
114+
check verbosity Nothing ignores checkDir
115+
multiCheck verbosity ignores namesDirs = do
116+
bs <- CM.mapM (uncurry checkFun) namesDirs
117+
return (and bs)
118+
where
119+
checkFun :: PackageName -> FilePath -> IO Bool
120+
checkFun mpn wdir = do
121+
check verbosity (Just mpn) ignores wdir
122+
96123
-------------------------------------------------------------------------------
97124
-- Grouping/displaying checks
98125

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
module Distribution.Client.CmdCheck
2+
( checkCommand
3+
, checkAction
4+
) where
5+
6+
import Distribution.Client.Compat.Prelude
7+
import Prelude ()
8+
9+
import Distribution.Client.Check (multiCheck)
10+
11+
{-
12+
import Distribution.Client.CmdErrorMessages
13+
-- xxx vedi questo!
14+
( plural
15+
, renderListCommaAnd
16+
, renderTargetProblem
17+
, renderTargetProblemNoTargets
18+
, renderTargetSelector
19+
, showTargetSelector
20+
, targetSelectorFilter
21+
, targetSelectorPluralPkgs
22+
)
23+
-}
24+
import Distribution.Client.ProjectOrchestration
25+
import Distribution.Client.Setup (GlobalFlags (..))
26+
import Distribution.Client.Types.PackageLocation
27+
( PackageLocation (..)
28+
, UnresolvedSourcePackage
29+
)
30+
import Distribution.Client.Types.PackageSpecifier (PackageSpecifier (..))
31+
import Distribution.PackageDescription.Check (CheckExplanationIDString)
32+
import Distribution.Simple.Command (CommandUI (..), OptionField (..), ShowOrParseArgs, option, reqArg')
33+
import Distribution.Simple.Setup (Flag (..), fromFlag, optionVerbosity)
34+
import Distribution.Simple.Utils (wrapText)
35+
import Distribution.Solver.Types.SourcePackage (srcpkgPackageId, srcpkgSource)
36+
import Distribution.Types.PackageId
37+
import Distribution.Verbosity (normal)
38+
39+
data CheckFlags = CheckFlags
40+
{ checkVerbosity :: Flag Verbosity
41+
, checkIgnore :: [CheckExplanationIDString]
42+
}
43+
deriving (Show, Typeable)
44+
45+
defaultCheckFlags :: CheckFlags
46+
defaultCheckFlags =
47+
CheckFlags
48+
{ checkVerbosity = Flag normal
49+
, checkIgnore = []
50+
}
51+
52+
checkOptions' :: ShowOrParseArgs -> [OptionField CheckFlags]
53+
checkOptions' _showOrParseArgs =
54+
[ optionVerbosity
55+
checkVerbosity
56+
(\v flags -> flags{checkVerbosity = v})
57+
, option
58+
['i']
59+
["ignore"]
60+
"ignore a specific warning (e.g. --ignore=missing-upper-bounds)"
61+
checkIgnore
62+
(\v c -> c{checkIgnore = v ++ checkIgnore c})
63+
(reqArg' "WARNING" (: []) (const []))
64+
]
65+
66+
-------------------------------------------------------------------------------
67+
-- Command
68+
-------------------------------------------------------------------------------
69+
70+
checkCommand :: CommandUI CheckFlags
71+
checkCommand =
72+
CommandUI
73+
{ commandName = "check"
74+
, commandSynopsis = "Check the package for common mistakes."
75+
, commandDescription = Just $ \_ ->
76+
wrapText $
77+
"If no targets are passed, expects a .cabal package file in the "
78+
++ "current directory.\n"
79+
++ "\n"
80+
++ "Some checks correspond to the requirements to packages on Hackage. "
81+
++ "If no `Error` is reported, Hackage should accept the "
82+
++ "package. If errors are present, `check` exits with 1 and Hackage "
83+
++ "will refuse the package.\n"
84+
, commandNotes = Nothing
85+
, commandUsage = usageFlags "check"
86+
, commandDefaultFlags = defaultCheckFlags
87+
, commandOptions = checkOptions'
88+
}
89+
90+
usageFlags :: String -> String -> String
91+
usageFlags name pname =
92+
"Usage: " ++ pname ++ " " ++ name ++ " [FLAGS]\n"
93+
94+
-------------------------------------------------------------------------------
95+
-- Action
96+
-------------------------------------------------------------------------------
97+
98+
checkAction :: CheckFlags -> [String] -> GlobalFlags -> IO ()
99+
checkAction checkFlags extraArgs _globalFlags = do
100+
-- xxx questo solo se non è vuoto
101+
-- Compute base context.
102+
let verbosityFlag = checkVerbosity checkFlags
103+
verbosity = fromFlag verbosityFlag
104+
baseCtx <- establishProjectBaseContext verbosity mempty OtherCommand
105+
let localPkgs = localPackages baseCtx
106+
let localIdSrc = mapMaybe specifierPkgIdSrc localPkgs
107+
108+
-- xxx qui astra con cmdinstall
109+
-- Get/process selectors. The only sensible selectors for `check`
110+
-- are only those which refer to a package as a whole.
111+
targetSelectors <-
112+
either (reportTargetSelectorProblems verbosity) return
113+
=<< readTargetSelectors localPkgs Nothing extraArgs
114+
let processedSels = concat $ mapMaybe (processSelector (map fst localIdSrc)) targetSelectors
115+
116+
-- And finally go from selectors to a directory we can feed to `check`.
117+
selectedIdSrc = filter (flip elem processedSels . fst) localIdSrc
118+
namesSrcs = map (\(li, ls) -> (pkgName li, ls)) selectedIdSrc
119+
120+
allOk <- multiCheck (fromFlag verbosityFlag) (checkIgnore checkFlags) namesSrcs
121+
unless allOk exitFailure
122+
where
123+
-- Good selectors for `check` are only those who refer to a
124+
-- package as a whole.
125+
processSelector :: [PackageId] -> TargetSelector -> Maybe [PackageId]
126+
processSelector _ (TargetPackage _ pIds _) = Just pIds
127+
processSelector _ (TargetPackageNamed{}) = Nothing
128+
processSelector allIds (TargetAllPackages{}) = Just allIds
129+
processSelector _ (TargetComponent{}) = Nothing
130+
processSelector _ (TargetComponentUnknown{}) = Nothing
131+
-- xxx errori qui
132+
-- xxx qua non solo Nothing, ma anche errori
133+
134+
-- Only 'PackageSpecifier's with an actual directory.
135+
specifierPkgIdSrc
136+
:: PackageSpecifier UnresolvedSourcePackage
137+
-> Maybe (PackageId, FilePath)
138+
specifierPkgIdSrc (NamedPackage{}) = Nothing
139+
specifierPkgIdSrc (SpecificSourcePackage pkg) =
140+
let pId = srcpkgPackageId pkg
141+
in -- No interested in remote/compressed sources.
142+
case srcpkgSource pkg of
143+
(LocalUnpackedPackage fp) -> Just (pId, fp)
144+
(LocalTarballPackage{}) -> Nothing
145+
(RemoteTarballPackage{}) -> Nothing
146+
(RepoTarballPackage{}) -> Nothing
147+
(RemoteSourceRepoPackage{}) -> Nothing
148+
149+
-- xxx orribile cambia
150+

cabal-install/src/Distribution/Client/Errors.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ data CabalInstallException
8181
| UploadActionDocumentation
8282
| UploadActionOnlyArchives [FilePath]
8383
| FileNotFound FilePath
84-
| CheckAction [String]
8584
| ReportAction [String]
8685
| InitAction
8786
| UserConfigAction FilePath
@@ -231,7 +230,6 @@ exceptionCodeCabalInstall e = case e of
231230
UploadActionDocumentation{} -> 7052
232231
UploadActionOnlyArchives{} -> 7053
233232
FileNotFound{} -> 7054
234-
CheckAction{} -> 7055
235233
ReportAction{} -> 7056
236234
InitAction{} -> 7057
237235
UserConfigAction{} -> 7058
@@ -405,7 +403,6 @@ exceptionMessageCabalInstall e = case e of
405403
"the 'upload' command expects only .tar.gz archives: "
406404
++ intercalate ", " otherFiles
407405
FileNotFound tarfile -> "file not found: " ++ tarfile
408-
CheckAction extraArgs -> "'check' only takes one (optional) directory path argument: " ++ unwords extraArgs
409406
ReportAction extraArgs -> "'report' doesn't take any extra arguments: " ++ unwords extraArgs
410407
InitAction ->
411408
"'init' only takes a single, optional, extra "

cabal-install/src/Distribution/Client/Main.hs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ module Distribution.Client.Main (main) where
2323
import Distribution.Client.Setup
2424
( ActAsSetupFlags (..)
2525
, BuildFlags (..)
26-
, CheckFlags (..)
2726
, ConfigExFlags (..)
2827
, ConfigFlags (..)
2928
, FetchFlags (..)
@@ -42,7 +41,6 @@ import Distribution.Client.Setup
4241
, actAsSetupCommand
4342
, benchmarkCommand
4443
, buildCommand
45-
, checkCommand
4644
, cleanCommand
4745
, configCompilerAux'
4846
, configPackageDB'
@@ -127,6 +125,7 @@ import Distribution.Client.Targets
127125

128126
import qualified Distribution.Client.CmdBench as CmdBench
129127
import qualified Distribution.Client.CmdBuild as CmdBuild
128+
import qualified Distribution.Client.CmdCheck as CmdCheck
130129
import qualified Distribution.Client.CmdClean as CmdClean
131130
import qualified Distribution.Client.CmdConfigure as CmdConfigure
132131
import qualified Distribution.Client.CmdExec as CmdExec
@@ -143,7 +142,6 @@ import qualified Distribution.Client.CmdSdist as CmdSdist
143142
import qualified Distribution.Client.CmdTest as CmdTest
144143
import qualified Distribution.Client.CmdUpdate as CmdUpdate
145144

146-
import Distribution.Client.Check as Check (check)
147145
import Distribution.Client.Configure (configure, writeConfigFlags)
148146
import Distribution.Client.Fetch (fetch)
149147
import Distribution.Client.Freeze (freeze)
@@ -429,7 +427,7 @@ mainWorker args = do
429427
, regularCmd fetchCommand fetchAction
430428
, regularCmd getCommand getAction
431429
, regularCmd unpackCommand unpackAction
432-
, regularCmd checkCommand checkAction
430+
, regularCmd CmdCheck.checkCommand CmdCheck.checkAction
433431
, regularCmd uploadCommand uploadAction
434432
, regularCmd reportCommand reportAction
435433
, regularCmd initCommand initAction
@@ -1230,19 +1228,6 @@ uploadAction uploadFlags extraArgs globalFlags = do
12301228
pkg <- fmap LBI.localPkgDescr (getPersistBuildConfig distPref)
12311229
return $ distPref </> display (packageId pkg) ++ "-docs" <.> "tar.gz"
12321230

1233-
checkAction :: CheckFlags -> [String] -> Action
1234-
checkAction checkFlags extraArgs _globalFlags = do
1235-
let verbosityFlag = checkVerbosity checkFlags
1236-
verbosity = fromFlag verbosityFlag
1237-
path <- case extraArgs of
1238-
[] -> return "."
1239-
[dp] -> return dp
1240-
(_ : es) ->
1241-
dieWithException verbosity $
1242-
CheckAction es
1243-
allOk <- Check.check (fromFlag verbosityFlag) (checkIgnore checkFlags) path
1244-
unless allOk exitFailure
1245-
12461231
formatAction :: Flag Verbosity -> [String] -> Action
12471232
formatAction verbosityFlag extraArgs _globalFlags = do
12481233
let verbosity = fromFlag verbosityFlag

0 commit comments

Comments
 (0)