filepatterns to exclude a match - shake-build-system

Shake uses various forms of matching, filepath against pattern. Is there one which can be used to exclude a pattern?
Example:
I have three directories a, b, c (somewhere in directory x) and each needs html files. There is a rule
(dir <> "//*.html") %> \out -> do -- deal with a and b
which should only deal with the directories a and b and a similar rule to process the files in c.
Is there a way (perhaps using ?>) to separate the two rules for one
(\f -> "x" prefixOf f && not "x/c" prefixOf f) <> "//*.html")
(\f -> "x/x" prefixOf f ) <> "//*.html")
and the other similarly?
The recommended approach to use xx.a.html and xx.b.html is here not possible, because files are processed with other programs which expect the regular html extension.
Alternatively

The rule:
pattern %> action
Is equivalent to:
(pattern ?==) ?> action
So you can write:
(\x -> "//*.html" ?== x && not ("c//*.html" ?== x) ?> action
To match rules matching //*.html, but not c//*.html.
More generally, there is no requirement to use the FilePattern ?== operator at all, so arbitrary matching predicates can be used instead.

With the advice (especially the hint about using **/*.html) I have it working.
The path bakedD is a prefix of staticD and the first rule deals only with files in bakedD which are not in staticD, the other only with these:
(\x -> ((bakedD <> "**/*.html") ?== x)
&& not ((staticD <> "**/*.html") ?== x)) ?> \out -> do
let md = doughD </> (makeRelative bakedD $ out -<.> "md")
runErr2action $ bakeOneFileFPs md doughD templatesD out
(staticD <> "**/*.html" ) %> \out -> do
copyFileChanged (replaceDirectory out doughD) out
There is no overlap between the two rules.
I hope this is useful for others with the same type of issue.

Related

Eiffel: regular expressions how to do grouping

I'd like to do grouping of regular expressions with eiffel. How do I do something like
l_reg.compile ("^([0-9]{3}) (rabbit[0-9]).*")
l_groups := l_reg.groups ("123 rabbit1")
my_first_rabbit := l_groups.at (2)
Didn't find any example on groups, LX_DFA_REGULAR_EXPRESSION class and other googlings
One solution is to use RX_PCRE_REGULAR_EXPRESSION instead of LX_DFA_REGULAR_EXPRESSION:
Including $ISE_LIBRARY\contrib\library\gobo\library\regexp\src\library.ecf library
l_reg: RX_PCRE_REGULAR_EXPRESSION
...
l_reg.compile ("^([0-9]{3}) (rabbit[0-9]).*")
l_reg.match ("123 rabbit1")
my_first_rabbit := l_reg.captured_substring (2)
There is no groups routine, although it could be implemented by calling captured_substring internally. There is only a routine split which does the reverse: returns the substrings which did not match the regular expression.
Something like
regex_groups (a_haystack, a_needle: STRING): ARRAY[STRING]
-- Test with https://www.regextester.com/1911
require
regex_match (a_haystack, a_needle)
local
l_reg: RX_PCRE_REGULAR_EXPRESSION
l_index: like {RX_PCRE_REGULAR_EXPRESSION}.match_count
do
create Result.make_empty
create l_reg.make
l_reg.compile (a_needle)
if l_reg.is_compiled then
l_reg.match (a_haystack)
from
l_index := 1
until
l_index > l_reg.match_count
loop
Result.extend (l_reg.captured_substring (l_index))
l_index := l_index + 1
end
else
--- error compiling regex
fallible.set_last_error (create {SIT_INTERNAL_ERROR}.make ("regex_group-> regex does not compile:" + a_needle))
end
ensure
not fallible.has_error
instance_free: Class
end
you could test your regex here: https://www.regextester.com/1911

Recursing directories only goes one file deep

I have the following code:
find_info(File) ->
case file:read_file_info(File) of
{ok, Facts} ->
case Facts#file_info.type of
directory -> directory;
regular -> regular
end;
{error,Reason} -> exit(Reason)
end.
find_files(Dir,Flag,Ending,Acc) ->
case file:list_dir(Dir) of
{ok,A} -> find_files_helper(A,Dir,Flag,Acc,Ending);
{_,_} -> Acc
end.
find_files_helper([H|Tail],Dir,Flag,Acc,Ending) ->
A = find_info(filename:absname_join(Dir,H)),
case A of
directory ->
case Flag of
true ->
find_files(filename:absname_join(Dir,H),Flag,Ending,Acc ++ find_files_helper(Tail,Dir,Flag,Acc,Ending));
false -> find_files_helper(Tail,Dir,Flag,Acc,Ending)
end;
regular ->
case filename:extension(H) of
Ending -> find_files_helper(Tail,Dir,Flag,[to_md5_large(H)] ++ Acc, Ending);
_ -> find_files_helper(Tail,Dir,Flag,Acc,Ending)
end;
{error,Reason} -> exit(Reason)
end;
find_files_helper([],_,_,Acc,_) -> Acc.
However whenever I run the find_files/4 the program only goes one file deep before crashing.
Say I have the following directory
home/
a/
ser.erl
b/
c/
file.erl
file2.erl
When run I will get the md5 of file.erl of file2.erl and of ser.erl. However if the directory looks like this:
home/
a/
ser.erl
back.erl
b/
c/
file.erl
file2.erl
Then the whole program crashes. I have spent few good hours looking for what I'm missing here in my logic however I have no idea.
The error message that I get is exception enoent in function p:to_md5_large/1.
In case the md5 is needed here it is:
to_md5_large(File) ->
case file:read_file(File) of
{ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init());
{error,Reason} -> exit(Reason)
end.
md5_helper(<<A:4/binary,B>>,Acc) -> md5_helper(B,erlang:md5_update(Acc,A));
md5_helper(A,Acc) ->
B = erlang:md5_update(Acc,A),
erlang:md5_final(B).
You're getting enoent because you're passing a filename like back.erl to to_md5_large when you're not in the directory where back.erl is located. Try passing the full filename instead. You're already calling filename:absname_join(Dir,H) in find_files_helper, so just save that to a variable and pass that variable instead of H to to_md5_large.
There is a function that does this for you:
fold_files(Dir, RegExp, Recursive, Fun, AccIn) -> AccOut
in your case:
Result = filelib:fold_files(Dir, ".*\.erl", true, fun(X,Acc) -> {ok,B} = file:read_file(X), [erlang:md5(B)|Acc] end, []).
[edit]
#Bula:
I didn't answer directly to your question for 2 reasons:
The first one is that, at the time I was writing my answer, you didn't provide the type of error you get. It is very important, with any language, to learn how to get information from error report. In erlang, most of the time, you get the error type an the line where it occurs, looking at the documentation you will have a very helpful information about what was going wrong. By the way, unless you want to manage errors, I discourage you to write things like:
case file:read_file(File) of
{ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init());
{error,Reason} -> exit(Reason)
end.
The following code will do the same, shorter, and you'll get the exact line number where you got an issue (its not the best example in your code, but it's the shorter)
{ok, <<B/binary>>} = file:read_file(File),
md5_helper(B,erlang:md5_init()),
The second is that I find your code too big, with useless helper functions. I think it is important to try to have a concise and readable code, and also to try to use the library function in the right way. For example you are using erlang:md5:init/0, erlang:md5_update/2 and erlang:md5_final/1 while a single call to erlang:md5/1 is enough in your case. The way you use it exists to be able to calculate the md5 when you get the data chunk by chunk, which is not your case, and the way you wrote the helper function does not allow to use this feature.
I don't understand why you want to have a "deployed" version of your code, but I propose you another version where I tried to follow my advices (written directly in the shell, so it need R17+ for the definition of recursive anonymous function) :o)
1> F = fun F(X,D,Ending) ->
1> {ok,StartD} = file:get_cwd(), %% save current directory
1> ok = file:set_cwd(D), %% move to the directory to explore
1> R = case filelib:is_dir(X) of
1> true -> %% if the element to analyze is a directory
1> {ok,Files} = file:list_dir(X), %% getits content
1> [F(Y,X,Ending) || Y <- Files]; %% and recursively analyze all its elements
1> false ->
1> case filelib:is_regular(X) andalso (filename:extension(X) == Ending) of
1> true -> %% if it is a regular file with the right extension
1> {ok,B} = file:read_file(X), %% read it
1> [erlang:md5(B)]; %% and calculate the md5 (must be return in a list
1> %% for consistancy with directory results)
1> false ->
1> [] %% in other cases (symlink, ...) return empty
1> end
1> end,
1> ok = file:set_cwd(StartD), %% restore current directory
1> lists:flatten(R) %% flatten for nicer result
1> end.
#Fun<erl_eval.42.90072148>
2> Md5 = fun(D) -> F(D,D,".erl") end.
#Fun<erl_eval.6.90072148>
3> Md5("C:/My programs/erl6.2/lib/stdlib-2.2").
[<<150,238,21,49,189,164,184,32,42,239,200,52,135,78,12,
112>>,
<<226,53,12,102,125,107,137,149,116,47,50,30,37,13,211,243>>,
<<193,114,120,24,175,27,23,218,7,169,146,8,19,208,73,255>>,
<<227,219,237,12,103,218,175,238,194,103,52,180,132,113,
184,68>>,
<<6,16,213,41,39,138,161,36,184,86,17,183,125,233,20,125>>,
<<23,208,91,76,69,173,159,200,44,72,9,9,50,40,226,27>>,
<<92,8,168,124,230,1,167,199,6,150,239,62,146,119,83,36>>,
<<100,238,68,145,58,22,88,221,179,204,19,26,50,172,142,193>>,
<<253,79,101,49,78,235,151,104,188,223,55,228,163,25,16,
147>>,
<<243,189,25,98,170,97,88,90,174,178,162,19,249,141,94,60>>,
<<237,85,6,153,218,60,23,104,162,112,65,69,148,90,15,240>>,
<<225,48,238,193,120,43,124,63,156,207,11,4,254,96,250,204>>,
<<67,254,107,82,106,87,36,119,140,78,216,142,66,225,8,40>>,
<<185,246,227,162,211,133,212,10,174,21,204,75,128,125,
200,...>>,
<<234,191,210,59,62,148,130,187,60,0,187,124,150,213,...>>,
<<199,231,45,34,185,9,231,162,187,130,134,246,54,...>>,
<<157,226,127,87,191,151,81,50,19,116,96,121,...>>,
<<15,59,143,114,184,207,96,164,155,44,238,...>>,
<<176,139,190,30,114,248,0,144,201,14,...>>,
<<169,79,218,157,20,10,20,146,12,...>>,
<<131,25,76,110,14,183,5,103,...>>,
<<91,197,189,2,48,142,67,...>>,
<<94,202,72,164,129,237,...>>,
<<"^NQÙ¡8hÿèkàå"...>>,<<"ðÙ.Q"...>>,
<<150,101,76,...>>,
<<"A^ÏrÔ"...>>,<<"¹"...>>,<<...>>|...]
4>

Running join on Maybe Relation

I have a model
Assignment
blah Text
....
and a model
File
assignmentId AssignmentId Maybe
...
and I want to get all the files associated with an assignment in a join query. I have tried Esqueleto and runJoin with selectOneMany but haven't had any luck, so I am considering not using a join, or using rawSql. That really doesn't seem like a good idea, but I can't figure this out. Is there any support for that feature?
Update, working example:
{-# LANGUAGE PackageImports, OverloadedStrings, ConstraintKinds #-}
module Handler.HTest where
import Import
import "esqueleto" Database.Esqueleto as Esql
import "monad-logger" Control.Monad.Logger (MonadLogger)
import "resourcet" Control.Monad.Trans.Resource (MonadResourceBase)
import qualified Data.List as L
getFilesByAssignment :: (PersistQuery (SqlPersist m), MonadLogger m
, MonadResourceBase m) =>
Text -> SqlPersist m [Entity File]
getFilesByAssignment myAssign = do
result <- select $
from $ \(assign `InnerJoin` file) -> do
on (just (assign ^. AssignmentId)
Esql.==. file ^. FileAssignmentId)
where_ (assign ^. AssignmentBlah Esql.==. val myAssign)
return (assign, file)
return $ map snd (result :: [(Entity Assignment, Entity File)])
(.$) = flip ($)
getTestR :: Handler RepHtml
getTestR = do
entFiles <- runDB $ getFilesByAssignment "test"
defaultLayout $ do
setTitle "Test page"
entFiles .$ map (show . unKey . entityKey)
.$ L.intercalate ", "
.$ toHtml
.$ toWidget

TypeError: invalid file: When trying to make a file name a variable

Hi I am trying to represent a file location as a variable because the finial script will be run on another machine. This is the code I have tried followed by the error I get. It seems to me that some how python is adding "\" and that is causing the problem. If that is the case how do I get it not to insert the "\"? Thank you
F = 'C:\Documents and Settings\myfile.txt','r'
f = open(F)
and the error
TypeError: invalid file: ('C:\\Documents and Settings\\myfile.txt', 'r')
From the docs:
http://docs.python.org/tutorial/inputoutput.html#reading-and-writing-files
Try this:
F = r'C:\Documents and Settings\myfile.txt'
f = open(F, 'r')
About the "double backslashes" - you need to escape backslashes in your strings or use r'string', see this:
http://docs.python.org/release/2.5.2/ref/strings.html
E.g. try this:
>>> a = 'a\nb'
>>> print a
a
b
To get what you expect, you need this:
>>> a = r'a\nb'
>>> print a
a\nb
or this:
>>> a = 'a\\nb'
>>> print a
a\nb
Try
f=open('C:\Documents and Settings\myfile.txt','r')
Instead of using the variable F. the way you have it 'r' is part of the file name, which it is not.
Instead of writing / or \, you should do this:
import os
F = os.path.join(
"C:",
os.path.join(
"Documents and Settings", "myfile.txt"
)
)
f = open(F, 'r')`
so that it uses / or \ according to your os.
(Although if you write C:/ it must mean you want to run your code on Windows... Hum...)

Compact C Folding in Vim

I'm trying to make a simple Vim script that would create very compact top-level folds for c files. Ideally, if it was run on this code:
static void funca(...)
{
...
}
/* Example comment */
static void funcb(...)
{
...
}
Then it would create folds which would look like this when closed:
+-- x Lines: static void funca(...)----------------------
+-- x Lines: static void funcb(...)----------------------
So basically it would be like foldmethod=syntax with foldlevel=1, except that each fold would start one line further up, and would extend further down to include all following blank lines.
I know how to make one of these folds (assuming foldmethod=manual):
/^{<cr>kVnn?^$<cr>zf
But I'm not sure how to put it into a function. This is my effort:
function Cfold()
set foldmethod=manual " Manual folds
ggzE " Delete all folds
while (/^{<cr>) " Somehow loop through each match
kVnn?^$<cr>zf " This would work fine except for the last function
endwhile
endfunction
map <Leader>f :call Cfold()<cr>
But it isn't valid, I'm not entirely sure how functions work. Also, it won't work for the last function in the file, since it won't find '^{' again. If someone could help me get this working, and somehow add a case for the last function in a file, I would be extremely grateful.
Thanks in advance :)
You can create folds programmatically using the foldexpr and foldtext. Try this, though you may have to tweak CFoldLevel so it doesn't swallow non-function parts of the code:
function! CFoldLevel(lnum)
let line = getline(a:lnum)
if line =~ '^/\*'
return '>1' " A new fold of level 1 starts here.
else
return '1' " This line has a foldlevel of 1.
endif
endfunction
function! CFoldText()
" Look through all of the folded text for the function signature.
let signature = ''
let i = v:foldstart
while signature == '' && i < v:foldend
let line = getline(i)
if line =~ '\w\+(.*)$'
let signature = line
endif
let i = i + 1
endwhile
" Return what the fold should show when folded.
return '+-- ' . (v:foldend - v:foldstart) . ' Lines: ' . signature . ' '
endfunction
function! CFold()
set foldenable
set foldlevel=0
set foldmethod=expr
set foldexpr=CFoldLevel(v:lnum)
set foldtext=CFoldText()
set foldnestmax=1
endfunction
See :help 'foldexpr' for more details.

Resources