summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2018-01-24 13:54:45 +0100
committerYorhel <git@yorhel.nl>2018-01-24 13:54:45 +0100
commit45297a9097296bbd3f7a008df95da3cfb88ba4b7 (patch)
treeed77abd845d17bdcc002142524bbbd8439413abf
parent005acbf1d2bdb56d358d1e4e3a74f498a6e9cbdc (diff)
Add -I command line flag
-rw-r--r--Main.hs37
-rw-r--r--nginx-confgen.cabal1
-rw-r--r--nginx-confgen.pod10
-rw-r--r--test/main.conf5
4 files changed, 40 insertions, 13 deletions
diff --git a/Main.hs b/Main.hs
index 492c82b..48f2b5a 100644
--- a/Main.hs
+++ b/Main.hs
@@ -3,7 +3,7 @@ module Main where
import Control.Applicative (empty)
import Control.Exception.Base (throwIO,Exception)
-import Control.Monad (void,foldM,join)
+import Control.Monad (void,foldM,join,filterM)
import qualified Data.Array as A
import Data.Char (isSpace)
import Data.HashMap.Strict (HashMap)
@@ -12,6 +12,7 @@ import Data.Semigroup ((<>))
import Data.Void
import Options.Applicative hiding (Parser, ParseError)
import System.Directory
+import System.FilePath
import System.IO (hPutStrLn,stderr)
import System.IO.Error (tryIOError)
import System.Process
@@ -173,6 +174,7 @@ data Error
| MacroNoNeedsBlock String
| MacroNeedsBlock String
| IncludeArg
+ | IncludeNotFound String
| IncludeParse (ParseError (Token String) Void)
| IncludeRecurse
| SetArg
@@ -198,6 +200,7 @@ instance Show Error where
show (MacroNoNeedsBlock n) = "Macro '"++n++"' does not accept a block argument"
show (MacroNeedsBlock n) = "Macro '"++n++"' requires a block argument, but none given"
show IncludeArg = "Invalid argument(s) to 'pre_include'"
+ show (IncludeNotFound f) = "Can't find include file '"++f++"'"
show (IncludeParse e) = parseErrorPretty e
show IncludeRecurse = "Recursion depth exceeded with 'pre_include'"
show SetArg = "Invalid argument(s) to 'pre_set'"
@@ -377,8 +380,24 @@ ifExpand st arg conf = do
+includeExpand :: PState -> Int -> String -> IO (PState, [Directive])
+includeExpand st n fn = do
+ fns <- filterM doesFileExist $ map (</>fn) $ stIncDir st
+ f <- case fns of
+ [] -> throwIO (IncludeNotFound fn)
+ f:_ -> return f
+ contents <- readFile f
+ ast <- case parse parser fn contents of
+ Left e -> throwIO (IncludeParse e)
+ Right r -> return r
+ (nst, conf) <- procConf (st { stIncludes = n-1 }) ast
+ return (nst { stIncludes = n+1 }, conf)
+
+
+
data PState = PState
- { stVars :: HashMap String [ArgComponent]
+ { stIncDir :: [String]
+ , stVars :: HashMap String [ArgComponent]
, stMacros :: HashMap String Macro
, stArgs :: HashMap String [ArgComponent] -- shadows stVars
-- Max 1, but Prelude's 'lookup' isn't generic to work on Maybe, so this'll do
@@ -431,13 +450,7 @@ procConf gst gconf = foldM p (gst, []) gconf
stmt st (Directive "pre_include" a b) =
case (stIncludes st, a, b) of
(0, _, _) -> throwIO IncludeRecurse
- (i, ArgString [Literal n]:[], Nothing) -> do
- contents <- readFile n
- ast <- case parse parser n contents of
- Left e -> throwIO (IncludeParse e)
- Right r -> return r
- (nst, conf) <- procConf (st { stIncludes = i-1 }) ast
- return (nst { stIncludes = i+1 }, conf)
+ (i, ArgString [Literal n]:[], Nothing) -> includeExpand st i n
_ -> throwIO IncludeArg
stmt st (Directive "pre_set" a b) =
@@ -486,6 +499,7 @@ data Options = Options
{ optVersion :: Bool
, optInput :: String
, optOutput :: String
+ , optInclude :: [String]
}
main :: IO ()
@@ -504,8 +518,11 @@ main = do
<$> switch (short 'V' <> long "version" <> hidden <> help "Show program version")
<*> strOption (short 'i' <> metavar "FILE" <> value "-" <> showDefault <> help "Input file")
<*> strOption (short 'o' <> metavar "FILE" <> value "-" <> showDefault <> help "Output file")
+ <*> many (strOption (short 'I' <> metavar "DIR" <> help "Add search path for pre_include directives"))
prog o = do
+ let inc = if null (optInclude o) then ["."] else optInclude o
+
input <- if optInput o == "-"
then getContents
else readFile (optInput o)
@@ -513,7 +530,7 @@ main = do
case parse parser (optInput o) input of
Left e -> hPutStrLn stderr $ parseErrorPretty e
Right r -> do
- output <- fmt <$> procConf' (PState mempty mempty mempty mempty mempty 15) r
+ output <- fmt <$> procConf' (PState inc mempty mempty mempty mempty mempty 15) r
if optOutput o == "-"
then putStr output
else writeFile (optOutput o) output
diff --git a/nginx-confgen.cabal b/nginx-confgen.cabal
index 8ebb227..5df1bf7 100644
--- a/nginx-confgen.cabal
+++ b/nginx-confgen.cabal
@@ -20,6 +20,7 @@ executable nginx-confgen
array
, base
, directory
+ , filepath
, megaparsec
, optparse-applicative
, process
diff --git a/nginx-confgen.pod b/nginx-confgen.pod
index 2bc0176..d4efeb5 100644
--- a/nginx-confgen.pod
+++ b/nginx-confgen.pod
@@ -54,6 +54,13 @@ C<->, then the file will be read from standard input.
Write the output to the given file. If this option is not given or set to C<->,
then the file will be written to standard output.
+=item -I I<DIR>
+
+Set the search path for I<pre_include> directives. This option can be given
+multiple times to search several directories in order. If this option is not
+given, then include files are resolved relative to the directory that
+nginx-confgen is run from (i.e. C<-I .>).
+
=back
@@ -68,8 +75,7 @@ during preprocessing. The included file may contain any preprocessing
directives supported by nginx-confgen. Variables and macros defined in the
included file will be available in the parent file.
-Beware that relative paths are resolved from the working directory that
-nginx-confgen is run from.
+Relative paths are searched for in the directories given with the C<-I> flag.
=head2 pre_set
diff --git a/test/main.conf b/test/main.conf
index 249d7ad..09cda5b 100644
--- a/test/main.conf
+++ b/test/main.conf
@@ -24,7 +24,10 @@ pre_exec $nameserver "grep nameserver /etc/resolv.conf \\
| head -n 1 | sed 's/^nameserver //'";
resolver $nameserver;
-pre_include test/macros.conf;
+# This needs -Itest to resolve
+pre_include macros.conf;
+
+pre_include /dev/null;
http {
types {