{"action":"created","issue":{"url":"https://api.github.com/repos/pydoit/doit/issues/10","labels_url":"https://api.github.com/repos/pydoit/doit/issues/10/labels{/name}","comments_url":"https://api.github.com/repos/pydoit/doit/issues/10/comments","events_url":"https://api.github.com/repos/pydoit/doit/issues/10/events","html_url":"https://github.com/pydoit/doit/pull/10","id":47509244,"number":10,"title":"Feature dry run","user":{"login":"OliverTED","id":7994555,"avatar_url":"https://avatars.githubusercontent.com/u/7994555?v=3","gravatar_id":"","url":"https://api.github.com/users/OliverTED","html_url":"https://github.com/OliverTED","followers_url":"https://api.github.com/users/OliverTED/followers","following_url":"https://api.github.com/users/OliverTED/following{/other_user}","gists_url":"https://api.github.com/users/OliverTED/gists{/gist_id}","starred_url":"https://api.github.com/users/OliverTED/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/OliverTED/subscriptions","organizations_url":"https://api.github.com/users/OliverTED/orgs","repos_url":"https://api.github.com/users/OliverTED/repos","events_url":"https://api.github.com/users/OliverTED/events{/privacy}","received_events_url":"https://api.github.com/users/OliverTED/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/pydoit/doit/labels/stage-development","name":"stage-development","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":18,"created_at":"2014-11-01T16:02:04Z","updated_at":"2015-02-03T03:05:34Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/pydoit/doit/pulls/10","html_url":"https://github.com/pydoit/doit/pull/10","diff_url":"https://github.com/pydoit/doit/pull/10.diff","patch_url":"https://github.com/pydoit/doit/pull/10.patch"},"body":"Hello,\r\n\r\n-------------------\r\nThis patch adds an option --dry-run to the run command.\r\n\r\nIn this mode changes to the database are prevented by a thin\r\nlayer around the the database object. Task action and teardown\r\nexecution is skipped.\r\n-------------------\r\n\r\nI did not test it thoroughly, its my first contribution :-). I did not add tests for the new code. Do you think this can be pulled ? Or what do you require for it being pulled ?\r\n\r\n\r\nThanks for your efforts,\r\nOliver"},"comment":{"url":"https://api.github.com/repos/pydoit/doit/issues/comments/72584495","html_url":"https://github.com/pydoit/doit/pull/10#issuecomment-72584495","issue_url":"https://api.github.com/repos/pydoit/doit/issues/10","id":72584495,"user":{"login":"schettino72","id":138474,"avatar_url":"https://avatars.githubusercontent.com/u/138474?v=3","gravatar_id":"","url":"https://api.github.com/users/schettino72","html_url":"https://github.com/schettino72","followers_url":"https://api.github.com/users/schettino72/followers","following_url":"https://api.github.com/users/schettino72/following{/other_user}","gists_url":"https://api.github.com/users/schettino72/gists{/gist_id}","starred_url":"https://api.github.com/users/schettino72/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/schettino72/subscriptions","organizations_url":"https://api.github.com/users/schettino72/orgs","repos_url":"https://api.github.com/users/schettino72/repos","events_url":"https://api.github.com/users/schettino72/events{/privacy}","received_events_url":"https://api.github.com/users/schettino72/received_events","type":"User","site_admin":false},"created_at":"2015-02-03T03:05:34Z","updated_at":"2015-02-03T03:05:34Z","body":"> Generally I thought that any rule that could be called should be printed on dry run. (Do you agree on this principle?). Then automatically you have the equivalence of --continue and --dry-run (or am I mistaken). Because --continue should not build anything that eventually changes by a successful run of failed rules.\r\n\r\nYou are using `make` terminology :) it does not exactly map to `doit` concepts so I am bit confused by what you mean.  I would say:\r\n\r\n`--continue` should not ~~build~~ try to execute anything that ~~eventually changes by a successful run of~~ depends on failed tasks ~~rules~~.\r\n\r\nFor my last [task_dep example](https://gist.github.com/schettino72/9a798a73189567d136cd#task_dep--uptodate) I included the sequence of commands to test it. The expected behaviour on the table refers to last invocation of `doit`. It is a poor example because I set `uptodate:True` it should be something that would fail if `t1` is executed again... It would be better example if it had a `result_dep` and `t1` would change it is returned value on every execution.\r\n\r\nIf we agree with the expected behaviour we can move to the implementation.\r\n\r\n### doit internals\r\n\r\n`doit` execution basically has three components:\r\n  - control.py controls the execution order of the tasks\r\n  - dependency.py checks if a task is up-to-date or not\r\n  - runner.py get tasks from control.py, check if need to be executed using dependency.py and finally executes task's actions.\r\n\r\ndependency.py has absolutely NO knowledge about relation between tasks or the order they should be executed. It always deals only with a single task.\r\n\r\ncontrol.py during its initialization will check for `file_dep` of all tasks that are a `target` from another one. For those it will implicitly create a `task_dep`. After this point control.py doesn't care at all about `file_dep` or `targets`.\r\n\r\n`doit` is general purpose tool and not strictly file-based as `make`. But since files based operations is so common doit has some built-in support for it by translating these file relations between tasks into the more general principle of `task_dep` that is used to build the task tree.\r\n\r\n### dry-run implementation\r\n\r\ndepenendency.py: I am now wonder if `dependency.py` should not be modified at all. At most it should contain only the modifications up to here (https://github.com/pydoit/doit/compare/feature-dry-run). The other option would be to modify `runner.py` to not call any operations that modify the DB.\r\n\r\nThe problem of your implementation is that you make changes on dependency.py so it will only be able to handle file dependencies. Handling things on control.py will allow you handle the more general case of `task_dep`. \r\n\r\nNote that since `doit` already has support --continue some machinery on how to deal with propagation of successful/unsuccessful status of task is already present. \r\n\r\nSo for dry-run I guess that we could say that if task has the status `run` you could imply that all tasks that depends on it will also need to be `run` without even checking if it is up-to-date by checking its `file_dep`s. This way `file_dep` that doesnt exist but are supposed to be created by other tasks will not raise error because the up-to-date check (`[runner]self.dep_manager.get_status()`) should not event be called ...\r\n\r\nps:\r\n\r\n* all this things were not clear to me also, just now after looking at your implementation and thinking about use-cases it became clear. sorry it took some time of you going in the wrong direction for me to realize that.\r\n\r\n* no worries about working on it just occasionally, take your time. "}}