1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2004-2008 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
8 // (at 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
13 // GNU 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
17 // <http://www.gnu.org/licenses/>.
18 //
19 //
20 // ci
21 //
22 // Actually do a CVS ci command. This uses any previous Argument,
23 // Directory, Entry, or Modified requests, if they have been sent.
24 // The last Directory sent specifies the working directory at the time
25 // of the operation. No provision is made for any input from the user.
26 // This means that ci must use a -m argument if it wants to specify a
27 // log message.
28 //
29 // Response expected: yes.
30 // Root required: yes.
31 //
32 //
33 // Example
34 //
35 // After the user modifies the file and instructs the client to check
36 // it back in. The client sends arguments to specify the log message
37 // and file to check in:
38 //
39 // C: Argument -m
40 // C: Argument Well, you see, it took me hours and hours to find
41 // C: Argumentx this typo and I searched and searched and eventually
42 // C: Argumentx had to ask John for help.
43 // C: Argument mungeall.c
44 //
45 // It also sends information about the contents of the working directory,
46 // including the new contents of the modified file. Note that the user
47 // has changed into the "supermunger" directory before executing this
48 // command; the top level directory is a user-visible concept because
49 // the server should print filenames in M and E responses relative to
50 // that directory.
51 //
52 // (We are waving our hands about the order of the requests. "Directory"
53 // and "Argument" can be in any order, but this probably isn't specified
54 // very well.)
55 //
56 // C: Directory .
57 // C: /u/cvsroot/supermunger
58 // C: Entry /mungeall.c/1.1///
59 // C: Modified mungeall.c
60 // C: u=rw,g=r,o=r
61 // C: 26
62 // C: int main () { abort (); }
63 //
64 // And finally, the client issues the checkin command (which makes use
65 // of the data just sent):
66 //
67 // C: ci
68 //
69 // And the server tells the client that the checkin succeeded:
70 //
71 // S: M Checking in mungeall.c;
72 // S: E /u/cvsroot/supermunger/mungeall.c,v <-- mungeall.c
73 // S: E new revision: 1.2; previous revision: 1.1
74 // S: E done
75 // S: Mode u=rw,g=r,o=r
76 // S: Checked-in ./
77 // S: /u/cvsroot/supermunger/mungeall.c
78 // S: /mungeall.c/1.2///
79 // S: ok
80 //
81 //
82 // Reverse Engineering Notes:
83 //
84 // First comes the command line arguments from the client.
85 // The following options are known to be transmitted by the client:
86 // -m <text> As two Argument requests, plus optional Argumentx
87 //
88 // Then follows a series of Directory/Entry/Modified requests for
89 // all the files which have changed in some way.
90 //
91 // Then comes a Directory request, specifying what the
92 // remaining arguments are relative to.
93 //
94 // Then a series of Argument requests, listing all of the files to be
95 // committed. Conceivably this list could differ from the implicit
96 // list you can derived from the Modified requests, because the -f
97 // ("force") flag on the client side can be used to commit files
98 // which have not been modified.
99 //
100 // Last, they send the "ci" request.
101 //
102 // The ugly part is that they could send more than one change at
103 // a time! CVS is more than happy to commit more than one module
104 // at once.
105 //
106
107 #include <common/ac/string.h>
108
109 #include <aecvsserver/module.h>
110 #include <libaegis/os.h>
111 #include <aecvsserver/request/ci.h>
112 #include <aecvsserver/server.h>
113
114
~request_checkin()115 request_checkin::~request_checkin()
116 {
117 }
118
119
request_checkin()120 request_checkin::request_checkin()
121 {
122 }
123
124
125 void
run_inner(server_ty * sp,string_ty *) const126 request_checkin::run_inner(server_ty *sp, string_ty *)
127 const
128 {
129 size_t j;
130 directory_ty *dp;
131 int ok;
132
133 if (server_root_required(sp, "ci"))
134 return;
135 if (server_directory_required(sp, "ci"))
136 return;
137
138 //
139 // Skip the options.
140 //
141 for (j = 0; j < sp->np->argument_count(); ++j)
142 {
143 string_ty *arg = sp->np->argument_nth(j);
144 if (arg->str_text[0] != '-')
145 break;
146 if (0 == strcmp(arg->str_text, "--"))
147 {
148 ++j;
149 break;
150 }
151 if (arg->str_text[1] == 'm')
152 ++j;
153 }
154
155 ok = 1;
156 dp = sp->np->get_curdir();
157 for (; j < sp->np->argument_count(); ++j)
158 {
159 string_ty *arg;
160 string_ty *client_side;
161 string_ty *server_side;
162
163 //
164 // Build the (more complete) name of the file on both the client
165 // side and the server side.
166 //
167 arg = sp->np->argument_nth(j);
168 client_side = os_path_cat(dp->client_side, arg);
169 server_side = os_path_cat(dp->server_side, arg);
170
171 //
172 // Pass the checkin to the relevant module, one file at a time.
173 //
174 // The CVS client is able to commit files to more than one module
175 // in a single command. This means we have to lookup the module
176 // for every file.
177 //
178 module mp = module::find_trim(server_side);
179 if (!mp->checkin(sp, client_side, server_side))
180 ok = 0;
181 str_free(client_side);
182 str_free(server_side);
183 if (!ok)
184 break;
185 }
186
187 if (ok)
188 {
189 server_m
190 (
191 sp,
192 "ci: now you have to use the \"aegis -develop-end\" command to "
193 "finish the job"
194 );
195 server_ok(sp);
196 }
197 }
198
199
200 const char *
name() const201 request_checkin::name()
202 const
203 {
204 return "ci";
205 }
206
207
208 bool
reset() const209 request_checkin::reset()
210 const
211 {
212 return true;
213 }
214