0

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.

Ignat Insarov
  • 4,660
  • 18
  • 37
  • You can write whatever rules you want for Shake, replacing the success verifier with whatever suits you. See https://hackage.haskell.org/package/shake-0.17.8/docs/Development-Shake-Rule.html – Neil Mitchell May 01 '19 at 10:07

2 Answers2

1

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).

Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85
0

Yes, shake supports this via phony.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • I get it that I can send a single hard-coded file, but I'm not sure how to select a file with a command line argument. – Ignat Insarov Apr 30 '19 at 19:45
  • @IgnatInsarov I guess that's a fairly orthogonal question, no? Use whatever command-line parsing library you like, then `want` or `need` the appropriate thing. – Daniel Wagner Apr 30 '19 at 19:50
  • I considered that `shake` deals with the command line arguments in its own way. I use it as `main = shakeArgs shakeOptions $ do stuff`. I thought maybe there is some functionality out of the box to handle a case like I described. Or some sort of best practice. – Ignat Insarov Apr 30 '19 at 19:58
  • @IgnatInsarov `shakeArgsWith` lets you plug your own stuff into shake's command-line parsing; or `shakeOptDescrs` lets you plug shake's command-line stuff into your own parser. – Daniel Wagner Apr 30 '19 at 21:03
  • Maybe you can move this advice into the body of your answer? In order for it to obtain permanence. – Ignat Insarov Apr 30 '19 at 22:15
  • @IgnatInsarov You're asking a separate question. If you want to ask and answer that, do it as a separate question. – Cubic May 01 '19 at 13:17