1 /**
2  * Copyright: Copyright Jason White, 2016
3  * License:   MIT
4  * Authors:   Jason White
5  *
6  * Description:
7  * Command to delete outputs.
8  */
9 module button.cli.clean;
10 
11 import button.cli.options : CleanOptions, GlobalOptions;
12 
13 import io.text, io.file.stdio;
14 
15 import button.state,
16        button.rule,
17        button.graph,
18        button.build,
19        button.textcolor;
20 
21 /**
22  * Deletes outputs.
23  */
24 int cleanCommand(CleanOptions opts, GlobalOptions globalOpts)
25 {
26     import std.getopt;
27     import std.file : remove;
28 
29     immutable color = TextColor(colorOutput(opts.color));
30 
31     try
32     {
33         string path = buildDescriptionPath(opts.path);
34         string statePath = path.stateName;
35 
36         auto state = new BuildState(statePath);
37 
38         {
39             state.begin();
40             scope (success)
41             {
42                 if (opts.dryRun)
43                     state.rollback();
44                 else
45                     state.commit();
46             }
47 
48             scope (failure)
49                 state.rollback();
50 
51             clean(state, opts.dryRun);
52         }
53 
54         // Close the database before (potentially) deleting it.
55         state.close();
56 
57         if (opts.purge)
58         {
59             println("Deleting `", statePath, "`");
60             remove(statePath);
61         }
62     }
63     catch (BuildException e)
64     {
65         stderr.println(color.status, ":: ", color.error,
66                 "Error", color.reset, ": ", e.msg);
67         return 1;
68     }
69 
70     return 0;
71 }
72 
73 /**
74  * Deletes all outputs from the file system.
75  */
76 void clean(BuildState state, bool dryRun)
77 {
78     import io.text, io.file.stdio;
79     import std.range : takeOne;
80     import button.resource : Resource;
81 
82     foreach (id; state.enumerate!(Index!Resource))
83     {
84         if (state.degreeIn(id) > 0)
85         {
86             auto r = state[id];
87 
88             println("Deleting `", r, "`");
89 
90             r.remove(dryRun);
91 
92             // Update the database with the new status of the resource.
93             state[id] = r;
94 
95             // We want to build this the next time around, so mark its task as
96             // pending.
97             auto incoming = state
98                 .incoming!(NeighborIndex!(Index!Resource))(id)
99                 .takeOne;
100             assert(incoming.length == 1,
101                     "Output resource has does not have 1 incoming edge! "~
102                     "Something has gone horribly wrong!");
103             state.addPending(incoming[0].vertex);
104         }
105     }
106 }