I'm new to IIS and i've a PHP project with all files in a public directory, in such a structure:
Root/public/index.phplogin.phpsub1/index.phpedit.phpsub2/index.phpsrc/js/script.jscss/theme.css
I need some rewrite rules for:
hide extension for just PHP files:example.com -> example.com/public/index.phpexample.com/login -> example.com/public/login.phpexample.com/sub1/edit -> example.com/public/sub1/edit.phpexample.com/src/css/theme.css -> example.com/src/css/theme.cssdefault index.php for subdirectories, if page is not specified:example.com/sub1/ -> example.com/public/sub1/index.phpexample.com/sub1/edit -> example.com/public/sub1/edit.phpoptional trailing slash for both pages and subdirectories:example.com/login -> example.com/public/login.phpexample.com/login/ -> example.com/public/login.phpexample.com/sub1 -> example.com/public/sub1/index.phpexample.com/sub1/ -> example.com/public/sub1/index.php example.com/sub1/edit -> example.com/public/sub1/edit.phpexample.com/sub1/edit/ -> example.com/public/sub1/edit.php
Related
I have a yesod site serving content that includes rest WaiSubsites. all working. I have a need to serve a small REACT based site and I'd like to use the same basic infrastructure to add a simple reverse proxying subset would embed that REACT server. I'm aware that I could put nginx etc. in front but I don't want to do that.
Is there an easy solution?
thanks,
Stephen.
update. So I've built a basic solution, but I'd like to be able to map random /x/y to /y and so I need to rewrite the response content URLs of form /y to /x/y. having trouble workin out the process response handler. anyone?
makeExternalServerProxy :: Manager -> ByteString -> Int -> Application
makeExternalServerProxy manager host port =
simpleCors $ S.serveWithContext (S.Proxy :: S.Proxy S.Raw) S.EmptyContext forwardH
where -- | proxy based forwarding of non API requests to host:port
forwardH :: S.Tagged S.Handler Application
forwardH = S.Tagged $ waiProxyToSettings
forwardRequest proxySettings manager
forwardRequest :: Network.Wai.Request -> IO WaiProxyResponse
forwardRequest req =
pure $ WPRModifiedRequest
(rewriteRequestPure (\(pq,q) _ -> ( case pq of
[] -> []
(_:xs) -> xs
, q)) req)
(ProxyDest host port)
-- | Sends a simple 402 error message with the contents of the exception.
handleException :: SomeException -> Application
handleException exc _ sr = sr $ responseLBS
HT.status402
[("content-type", "text/plain")]
("We're sorry: Internal Error:\n\n" <>
TLE.encodeUtf8 (pack $ show exc))
proxySettings = defaultWaiProxySettings
{ wpsOnExc = handleException
, wpsProcessBody = processResponse
}
processResponse :: Network.Wai.Request -> Response () -> Maybe (ConduitT ByteString (Flush Builder) IO ())
processResponse = undefined
I'm trying to use the FilePath.Find function from FileManip to ignore recursion on certain directories.
E.g. I want to ignore directories ending in test, or ignore .git, etc.
Example: give me all files not in the stack-work dir or the web dir
import System.Directory
import System.Environment
import System.FilePath.Find
import System.FilePath.GlobPattern
import qualified Data.List as L
import Control.Monad
notIsSuffixOf :: [Char] -> [Char] -> Bool
notIsSuffixOf a b = not (L.isSuffixOf a b)
nots :: FindClause Bool
nots = (\d -> notIsSuffixOf "web" d || notIsSuffixOf "stack-work" d) `liftM` directory
findAllNots :: FilePath -> IO [FilePath]
findAllNots path = find nots (fileType ==? RegularFile) path
But it's definitely not ignoring the web or stack-work directories. I've been wracking my brain on this but can't seem to figure it out. Doing them in isolation doesn't seem to work reliably either (doing just stack-work works, but "web" still matches /blah/web/jds.txt for example.
If I change it to isSuffixOf I match on nothing, which is also disconcerting. Reading through http://hackage.haskell.org/package/filemanip-0.3.6.3/docs/System-FilePath-Find.html indicates that this should work, see top example where (isInfixOf "temp") `liftM` directory matches any directory with temp
In Test Dir
Test (Dir)
-> 20171101 (Dir)
-> 20171102 (Dir)
-> images (Dir)
-> test.apple.1.txt
-> 20171103 (Dir)
-> images (Dir)
-> test.apple.2.txt
I want to make symbolic link below :
Test2 (Test's symbolic link)
-> 20171101 (Dir)
-> 20171102 (Dir)
-> images (Dir)
-> test.banana.1.txt
-> 20171103 (Dir)
-> images (Dir)
-> test.banana.2.txt
I want to change file name pattern apple to banana while making symbolic link.
In result,
In original dir, test.apple.1.txt remains
In symbolic link, test.banana.1.txt remains
I find show pattern change shell script below:
for i in `find .`; do echo `echo $i | sed -e 's/apple/banana/'`; done;
But making symbolic link is difficult..
Is it possible?
I'm currently testing porting our build system from make to shake and have hit a roadblock:
Given the following project structure:
static/a.js
static/b.coffee
build/a.js
build/b.js
That is, various input extensions map to identical output extensions, so a straightforward "build//*.js" %> rule isn't going to work.
I wanted to avoid using priority if possible, and writing an ad-hoc build rule that checks for the existence of either possible input felt clunky (especially since this situation occurs with other filetypes as well), so I wrote the following:
data StaticFileMapping a = StaticFileMapping String String (FilePath -> FilePath -> Action a)
staticInputs :: FilePath -> StaticFileMapping a -> Action [FilePath]
staticInputs dir (StaticFileMapping iExt _ _) = (findFiles (dir </> "static") [iExt])
staticInputToOutput :: StaticFileMapping a -> FilePath -> FilePath
staticInputToOutput (StaticFileMapping _ oExt _) = (remapDir ["build"]) . (-<.> oExt)
staticTargets :: FilePath -> StaticFileMapping a -> Action [FilePath]
staticTargets dir sfm = (map $ staticInputToOutput sfm) <$> staticInputs dir sfm
rules :: FilePath -> StaticFileMapping a -> Rules ()
rules dir sfm#(StaticFileMapping _ _ process) = join $ mconcat . (map buildInputRule) <$> staticInputs dir sfm
where buildInputRule :: FilePath -> Rules ()
buildInputRule input = (staticInputToOutput sfm input) %> (process input)
That way I can define a mapping for each input type (.coffee -> .js, .svg -> .png) and so on, with only a tiny amount of code implementing the transformation for each. And it almost works.
But it seems impossible to go from (Action a) to Rules _ without throwing the value inside the Action away first, as far as I can tell.
Is there a function with type (Action a) -> (a -> Rules ()) -> Rules () or (Action a) -> (Rules a)? Can I implement either one myself, or do I need to modify the library's code?
Or is this entire approach hare-brained and I should take some other route?
First off, using priority would not work, as that picks a rule statically then runs it - it doesn't backtrack. It's also important that Shake doesn't run any Action operations to produce Rules (as per the two functions you propose) since the Action might call need on a Rule that it itself defines, or is defined by another action rule, thus making the ordering of those Action calls visible. You could add IO (Rules ()) -> Rules (), which might be enough for what you are thinking of (directory listing), but it isn't currently exposed (I have an internal function that does exactly that).
To give a few example approaches it's useful to define plausible commands to convert .js/.coffee files:
cmdCoffee :: FilePath -> FilePath -> Action ()
cmdCoffee src out = do
need [src]
cmd "coffee-script-convertor" [src] [out]
cmdJavascript :: FilePath -> FilePath -> Action ()
cmdJavascript = copyFile'
Approach 1: Use doesFileExist
This would be my standard approach, writing something like:
"build/*.js" %> \out -> do
let srcJs = "static" </> dropDirectory1 out
let srcCf = srcJs -<.> "coffee"
b <- doesFileExist srcCf
if b then cmdCoffee srcCf out else cmdJavascript srcJs out
This accurately captures the dependency that if the user adds a .coffee file in the directory then the rule should be rerun. You could imagine sugaring up the doesFileExist if this is a common pattern for you. You could even drive it from you list of StaticFileMapping structures (do a group on the oExt field to add one rule per oExt than calls doesFileExists on each iExt in turn). An advantage of this approach is that if you do shake build/out.js it doesn't need to do a directory listing, although likely that cost is negligible.
Approach 2: List the files before calling shake
Instead of writing main = shakeArgs ... do:
import System.Directory.Extra(listFilesRecursive) -- from the "extra" package
main = do
files <- listFilesRecursive "static"
shakeArgs shakeOptions $ do
forM_ files $ \src -> case takeExtension src of
".js" -> do
let out = "build" </> takeDirectory1 src
want [out]
out %> \_ -> cmdJavascript src out
-- rules for all other types you care about
_ -> return ()
Here you operate in IO to get the list of files, then can add rules by referring to that previously captured value. Adding rulesIO :: IO (Rules ()) -> Rules () would allow you to list the files inside shakeArgs.
Approach 3: List the files inside the rules
You can define a mapping between file names and outputs, driven from the directory listing:
buildJs :: Action (Map FilePath (Action ()))
buildJs = do
js <- getDirectoryFiles "static" ["*.js"]
cf <- getDirectoryFiles "static" ["*.coffee"]
return $ Map.fromList $
[("build" </> j, cmdJavascript ("static" </> j) ("build" </> j)) | j <- js] ++
[("build" </> c, cmdCoffee ("static" </> c) ("")) | c <- cf]
Then lift that into a set of rules:
action $ do
mpJs <- buildJs
need $ Map.keys mpJs
"//*.js" %> \out -> do
mpJs <- buildJs
mpJs Map.! out
However, that recomputes the directory listing for every file we build, so we should cache it and make sure it's only computed once:
mpJs <- newCache $ \() -> buildJs
action $ do
mpJs <- mpJs ()
need $ Map.keys mpJs
"//*.js" %> \out -> do
mpJs <- mpJs ()
mpJs Map.! out
This solution is probably closest to your original approach, but I find it the most complex.
I'm making a Yesod subsite and am getting a type error in some Template Haskell-generated code:
Yesod\DataSource\Data.hs:19:1:
Couldn't match type `[Char]' with `Text'
Expected type: () -> ([Text], [(Text, Text)]) -> Maybe (Route DataSource)
Actual type: () -> ([[Char]], [(Text, Text)]) -> Maybe (Route DataSource)
In the first argument of `\ f_amMs x_amMt -> f_amMs () x_amMt ::
forall a_amMu.
(() -> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu))
-> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu)', namely
`helper_amMr'
In the expression:
\ f_amMs x_amMt -> f_amMs () x_amMt ::
forall a_amMu.
(() -> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu))
-> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu)
helper_amMr
The problem is clear, but I don't understand why it's generating incorrect code.
The issue occurs in this TH call:
mkYesodSubData "DataSource" [parseRoutes|
/ SubHomeR GET
/datasource DataSourceInputR POST GET
|]
Specifically, it is caused by the line:
/datasource DataSourceInputR POST GET
Removing this line fixes the issue.
I'm using Stackage LTS 1.15:
remote-repo: stackage-lts-1.15:http://www.stackage.org/snapshot/lts-1.15
And I'm inside a cabal sandbox.
Here are the relevant files: https://gist.github.com/BeerendLauwers/774cc432c3ada5b597e1
Any idea?
I think that the generated code expects that you have the OverloadedStrings extension enabled in your source file. Try adding
{-# LANGUAGE OverloadedStrings #-}
to the top of the source file where you splice in the Template Haskell code (i.e. Data.hs).