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