Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose Development.Shake.FilePattern.match or similar #485

Closed
dmwit opened this issue Sep 15, 2016 · 5 comments
Closed

expose Development.Shake.FilePattern.match or similar #485

dmwit opened this issue Sep 15, 2016 · 5 comments

Comments

@dmwit
Copy link

dmwit commented Sep 15, 2016

I want to write a rule like this:

"build/year-*-loc-*.json" %> \fp -> do
    let [year, loc] = match "build/year-*-loc-*.json" fp
    buildJSONFor year loc

where here if the matching file were, say, build/year-2016-loc-OR.json, the variables year and loc would get bound to "2016" and "OR", respectively. I could imagine wanting to know which part of the filename the // and ** globs matched as well, of course. Perhaps a slightly higher-level API would also be welcome, e.g. something like

 pattern !> act = pattern %> (act . match pattern)

so that the above rule could also be written:

"build/year-*-loc-*.json" !> \[year, loc] -> buildJSONFor year loc
@ndmitchell
Copy link
Owner

That does sound like quite a reasonable idea - only hard bit is figuring out exactly what the API should be. Does it deserve a symbol? I suspect so. Should the full path be the first component of the array? Is %%> a more natural symbol? I still have worries about the arity of the array not matching, but I guess there's no easy way to check that statically without TemplateHaskell or not using a string.

@dmwit
Copy link
Author

dmwit commented Sep 18, 2016

Should the full path be the first component of the array?

Empirically, I've found it quite useful to include it: if it is not included, and the action you want to run needs to know it (e.g. for the argument to -o to a compiler or similar), one must reconstruct it inside the Action from the values in the match, and this is error-prone and also violates DRY.

I still have worries about the arity of the array not matching, but I guess there's no easy way to check that statically without TemplateHaskell or not using a string.

I think checking this statically would require some fairly heavyweight infrastructure for a smallish benefit, especially considering how easy it is to notice that you got it wrong when testing the new rule you just wrote. You could also look to the various regex libraries, which also do the statically unsafe thing and return a [] or Array of matches.

For posterity, I implemented a similar function using regex-tdfa like this and have found it quite useful; the only change to the API I suggested above is that my action takes the full filename as a separate argument:

type FileRegex = String

(!>) :: FileRegex -> (String -> [String] -> Action ()) -> Rules ()
(!>) pat = \act -> case regex_ of
    Left problem -> fail problem
    Right regex -> actOnPath $ \fp -> case regexec regex fp of
        Left problem -> error ("in (!>): " ++ problem) -- should never happen
        Right (Just (pre, main, post, rest))
            | null pre && null post -> Just (act main rest)
        _ -> Nothing
    where
    regex_ = compile
        defaultCompOpt { lastStarGreedy = True }
        defaultExecOpt
        pat

@dmwit
Copy link
Author

dmwit commented Sep 18, 2016

Oh yes, and I forgot to include the definition of actOnPath:

-- TODO: add this to shake so that we do not need to run the argument twice
actOnPath :: (FilePath -> Maybe (Action ())) -> Rules ()
actOnPath f = (isJust . f) ?> (fromJust . f)

...but that's a separate feature request. ;-)

@ndmitchell
Copy link
Owner

The new Shake has filePattern exposed which should make implementing this on the outside feasible - I recommend people have a go at what an API should be, use it internally, and if they like it, share back here.

@ndmitchell
Copy link
Owner

See https://hackage.haskell.org/package/filepattern which now offers a complete API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants