I would like to execute a command that takes a specific file in the project (building it as necessary) and sends it somewhere externally. For example, it may be a command that uploads a web page, or sends an e-mail. It may even write some additional files, such as a log, but that is not the point of calling it.
In other words, this action is evoked by naming its source, rather than the target — either because there is no tangible target, or it is insignificant and the action is primarily wanted for its side effect.
I see it that an extra command line argument will have to be provided, like this:
% BuildSystem send pizza.box
The command above should be equivalent to the following:
% BuildSystem pizza.box
% send pizza.box
Can (and "should") this be performed with the shake
build system?
P.S. As Daniel suggests in an answer, I can extend shake
's argument parser. But I am not sure if this is the best practice for a case like this. It seems a little at odds with the way shake
behaves, treating every single command line argument as a self-contained goal. It is also a whole new logic for the operator to design, so much overhead for such a menial task.
It might be more intuitive to request a receipt
file for each box
that is sent. For instance:
% BuildSystem pizza.receipt
— would then be equivalent to:
% BuildSystem pizza.box
% send pizza.box >pizza.receipt
On the downside, as I understand from an official answer to a question nearby,we cannot have a pseudo-target like pizza.send
that does not actually result in a file pizza.send
being created. So I am not sure, again, if this is the right way.
P.S. 2 It would be even better if we could replace the default "file exists" success verifier with a custom code. For instance, instead of verifying that a file pizza.receipt
(that we otherwise have no need for) was indeed created, we may telephone the customer and ask them if they enjoyed the lunch. If we can arrange that, we can then invoke the corresponding rule with a "pseudo-file" target pizza.send
. In general, build artifacts need not reside on the local file system at all, insofar as the code that can verify and retrieve them is given.
The answer depends on whether you want to send the email once, or repeatedly, even if pizza.box
doesn't change. In both cases let's imagine you want to write BuildSystem send.pizza.box
to cause the email to be sent.
Send every time
If you want to send a copy of pizza.box
every time you can use a phony
rule:
phony "send.pizza.box" $ do
need ["pizza.box"]
cmd_ "send-email" "pizza.box"
If you want that to work for all files, you can generalise to:
phonys $ \s -> case stripPrefix "send." s of
Nothing -> Nothing
Just file -> Just $ do
need [file]
cmd_ "send-email" [file]
Send once
If you only want one copy of each changed pizza.box
to be sent then you need to record evidence of that locally, to stop sending successive copies. The easiest way to do that is actually create a file send.pizza.box
:
"send.*" %> \out -> do
let src = drop 5 out
need [src]
cmd_ "send-email" [src]
writeFile' out ""
If you strongly want to avoid writing the send.pizza.box
file you can use the phony
technique from above combined with addOracle
(but it's unlikely to be worth the additional hassle).