Repository navigation
Rake -n does not mark dependents for Execution #92
Description
Activity
Even though it knows it must update both fileB and fileC
fileCtask should only be executed iffileBchanged. So how can rake know thatfileBis going to change without actually executingfileBtask (given it's a dry-run)?I think rake cannot know if fileB is going to have it's file timestamp updated or not, that depends on what the actual
fileBfile task does in the block implementation, which is never executed in a dry-run.So at most, rake can say something like
** Execute (dry run) fileB ** May execute (dry run) fileCOr maybe i am missing something.
- added 5 commits that reference this issue
on Feb 7, 2018 I think I've always assumed that if the code for building
fileBdoes not change its timestamp (so as to be more recent thanfileC), then rake would assume that there was an error and fail loudly.If this check was in place, then it wouldn't be a problem for the dry-run to print this:
** Execute (dry run) fileB ** Execute (dry run) fileCbecause the semantics would be the following: "
fileCwill be run as long as there is no problem when buildingfileB". This is already true if thefileBtask raises an exception (in which case thefileCtask will not be executed).In fact, whenever there is more than one line such as
** Execute (dry run) <something>in the dry-run output, we can never be sure if all of them will be executed. If any task fails with an exception, rake correctly stops all following executions, even the ones that are completely unrelated to it. There is always the implicit assumption ofMay executefor all but the first occurrence ofExecute.But then, all of this would require rake to actually fail on error (instead of failing silently) when its
filetasks fail to update the timestamp from the dependent to a value that is more recent than the one of the target. Would this be feasible to implement? Maybe there's a downside I'm not seeing?Hi Silvio, thanks for responding.
I think I've always assumed that if the code for building
fileBdoes not change its timestamp (so as to be more recent thanfileC), then rake would assume that there was an error and fail loudly.Whether rake should or should not raise an error if the file task doesn't update the file as part of the file task execution seems like an interesting but separate discussion to me.
Back to the original issue about
dry-runs, it seems like, as of today, rake doesn't assume anything about whatfileBtask does when it's executed. User is free to implement it in any way it likes. rake is agnostic about that. So that means, as per the actual situation, the dry-run cannot assumefileCis going to be executed, just based on the fact thatfileBfile task is going to be executed, right?Well, whenever there are two tasks marked for execution, we can never know if the second one will ever execute. Even if we run
$ rake fileB fileCwe are not guaranteed that thefileCtask will be executed (it won't iffileBfails with an exception). But still,rake -nwill show both as marked for execution, because under normal circumstances, both should be executed. So I agree that we cannot assume thatfileCwill be executed, but I will say this assumption is always true whenever we have more than 1 task marked for execution.The reason why mentioned my assumption of rake raising an error is that any other solution would require silent failure (I think). For example, if
fileBdoes not update the timestamp then either:
a) Rake will try to buildfileCanyway (silently ignore the fact thatfileBfailed). I think nobody wants this option.
b) Rake will silently skip the targetfileC, and users will think that the build worked even though it didn't.
c) Rake will fail with an error saying thatfileBwas built with a timestamp that is older than the one infileC.If we go for option (c), then I don't see any problem in saying both
** Execute fileBand** Execute fileC, because under normal circumstances both will be executed. And under exceptional circumstances, rake will stop on the first error, regardless of whether the error occurred insidefileBor it was an error in the timestamp offileB.Maybe there's an option (d) that I'm missing? Or maybe options (a) or (b) are better than I think?
Side note:
[...] as of today, rake doesn't assume anything about what fileB task does when it's executed. User is free to implement it in any way it likes. rake is agnostic about that.
Actually, I think rake does assume that file tasks update the timestamps. That's why it will not run
fileBif it thinks the timestamp is already fine. Basically, the main assumption rake makes aboutfiletasks would be that they update the timestamp for the given file. Timestamps are important for rake, which is also why it will not runfileCif the timestamp offileBis not updated, in options (b) and (c) above.(it won't if fileB fails with an exception)
Keep in mind
fileCwon't run also iffileBfile task has a conditional implementation, and the condition returnsfalse. E.g.file "fileB" => %W[fileA] do |t| if something_happens? sh %Q[touch #{t.name}] end end
Implementation of the task, including the update of the file timestamp it's up to the user, plus rake doesn't assume anything about the implementation of the task as of now.
So I agree that we cannot assume that fileC will be executed
Cool, we agree on that 👍
So if we cannot assume that
fileCwill be executed, wouldn't be misleading to include** Execute (dry run) fileCin the output of the dry-run?
rake doesn't assume anything about the implementation of the task as of now
Rake does assume that file tasks update the timestamps. That's why it will not run
fileBif it thinks the timestamp is already fine. This is the main assumption behind Makefiles, and is the expected behavior of thefilemethod. If thefilemethod were not supposed to be used for timestamp-related tasks, then I would say that the current documentation on rake is very misleading. But I think we can agree that the point offileis to represent a file-building task that relies on timestamps. That's an assumption that's made by bothmakeand rake'sfilemethod.So if we cannot assume that fileC will be executed, wouldn't be misleading to include
** Execute (dry run) fileC
in the output of the dry-run?Whenever there are two tasks marked for execution, we can never know if the second one will ever execute. Even if we run
$ rake fileB fileCwe are not guaranteed that thefileCtask will be executed (it won't iffileBfails with an exception). But still,rake -nwill show both as marked for execution, because under normal circumstances, both should be executed.Should
rake -nbe modified so as to never ever show more than one line containingExecute, so as to avoid a literal interpretation that thisExecutenecessarily means that this taks will be executed no matter what? I wouldn't say so. I'd say it's implicit that any failure in the chain will stop the execution of further tasks, so it's a bug if rake currently does not show everything that will be executed. This bug makesrake -nextremely misleading (we cannot rely on it to know what tasks will actually be called), and prevents any scripting of its output to predict what tasks will actually be executed."
rake -nshows everything that will be executed when required." defines the behavior for me. Maybe the documentation needs to be more specific for file tasks to help beginners which never usedmakeor similar before…
I have a Rakefile with these file tasks:
I perform this setup, where everything is built and then the first file in the chain (
fileA) is updated:And now
rake -ntells me that onlyfileBneeds to be updated...Even though it knows it must update both
fileBandfileC:I expected
rake -nto tell me this:The problem seems to stem from the fact that the internal function
out_of_date?(infile_task.rb) does not take into account when a file should have updated its timestamp (but didn't, because this is a dry-run).