@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP, ConstraintKinds #-}
2#if !(MIN_VERSION_base(4,8,0))
2#if !(MIN_VERSION_base(4,8,0))
3{-# LANGUAGE OverlappingInstances #-}
3{-# LANGUAGE OverlappingInstances #-}
@@ -14,6 +14,7 @@ import Idris.CmdOptions
15import Control.Monad.State.Strict
15import Control.Monad.State.Strict
16import Control.Applicative
16import Control.Applicative
17+import System.FilePath (takeFileName, isValid)
18import Util.System
19import Util.System
@@ -62,11 +63,41 @@ pPkg = do
67+-- | Parses a filename.
69+-- | Treated for now as an identifier or a double-quoted string.
70+filename :: (MonadicParsing m, HasLastTokenSpan m) => m String
73+ -- Treat a double-quoted string as a filename to support spaces.
74+ -- This also moves away from tying filenames to identifiers, so
75+ -- it will also accept hyphens
76+ -- (https://github.com/idris-lang/Idris-dev/issues/2721)
79+ -- Through at least version 0.9.19.1, IPKG executable values were
80+ -- possibly namespaced identifiers, like foo.bar.baz.
81+ show <$> fst <$> iName []
82+ if isValidFilename filename
84+ else fail "a filename must be non-empty and have no directory component")
87+ isValidFilename :: FilePath -> Bool
88+ isValidFilename path =
89+ and [isNonEmpty, isValidPath, hasNoDirectoryComponent]
91+ isNonEmpty = path /= ""
92+ isValidPath = System.FilePath.isValid path
93+ hasNoDirectoryComponent = path == takeFileName path
65pClause :: PParser ()
96pClause :: PParser ()
66pClause = do reserved "executable"; lchar '=';
97pClause = do reserved "executable"; lchar '=';
67− exec <- fst <$> iName []
98+ exec <- filename
69− put (st { execout = Just (show exec) })
100+ put (st { execout = Just exec })
70 <|> do reserved "main"; lchar '=';
101 <|> do reserved "main"; lchar '=';
71 main <- fst <$> iName []
102 main <- fst <$> iName []
72 st <- get
103 st <- get