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