Content-Length: 1084184 | pFad | http://github.com/purescript/purescript/commit/5dcd000363c3c27e29f2bb8e6848c7782c17a40d

52 Add support for `--source-globs-file` CLI arg in relevant `purs` comm… · purescript/purescript@5dcd000 · GitHub
Skip to content

Commit 5dcd000

Browse files
Add support for --source-globs-file CLI arg in relevant purs commands (#4530)
* Enable passing source input globs via `--source-globs-file path/to/file` `--source-globs-file` support has been added to the following commands: `compile`, `docs`, `graph`, `ide`, and `publish`. Due to a [shell character limitation on Windows](https://learn.microsoft.com/en-us/troubleshoot/windows-client/shell-experience/command-line-string-limitation) where a large list of source globs cannot be passed (e.g. `purs compile ... glob1000/src/**/*.purs`), source globs can be stored in a file according to the format below and the file is passed in instead via `purs compile ---source-globs-file path/to/file`. ``` # Lines starting with '#' are comments. # Blank lines are ignored. # Otherwise, every line is a glob. .spago/foo-1.2.3/src/**/*.purs .spago/bar-2.3.3/src/**/*.purs my-package/src/**/*.purs my-package/tests/**/*.purs ``` `--source-globs-file` is an optional argument. Mixing it with the normal source globs is fine. Assuming `.spago/source-globs` contains `src/**/*.purs`, each command below will use the same input globs: ```sh purs compile src/**/*.purs purs compile --source-globs .spago/source-globs purs compile --source-globs .spago/source-globs src/**/*.purs ``` In the command... ``` purs compile inputGlob1 inputGlob2 --source-globs-file fileWithMoreGlobs --exclude-files excludeGlob1 ``` the files passed to the compiler are: all the files found by `inputGlob1`, `inputGlob2`, and all the globs listed in `fileWithMoreGlobs` minus the files found by `excludeGlob1`. * Add `--exclude-file` to more commands While implementing the fix above, I discovered that the `--exclude-file` CLI arg wasn't included in other `purs` commands where such a usage would be relevant (e.g. `docs`, `repl`, `graph`, and `ide`). This PR also rectifies that problem.
1 parent e25c476 commit 5dcd000

File tree

15 files changed

+317
-81
lines changed

15 files changed

+317
-81
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ jobs:
130130
- id: "build"
131131
run: "ci/fix-home ci/build.sh"
132132

133+
- name: "(Linux only) Glob tests"
134+
if: "contains(matrix.os, 'ubuntu-latest')"
135+
working-directory: "sdist-test"
136+
# We build in this directory in build.sh, so this is where we need to
137+
# launch `stack exec`. The actual glob checks happen in a temporary directory.
138+
run: |
139+
apt-get install tree
140+
../ci/fix-home stack exec bash ../glob-test.sh
141+
133142
- name: "(Linux only) Build the entire package set"
134143
if: "contains(matrix.os, 'ubuntu-latest')"
135144
# We build in this directory in build.sh, so this is where we need to
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
* Add `--exclude-file` to more commands
2+
3+
This CLI arg was added to the `compile` command, but not to other commands
4+
where such a usage would be relevant (e.g. `docs`, `repl`, `graph`, and `ide`).
5+
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
* Enable passing source input globs via `--source-globs-file path/to/file`
2+
3+
`--source-globs-file` support has been added to the following commands:
4+
`compile`, `docs`, `graph`, `ide`, and `publish`.
5+
6+
Due to a [shell character limitation on Windows](https://learn.microsoft.com/en-us/troubleshoot/windows-client/shell-experience/command-line-string-limitation) where a large list of
7+
source globs cannot be passed (e.g. `purs compile ... glob1000/src/**/*.purs`),
8+
source globs can be stored in a file according to the format below
9+
and the file is passed in instead via `purs compile ---source-globs-file path/to/file`.
10+
11+
```
12+
# Lines starting with '#' are comments.
13+
# Blank lines are ignored.
14+
# Otherwise, every line is a glob.
15+
16+
.spago/foo-1.2.3/src/**/*.purs
17+
.spago/bar-2.3.3/src/**/*.purs
18+
my-package/src/**/*.purs
19+
my-package/tests/**/*.purs
20+
```
21+
22+
`--source-globs-file` is an optional argument. Mixing it with the normal source globs is fine.
23+
Assuming `.spago/source-globs` contains `src/**/*.purs`, each command below will use
24+
the same input globs:
25+
```sh
26+
purs compile src/**/*.purs
27+
purs compile --source-globs .spago/source-globs
28+
purs compile --source-globs .spago/source-globs src/**/*.purs
29+
```
30+
31+
In the command...
32+
```
33+
purs compile inputGlob1 inputGlob2 --source-globs-file fileWithMoreGlobs --exclude-files excludeGlob1
34+
```
35+
the files passed to the compiler are: all the files found by
36+
`inputGlob1`, `inputGlob2`, and all the globs listed in `fileWithMoreGlobs`
37+
minus the files found by `excludeGlob1`.
38+

app/Command/Compile.hs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,27 @@ import Control.Monad (when)
77
import Data.Aeson qualified as A
88
import Data.Bool (bool)
99
import Data.ByteString.Lazy.UTF8 qualified as LBU8
10-
import Data.List (intercalate, (\\))
10+
import Data.List (intercalate)
1111
import Data.Map qualified as M
1212
import Data.Set qualified as S
1313
import Data.Text qualified as T
1414
import Data.Traversable (for)
1515
import Language.PureScript qualified as P
1616
import Language.PureScript.CST qualified as CST
1717
import Language.PureScript.Errors.JSON (JSONResult(..), toJSONErrors)
18+
import Language.PureScript.Glob (toInputGlobs, PSCGlobs(..), warnFileTypeNotFound)
1819
import Language.PureScript.Make (buildMakeActions, inferForeignModules, runMake)
1920
import Options.Applicative qualified as Opts
21+
import SharedCLI qualified
2022
import System.Console.ANSI qualified as ANSI
2123
import System.Exit (exitSuccess, exitFailure)
2224
import System.Directory (getCurrentDirectory)
23-
import System.FilePath.Glob (glob)
24-
import System.IO (hPutStr, hPutStrLn, stderr, stdout)
25+
import System.IO (hPutStr, stderr, stdout)
2526
import System.IO.UTF8 (readUTF8FilesT)
2627

2728
data PSCMakeOptions = PSCMakeOptions
2829
{ pscmInput :: [FilePath]
30+
, pscmInputFromFile :: Maybe FilePath
2931
, pscmExclude :: [FilePath]
3032
, pscmOutputDir :: FilePath
3133
, pscmOpts :: P.Options
@@ -54,9 +56,12 @@ printWarningsAndErrors verbose True files warnings errors = do
5456

5557
compile :: PSCMakeOptions -> IO ()
5658
compile PSCMakeOptions{..} = do
57-
included <- globWarningOnMisses warnFileTypeNotFound pscmInput
58-
excluded <- globWarningOnMisses warnFileTypeNotFound pscmExclude
59-
let input = included \\ excluded
59+
input <- toInputGlobs $ PSCGlobs
60+
{ pscInputGlobs = pscmInput
61+
, pscInputGlobsFromFile = pscmInputFromFile
62+
, pscExcludeGlobs = pscmExclude
63+
, pscWarnFileTypeNotFound = warnFileTypeNotFound "compile"
64+
}
6065
when (null input) $ do
6166
hPutStr stderr $ unlines [ "purs compile: No input files."
6267
, "Usage: For basic information, try the `--help' option."
@@ -72,29 +77,6 @@ compile PSCMakeOptions{..} = do
7277
printWarningsAndErrors (P.optionsVerboseErrors pscmOpts) pscmJSONErrors moduleFiles makeWarnings makeErrors
7378
exitSuccess
7479

75-
warnFileTypeNotFound :: String -> IO ()
76-
warnFileTypeNotFound = hPutStrLn stderr . ("purs compile: No files found using pattern: " ++)
77-
78-
globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath]
79-
globWarningOnMisses warn = concatMapM globWithWarning
80-
where
81-
globWithWarning pattern' = do
82-
paths <- glob pattern'
83-
when (null paths) $ warn pattern'
84-
return paths
85-
concatMapM f = fmap concat . mapM f
86-
87-
inputFile :: Opts.Parser FilePath
88-
inputFile = Opts.strArgument $
89-
Opts.metavar "FILE"
90-
<> Opts.help "The input .purs file(s)."
91-
92-
excludedFiles :: Opts.Parser FilePath
93-
excludedFiles = Opts.strOption $
94-
Opts.short 'x'
95-
<> Opts.long "exclude-files"
96-
<> Opts.help "Glob of .purs files to exclude from the supplied files."
97-
9880
outputDirectory :: Opts.Parser FilePath
9981
outputDirectory = Opts.strOption $
10082
Opts.short 'o'
@@ -161,8 +143,9 @@ options =
161143
handleTargets ts = S.fromList (if P.JSSourceMap `elem` ts then P.JS : ts else ts)
162144

163145
pscMakeOptions :: Opts.Parser PSCMakeOptions
164-
pscMakeOptions = PSCMakeOptions <$> many inputFile
165-
<*> many excludedFiles
146+
pscMakeOptions = PSCMakeOptions <$> many SharedCLI.inputFile
147+
<*> SharedCLI.globInputFile
148+
<*> many SharedCLI.excludeFiles
166149
<*> outputDirectory
167150
<*> options
168151
<*> (not <$> noPrefix)

app/Command/Docs.hs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import Data.Text qualified as T
1313
import Language.PureScript qualified as P
1414
import Language.PureScript.Docs qualified as D
1515
import Language.PureScript.Docs.Tags (dumpCtags, dumpEtags)
16+
import Language.PureScript.Glob (PSCGlobs(..), toInputGlobs, warnFileTypeNotFound)
1617
import Options.Applicative qualified as Opts
1718
import Text.PrettyPrint.ANSI.Leijen qualified as PP
19+
import SharedCLI qualified
1820
import System.Directory (getCurrentDirectory, createDirectoryIfMissing, removeFile)
1921
import System.Exit (exitFailure)
2022
import System.FilePath ((</>))
21-
import System.FilePath.Glob (compile, glob, globDir1)
23+
import System.FilePath.Glob (compile, globDir1)
2224
import System.IO (hPutStrLn, stderr)
2325
import System.IO.UTF8 (writeUTF8FileT)
2426

@@ -35,12 +37,19 @@ data PSCDocsOptions = PSCDocsOptions
3537
, _pscdOutput :: Maybe FilePath
3638
, _pscdCompileOutputDir :: FilePath
3739
, _pscdInputFiles :: [FilePath]
40+
, _pscdInputFromFile :: Maybe FilePath
41+
, _pscdExcludeFiles :: [FilePath]
3842
}
3943
deriving (Show)
4044

4145
docgen :: PSCDocsOptions -> IO ()
42-
docgen (PSCDocsOptions fmt moutput compileOutput inputGlob) = do
43-
input <- concat <$> mapM glob inputGlob
46+
docgen (PSCDocsOptions fmt moutput compileOutput inputGlob inputGlobFromFile excludeGlob) = do
47+
input <- toInputGlobs $ PSCGlobs
48+
{ pscInputGlobs = inputGlob
49+
, pscInputGlobsFromFile = inputGlobFromFile
50+
, pscExcludeGlobs = excludeGlob
51+
, pscWarnFileTypeNotFound = warnFileTypeNotFound "docs"
52+
}
4453
when (null input) $ do
4554
hPutStrLn stderr "purs docs: no input files."
4655
exitFailure
@@ -104,7 +113,13 @@ defaultOutputForFormat fmt =
104113
Ctags -> "tags"
105114

106115
pscDocsOptions :: Opts.Parser PSCDocsOptions
107-
pscDocsOptions = PSCDocsOptions <$> format <*> output <*> compileOutputDir <*> many inputFile
116+
pscDocsOptions =
117+
PSCDocsOptions <$> format
118+
<*> output
119+
<*> compileOutputDir
120+
<*> many SharedCLI.inputFile
121+
<*> SharedCLI.globInputFile
122+
<*> many SharedCLI.excludeFiles
108123
where
109124
format :: Opts.Parser Format
110125
format = Opts.option Opts.auto $
@@ -128,11 +143,6 @@ pscDocsOptions = PSCDocsOptions <$> format <*> output <*> compileOutputDir <*> m
128143
<> Opts.metavar "DIR"
129144
<> Opts.help "Compiler output directory"
130145

131-
inputFile :: Opts.Parser FilePath
132-
inputFile = Opts.strArgument $
133-
Opts.metavar "FILE"
134-
<> Opts.help "The input .purs file(s)"
135-
136146
command :: Opts.Parser (IO ())
137147
command = docgen <$> (Opts.helper <*> pscDocsOptions)
138148

app/Command/Graph.hs

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,30 @@ import Data.ByteString.Lazy qualified as LB
1010
import Data.ByteString.Lazy.UTF8 qualified as LBU8
1111
import Language.PureScript qualified as P
1212
import Language.PureScript.Errors.JSON (JSONResult(..), toJSONErrors)
13+
import Language.PureScript.Glob (PSCGlobs(..), toInputGlobs, warnFileTypeNotFound)
1314
import Options.Applicative qualified as Opts
15+
import SharedCLI qualified
1416
import System.Console.ANSI qualified as ANSI
1517
import System.Exit (exitFailure)
1618
import System.Directory (getCurrentDirectory)
17-
import System.FilePath.Glob (glob)
1819
import System.IO (hPutStr, hPutStrLn, stderr)
1920

2021
data GraphOptions = GraphOptions
2122
{ graphInput :: [FilePath]
23+
, graphInputFromFile :: Maybe FilePath
24+
, graphExclude :: [FilePath]
2225
, graphJSONErrors :: Bool
2326
}
2427

2528
graph :: GraphOptions -> IO ()
2629
graph GraphOptions{..} = do
27-
input <- globWarningOnMisses (unless graphJSONErrors . warnFileTypeNotFound) graphInput
30+
input <- toInputGlobs $ PSCGlobs
31+
{ pscInputGlobs = graphInput
32+
, pscInputGlobsFromFile = graphInputFromFile
33+
, pscExcludeGlobs = graphExclude
34+
, pscWarnFileTypeNotFound = unless graphJSONErrors . warnFileTypeNotFound "graph"
35+
}
36+
2837
when (null input && not graphJSONErrors) $ do
2938
hPutStr stderr $ unlines
3039
[ "purs graph: No input files."
@@ -37,26 +46,16 @@ graph GraphOptions{..} = do
3746
printWarningsAndErrors graphJSONErrors makeWarnings makeResult
3847
>>= (LB.putStr . Json.encode)
3948

40-
where
41-
warnFileTypeNotFound :: String -> IO ()
42-
warnFileTypeNotFound =
43-
hPutStrLn stderr . ("purs graph: No files found using pattern: " <>)
44-
45-
4649
command :: Opts.Parser (IO ())
4750
command = graph <$> (Opts.helper <*> graphOptions)
4851
where
4952
graphOptions :: Opts.Parser GraphOptions
5053
graphOptions =
51-
GraphOptions <$> many inputFile
54+
GraphOptions <$> many SharedCLI.inputFile
55+
<*> SharedCLI.globInputFile
56+
<*> many SharedCLI.excludeFiles
5257
<*> jsonErrors
5358

54-
inputFile :: Opts.Parser FilePath
55-
inputFile =
56-
Opts.strArgument $
57-
Opts.metavar "FILE" <>
58-
Opts.help "The input .purs file(s)."
59-
6059
jsonErrors :: Opts.Parser Bool
6160
jsonErrors =
6261
Opts.switch $
@@ -84,16 +83,3 @@ printWarningsAndErrors True warnings errors = do
8483
case errors of
8584
Left _errs -> exitFailure
8685
Right res -> pure res
87-
88-
89-
globWarningOnMisses :: (String -> IO ()) -> [FilePath] -> IO [FilePath]
90-
globWarningOnMisses warn = concatMapM globWithWarning
91-
where
92-
globWithWarning :: String -> IO [FilePath]
93-
globWithWarning pattern' = do
94-
paths <- glob pattern'
95-
when (null paths) $ warn pattern'
96-
return paths
97-
98-
concatMapM :: (a -> IO [b]) -> [a] -> IO [b]
99-
concatMapM f = fmap concat . mapM f

app/Command/Ide.hs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import Language.PureScript.Ide.State (updateCacheTimestamp)
3535
import Language.PureScript.Ide.Types (Ide, IdeConfiguration(..), IdeEnvironment(..), IdeLogLevel(..), emptyIdeState)
3636
import Network.Socket qualified as Network
3737
import Options.Applicative qualified as Opts
38+
import SharedCLI qualified
3839
import System.Directory (doesDirectoryExist, getCurrentDirectory, setCurrentDirectory)
3940
import System.FilePath ((</>))
4041
import System.IO (BufferMode(..), hClose, hFlush, hSetBuffering, hSetEncoding, utf8)
@@ -59,6 +60,8 @@ listenOnLocalhost port = do
5960
data ServerOptions = ServerOptions
6061
{ _serverDirectory :: Maybe FilePath
6162
, _serverGlobs :: [FilePath]
63+
, _serverGlobsFromFile :: Maybe FilePath
64+
, _serverGlobsExcluded :: [FilePath]
6265
, _serverOutputPath :: FilePath
6366
, _serverPort :: Network.PortNumber
6467
, _serverLoglevel :: IdeLogLevel
@@ -110,7 +113,7 @@ command = Opts.helper <*> subcommands where
110113
Opts.option Opts.auto (Opts.long "port" `mappend` Opts.short 'p' `mappend` Opts.value (4242 :: Integer))
111114

112115
server :: ServerOptions -> IO ()
113-
server opts'@(ServerOptions dir globs outputPath port logLevel editorMode polling noWatch) = do
116+
server opts'@(ServerOptions dir globs globsFromFile globsExcluded outputPath port logLevel editorMode polling noWatch) = do
114117
when (logLevel == LogDebug || logLevel == LogAll)
115118
(putText "Parsed Options:" *> print opts')
116119
maybe (pure ()) setCurrentDirectory dir
@@ -136,6 +139,8 @@ command = Opts.helper <*> subcommands where
136139
{ confLogLevel = logLevel
137140
, confOutputPath = outputPath
138141
, confGlobs = globs
142+
, confGlobsFromFile = globsFromFile
143+
, confGlobsExclude = globsExcluded
139144
}
140145
ts <- newIORef Nothing
141146
let
@@ -150,7 +155,9 @@ command = Opts.helper <*> subcommands where
150155
serverOptions =
151156
ServerOptions
152157
<$> optional (Opts.strOption (Opts.long "directory" `mappend` Opts.short 'd'))
153-
<*> many (Opts.argument Opts.str (Opts.metavar "Source GLOBS..."))
158+
<*> many SharedCLI.inputFile
159+
<*> SharedCLI.globInputFile
160+
<*> many SharedCLI.excludeFiles
154161
<*> Opts.strOption (Opts.long "output-directory" `mappend` Opts.value "output/")
155162
<*> (fromIntegral <$>
156163
Opts.option Opts.auto (Opts.long "port" `mappend` Opts.short 'p' `mappend` Opts.value (4242 :: Integer)))

app/Command/REPL.hs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,25 @@ import Control.Monad.Trans.Reader (ReaderT, runReaderT)
1515
import Data.Foldable (for_)
1616
import Language.PureScript qualified as P
1717
import Language.PureScript.CST qualified as CST
18+
import Language.PureScript.Glob (PSCGlobs(..), toInputGlobs, warnFileTypeNotFound)
1819
import Language.PureScript.Interactive
1920
import Options.Applicative qualified as Opts
21+
import SharedCLI qualified
2022
import System.Console.Haskeline (InputT, Settings(..), defaultSettings, getInputLine, handleInterrupt, outputStrLn, runInputT, setComplete, withInterrupt)
2123
import System.IO.UTF8 (readUTF8File)
2224
import System.Exit (ExitCode(..), exitFailure)
2325
import System.Directory (doesFileExist, getCurrentDirectory)
2426
import System.FilePath ((</>))
25-
import System.FilePath.Glob qualified as Glob
2627
import System.IO (hPutStrLn, stderr)
2728

2829
-- | Command line options
2930
data PSCiOptions = PSCiOptions
3031
{ psciInputGlob :: [String]
32+
, psciInputFromFile :: Maybe String
33+
, psciExclude :: [String]
3134
, psciBackend :: Backend
3235
}
3336

34-
inputFile :: Opts.Parser FilePath
35-
inputFile = Opts.strArgument $
36-
Opts.metavar "FILES"
37-
<> Opts.help "Optional .purs files to load on start"
38-
3937
nodePathOption :: Opts.Parser (Maybe FilePath)
4038
nodePathOption = Opts.optional . Opts.strOption $
4139
Opts.metavar "FILE"
@@ -63,7 +61,9 @@ backend =
6361
<|> (nodeBackend <$> nodePathOption <*> nodeFlagsOption)
6462

6563
psciOptions :: Opts.Parser PSCiOptions
66-
psciOptions = PSCiOptions <$> many inputFile
64+
psciOptions = PSCiOptions <$> many SharedCLI.inputFile
65+
<*> SharedCLI.globInputFile
66+
<*> many SharedCLI.excludeFiles
6767
<*> backend
6868

6969
-- | Parses the input and returns either a command, or an error as a 'String'.
@@ -132,7 +132,12 @@ command = loop <$> options
132132
where
133133
loop :: PSCiOptions -> IO ()
134134
loop PSCiOptions{..} = do
135-
inputFiles <- concat <$> traverse Glob.glob psciInputGlob
135+
inputFiles <- toInputGlobs $ PSCGlobs
136+
{ pscInputGlobs = psciInputGlob
137+
, pscInputGlobsFromFile = psciInputFromFile
138+
, pscExcludeGlobs = psciExclude
139+
, pscWarnFileTypeNotFound = warnFileTypeNotFound "repl"
140+
}
136141
e <- runExceptT $ do
137142
modules <- ExceptT (loadAllModules inputFiles)
138143
when (null modules) . liftIO $ do

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/purescript/purescript/commit/5dcd000363c3c27e29f2bb8e6848c7782c17a40d

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy