1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1994-1999, 2001-2008, 2011, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/ac/assert.h>
20 #include <common/ac/stdio.h>
21 
22 #include <common/gettime.h>
23 #include <common/progname.h>
24 #include <common/quit.h>
25 #include <common/sizeof.h>
26 #include <common/trace.h>
27 #include <libaegis/ael/project/history.h>
28 #include <libaegis/arglex2.h>
29 #include <libaegis/arglex/change.h>
30 #include <libaegis/arglex/project.h>
31 #include <libaegis/change/file.h>
32 #include <libaegis/change/identifier.h>
33 #include <libaegis/commit.h>
34 #include <libaegis/file/event.h>
35 #include <libaegis/help.h>
36 #include <libaegis/lock.h>
37 #include <libaegis/pconf.fmtgen.h>
38 #include <libaegis/project/file.h>
39 #include <libaegis/project/file/roll_forward.h>
40 #include <libaegis/project.h>
41 #include <libaegis/project/history.h>
42 #include <libaegis/sub.h>
43 #include <libaegis/user.h>
44 #include <libaegis/zero.h>
45 
46 #include <aegis/aedn.h>
47 
48 
49 static void
delta_name_usage(void)50 delta_name_usage(void)
51 {
52     const char      *progname;
53 
54     progname = progname_get();
55     fprintf
56     (
57         stderr,
58         "usage: %s -Delta_Name [ <option>... ][ <delta_number> ] <string>...\n",
59         progname
60     );
61     fprintf(stderr, "       %s -Delta_Name -List [ <option>... ]\n", progname);
62     fprintf(stderr, "       %s -Delta_Name -Help\n", progname);
63     quit(1);
64 }
65 
66 
67 static void
delta_name_help(void)68 delta_name_help(void)
69 {
70     help("aedn", delta_name_usage);
71 }
72 
73 
74 static void
delta_name_list(void)75 delta_name_list(void)
76 {
77     trace(("delta_name_list()\n{\n"));
78     arglex();
79     change_identifier cid;
80     cid.command_line_parse_rest(delta_name_usage);
81     list_project_history(cid, 0);
82     trace(("}\n"));
83 }
84 
85 
86 static void
delta_name_main(void)87 delta_name_main(void)
88 {
89     trace(("delta_name_main()\n{\n"));
90     arglex();
91     bool stomp = false;
92     change_identifier cid;
93     nstring new_name;
94     while (arglex_token != arglex_token_eoln)
95     {
96         switch (arglex_token)
97         {
98         default:
99             generic_argument(delta_name_usage);
100             continue;
101 
102         case arglex_token_overwriting:
103             if (stomp)
104                 duplicate_option(delta_name_usage);
105             stomp = true;
106             break;
107 
108         case arglex_token_string:
109             if (!new_name.empty())
110             {
111                 error_intl(0, i18n("too many delta names"));
112                 delta_name_usage();
113             }
114             new_name = arglex_value.alv_string;
115             break;
116 
117         case arglex_token_delta:
118         case arglex_token_number:
119         case arglex_token_change:
120         case arglex_token_delta_from_change:
121         case arglex_token_delta_date:
122         case arglex_token_project:
123             cid.command_line_parse(delta_name_usage);
124             continue;
125 
126         case arglex_token_wait:
127         case arglex_token_wait_not:
128             user_ty::lock_wait_argument(delta_name_usage);
129             break;
130         }
131         arglex();
132     }
133     cid.command_line_check(delta_name_usage);
134     if (new_name.empty())
135     {
136         error_intl(0, i18n("no delta name"));
137         delta_name_usage();
138     }
139 
140     //
141     // If the user did not nominate a specific change set, then we take
142     // the head of the branch (most recent integration) as the change
143     // the label is to be attached to.
144     //
145     if (!cid.set())
146         cid.set_delta_from_branch_head();
147 
148     //
149     // lock the project file
150     //
151     cid.get_pp()->pstate_lock_prepare();
152     lock_take();
153 
154     //
155     // it is an error if the user is not a project administrator
156     //
157     if (!project_administrator_query(cid.get_pp(), cid.get_up()->name()))
158         project_fatal(cid.get_pp(), 0, i18n("not an administrator"));
159 
160     //
161     // find the delta number
162     //
163     long delta_number = cid.get_cp()->delta_number_get();
164     if (delta_number <= 0)
165     {
166         change_fatal(cid.get_cp(), 0, i18n("aedn bad state"));
167     }
168 
169     //
170     // Make sure the name has not been used already.
171     //
172     if (!stomp)
173     {
174         long other =
175             project_history_delta_by_name(cid.get_pp(), new_name.get_ref(), 1);
176         if (other && other != delta_number)
177         {
178             sub_context_ty sc;
179             sc.var_set_string("Name", new_name);
180             sc.var_set_long("Number", delta_number);
181             sc.var_optional("Number");
182             sc.var_set_long("Other", other);
183             sc.var_optional("Other");
184             project_fatal(cid.get_pp(), &sc, i18n("delta $name in use"));
185             // NOTREACHED
186         }
187     }
188     project_history_delta_name_delete(cid.get_pp(), new_name.get_ref());
189 
190     //
191     // add the name to the selected history entry
192     //
193     project_history_delta_name_add
194     (
195         cid.get_pp(),
196         delta_number,
197         new_name.get_ref()
198     );
199 
200     //
201     // If the history label command is defined,
202     // label each of the project files.
203     //
204     pconf_ty *pconf_data = project_pconf_get(cid.get_pp());
205     if (pconf_data->history_label_command)
206     {
207         time_t delta_date =
208             project_history_delta_to_timestamp(cid.get_pp(), delta_number);
209         project_file_roll_forward historian(cid.get_pp(), delta_date, 0);
210         for (size_t j = 0;; j++)
211         {
212             fstate_src_ty *src = cid.get_pp()->file_nth(j, view_path_simple);
213             if (!src)
214                 break;
215             file_event *fep = historian.get_last(src->file_name);
216             if (!fep)
217             {
218                 //
219                 // File not yet created at this delta.
220                 //
221                 continue;
222             }
223             src = fep->get_src();
224             assert(src);
225             switch (src->action)
226             {
227             case file_action_remove:
228                 //
229                 // File removed before this delta.
230                 //
231                 continue;
232 
233             case file_action_create:
234             case file_action_modify:
235             case file_action_insulate:
236             case file_action_transparent:
237                 break;
238             }
239 
240             //
241             // Label everything else.
242             //
243             change_run_history_label_command
244             (
245                 fep->get_change(),
246                 src,
247                 new_name.get_ref()
248             );
249         }
250     }
251 
252     //
253     // release the locks
254     //
255     cid.get_pp()->pstate_write();
256     commit();
257     lock_release();
258 
259     //
260     // verbose success message
261     //
262     {
263         sub_context_ty sc;
264         sc.var_set_string("Name", new_name);
265         sc.var_optional("Name");
266         sc.var_set_long("Number", delta_number);
267         sc.var_optional("Number");
268         project_verbose(cid.get_pp(), &sc, i18n("delta name complete"));
269     }
270     trace(("}\n"));
271 }
272 
273 
274 void
delta_name_assignment(void)275 delta_name_assignment(void)
276 {
277     static arglex_dispatch_ty dispatch[] =
278     {
279         { arglex_token_help, delta_name_help, 0 },
280         { arglex_token_list, delta_name_list, 0 },
281     };
282 
283     trace(("delta_name_assignment()\n{\n"));
284     arglex_dispatch(dispatch, SIZEOF(dispatch), delta_name_main);
285     trace(("}\n"));
286 }
287 
288 
289 // vim: set ts=8 sw=4 et :
290