29 |
/* GNULIB headers. */ |
/* GNULIB headers. */ |
30 |
|
|
31 |
/* CVS headers. */ |
/* CVS headers. */ |
32 |
|
#include "difflib.h" |
33 |
#include "server.h" |
#include "server.h" |
34 |
#include "subr.h" |
#include "subr.h" |
35 |
#include "cvs.h" /* For CVSADM_BASE. */ |
#include "cvs.h" /* For CVSADM_BASE. */ |
249 |
int |
int |
250 |
base_checkout (RCSNode *rcs, struct file_info *finfo, |
base_checkout (RCSNode *rcs, struct file_info *finfo, |
251 |
const char *prev, const char *rev, const char *tag, |
const char *prev, const char *rev, const char *tag, |
252 |
const char *options, bool writable) |
const char *options) |
253 |
{ |
{ |
254 |
int status; |
int status; |
255 |
char *basefile; |
char *basefile; |
264 |
basefile = make_base_file_name (finfo->file, rev); |
basefile = make_base_file_name (finfo->file, rev); |
265 |
status = RCS_checkout (rcs, basefile, rev, tag, options, |
status = RCS_checkout (rcs, basefile, rev, tag, options, |
266 |
NULL, NULL, NULL); |
NULL, NULL, NULL); |
267 |
xchmod (basefile, writable); |
|
268 |
|
/* Always mark base files as read-only, to make disturbing them |
269 |
|
* accidentally at least slightly challenging. |
270 |
|
*/ |
271 |
|
xchmod (basefile, false); |
272 |
free (basefile); |
free (basefile); |
273 |
|
|
274 |
if (server_active && strcmp (cvs_cmd_name, "export")) |
if (server_active && strcmp (cvs_cmd_name, "export")) |
280 |
|
|
281 |
|
|
282 |
void |
void |
283 |
base_copy (struct file_info *finfo, const char *rev, const char *exists) |
base_copy (struct file_info *finfo, const char *rev, const char *flags) |
284 |
{ |
{ |
285 |
char *basefile; |
char *basefile; |
286 |
|
|
287 |
TRACE (TRACE_FUNCTION, "base_copy (%s, %s, %s)", |
TRACE (TRACE_FUNCTION, "base_copy (%s, %s, %s)", |
288 |
finfo->fullname, rev, exists); |
finfo->fullname, rev, flags); |
289 |
|
|
290 |
|
assert (flags && flags[0] && flags[1]); |
291 |
|
|
292 |
basefile = make_base_file_name (finfo->file, rev); |
basefile = make_base_file_name (finfo->file, rev); |
293 |
if (isfile (finfo->file)) |
if (isfile (finfo->file)) |
294 |
xchmod (finfo->file, true); |
xchmod (finfo->file, true); |
295 |
copy_file (basefile, finfo->file); |
copy_file (basefile, finfo->file); |
296 |
|
if (flags[1] == 'y') |
297 |
|
xchmod (finfo->file, true); |
298 |
free (basefile); |
free (basefile); |
299 |
|
|
300 |
if (server_active && strcmp (cvs_cmd_name, "export")) |
if (server_active && strcmp (cvs_cmd_name, "export")) |
301 |
server_base_copy (finfo, rev, exists); |
server_base_copy (finfo, rev, flags); |
302 |
} |
} |
303 |
|
|
304 |
|
|
314 |
error (0, errno, "Failed to remove `%s'", basefile); |
error (0, errno, "Failed to remove `%s'", basefile); |
315 |
free (basefile); |
free (basefile); |
316 |
} |
} |
317 |
|
|
318 |
|
|
319 |
|
|
320 |
|
/* Merge revisions REV1 and REV2. */ |
321 |
|
int |
322 |
|
base_merge (RCSNode *rcs, struct file_info *finfo, const char *options, |
323 |
|
const char *urev, const char *rev1, const char *rev2) |
324 |
|
{ |
325 |
|
char *f1, *f2; |
326 |
|
int retval; |
327 |
|
|
328 |
|
assert (!options || !options[0] |
329 |
|
|| (options[0] == '-' && options[1] == 'k')); |
330 |
|
|
331 |
|
/* Check out chosen revisions. The error message when RCS_checkout |
332 |
|
fails is not very informative -- it is taken verbatim from RCS 5.7, |
333 |
|
and relies on RCS_checkout saying something intelligent upon failure. */ |
334 |
|
|
335 |
|
if (base_checkout (rcs, finfo, urev, rev1, rev1, options)) |
336 |
|
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
337 |
|
rev1, finfo->fullname); |
338 |
|
|
339 |
|
if (base_checkout (rcs, finfo, urev, rev2, rev2, options)) |
340 |
|
error (1, 0, "checkout of revision %s of `%s' failed.\n", |
341 |
|
rev2, finfo->fullname); |
342 |
|
|
343 |
|
f1 = make_base_file_name (finfo->file, rev1); |
344 |
|
f2 = make_base_file_name (finfo->file, rev2); |
345 |
|
|
346 |
|
if (!server_active || !server_use_bases()) |
347 |
|
{ |
348 |
|
/* Merge changes. */ |
349 |
|
/* It may violate the current abstraction to fail to generate the same |
350 |
|
* files on the server as will be generated on the client, but I do not |
351 |
|
* believe that they are being used currently and it saves server CPU. |
352 |
|
*/ |
353 |
|
cvs_output ("Merging differences between revisions ", 0); |
354 |
|
cvs_output (rev1, 0); |
355 |
|
cvs_output (" and ", 5); |
356 |
|
cvs_output (rev2, 0); |
357 |
|
cvs_output (" into `", 7); |
358 |
|
if (!finfo->update_dir || !strcmp (finfo->update_dir, ".")) |
359 |
|
cvs_output (finfo->file, 0); |
360 |
|
else |
361 |
|
cvs_output (finfo->fullname, 0); |
362 |
|
cvs_output ("'\n", 2); |
363 |
|
|
364 |
|
retval = merge (finfo->file, f1, f2, rev1, rev2); |
365 |
|
} |
366 |
|
else |
367 |
|
retval = 0; |
368 |
|
|
369 |
|
if (server_active) |
370 |
|
server_base_merge (finfo, rev1, rev2); |
371 |
|
|
372 |
|
if (strcmp (urev, rev1) && unlink_file (f1) < 0) |
373 |
|
error (0, errno, "unable to remove `%s'", f1); |
374 |
|
if (strcmp (urev, rev2) && unlink_file (f2) < 0) |
375 |
|
error (0, errno, "unable to remove `%s'", f2); |
376 |
|
free (f1); |
377 |
|
free (f2); |
378 |
|
|
379 |
|
return retval; |
380 |
|
} |