2 * main.c: Subversion command line client.
4 * ====================================================================
5 * Copyright (c) 2000-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ==================================================================== */
28 #include <apr_strings.h>
29 #include <apr_tables.h>
30 #include <apr_general.h>
31 #include <apr_signal.h>
33 #include "svn_cmdline.h"
34 #include "svn_pools.h"
36 #include "svn_client.h"
37 #include "svn_config.h"
38 #include "svn_string.h"
40 #include "svn_delta.h"
42 #include "svn_error.h"
50 #include "svn_private_config.h"
53 /*** Option Processing ***/
55 /* Add an identifier here for long options that don't have a short
56 option. Options that have both long and short options should just
57 use the short option letter as identifier. */
59 opt_ancestor_path
= SVN_OPT_FIRST_LONGOPT_ID
,
100 opt_with_all_revprops
,
107 /* Option codes and descriptions for the command line client.
109 * The entire list must be terminated with an entry of nulls.
111 const apr_getopt_option_t svn_cl__options
[] =
113 {"force", opt_force
, 0, N_("force operation to run")},
114 {"force-log", opt_force_log
, 0,
115 N_("force validity of log message source")},
116 {"help", 'h', 0, N_("show help on a subcommand")},
117 {NULL
, '?', 0, N_("show help on a subcommand")},
118 {"message", 'm', 1, N_("specify log message ARG")},
119 {"quiet", 'q', 0, N_("print nothing, or only summary information")},
120 {"recursive", 'R', 0, N_("descend recursively, same as --depth=infinity")},
121 {"non-recursive", 'N', 0, N_("obsolete; try --depth=files or --depth=immediates")},
122 {"change", 'c', 1, N_
123 ("the change made by revision ARG (like -r ARG-1:ARG)\n"
124 " If ARG is negative this is like -r ARG:ARG-1")
126 {"revision", 'r', 1, N_
127 ("ARG (some commands also take ARG1:ARG2 range)\n"
128 " A revision argument can be one of:\n"
129 " NUMBER revision number\n"
130 " '{' DATE '}' revision at start of the date\n"
131 " 'HEAD' latest in repository\n"
132 " 'BASE' base rev of item's working copy\n"
133 " 'COMMITTED' last commit at or before BASE\n"
134 " 'PREV' revision just before COMMITTED")
135 /* spacing corresponds to svn_opt_format_option */
137 {"file", 'F', 1, N_("read log message from file ARG")},
138 {"incremental", opt_incremental
, 0,
139 N_("give output suitable for concatenation")},
141 {"encoding", opt_encoding
, 1,
142 N_("treat value as being in charset encoding ARG")},
144 {"version", opt_version
, 0, N_("show program version information")},
145 {"verbose", 'v', 0, N_("print extra information")},
146 {"show-updates", 'u', 0, N_("display update information")},
147 {"username", opt_auth_username
, 1, N_("specify a username ARG")},
148 {"password", opt_auth_password
, 1, N_("specify a password ARG")},
150 {"extensions", 'x', 1,
151 N_("Default: '-u'. When Subversion is invoking an\n"
153 " external diff program, ARG is simply passed along\n"
155 " to the program. But when Subversion is using its\n"
157 " default internal diff implementation, or when\n"
159 " Subversion is displaying blame annotations, ARG\n"
161 " could be any of the following:\n"
165 " Output 3 lines of unified context.\n"
167 " -b (--ignore-space-change):\n"
169 " Ignore changes in the amount of white space.\n"
171 " -w (--ignore-all-space):\n"
173 " Ignore all white space.\n"
175 " --ignore-eol-style:\n"
177 " Ignore changes in EOL style\n"
179 " -p (--show-c-function):\n"
181 " Show C function name in diff output.")},
183 {"targets", opt_targets
, 1,
184 N_("pass contents of file ARG as additional args")},
185 {"depth", opt_depth
, 1,
186 N_("limit operation by depth ARG ('empty', 'files',\n"
188 "'immediates', or 'infinity')")},
189 {"set-depth", opt_set_depth
, 1,
190 N_("set new working copy depth to ARG ('empty',\n"
192 "'files', 'immediates', or 'infinity')")},
193 {"xml", opt_xml
, 0, N_("output in XML")},
194 {"strict", opt_strict
, 0, N_("use strict semantics")},
195 {"stop-on-copy", opt_stop_on_copy
, 0,
196 N_("do not cross copies while traversing history")},
197 {"no-ignore", opt_no_ignore
, 0,
198 N_("disregard default and svn:ignore property ignores")},
199 {"no-auth-cache", opt_no_auth_cache
, 0,
200 N_("do not cache authentication tokens")},
201 {"non-interactive", opt_non_interactive
, 0,
202 N_("do no interactive prompting")},
203 {"dry-run", opt_dry_run
, 0,
204 N_("try operation but make no changes")},
205 {"no-diff-deleted", opt_no_diff_deleted
, 0,
206 N_("do not print differences for deleted files")},
207 {"notice-ancestry", opt_notice_ancestry
, 0,
208 N_("notice ancestry when calculating differences")},
209 {"ignore-ancestry", opt_ignore_ancestry
, 0,
210 N_("ignore ancestry when calculating merges")},
211 {"ignore-externals", opt_ignore_externals
, 0,
212 N_("ignore externals definitions")},
214 {"diff-cmd", opt_diff_cmd
, 1, N_("use ARG as diff command")},
215 {"diff3-cmd", opt_merge_cmd
, 1, N_("use ARG as merge command")},
216 {"editor-cmd", opt_editor_cmd
, 1, N_("use ARG as external editor")},
218 {"record-only", opt_record_only
, 0,
219 N_("mark revisions as merged (use with -r)")},
220 {"old", opt_old_cmd
, 1, N_("use ARG as the older target")},
221 {"new", opt_new_cmd
, 1, N_("use ARG as the newer target")},
222 {"revprop", opt_revprop
, 0,
223 N_("operate on a revision property (use with -r)")},
224 {"relocate", opt_relocate
, 0, N_("relocate via URL-rewriting")},
225 {"config-dir", opt_config_dir
, 1,
226 N_("read user configuration files from directory ARG")},
227 {"auto-props", opt_autoprops
, 0, N_("enable automatic properties")},
228 {"no-auto-props", opt_no_autoprops
, 0, N_("disable automatic properties")},
229 {"native-eol", opt_native_eol
, 1,
230 N_("use a different EOL marker than the standard\n"
232 "system marker for files with the svn:eol-style\n"
234 "property set to 'native'.\n"
236 "ARG may be one of 'LF', 'CR', 'CRLF'")},
237 {"limit", 'l', 1, N_("maximum number of log entries")},
238 {"no-unlock", opt_no_unlock
, 0, N_("don't unlock the targets")},
239 {"summarize", opt_summarize
, 0, N_("show a summary of the results")},
240 {"remove", opt_remove
, 0, N_("remove changelist association")},
241 {"changelist", opt_changelist
, 1,
242 N_("operate only on members of changelist ARG\n"
245 {"keep-changelists", opt_keep_changelists
, 0,
246 N_("don't delete changelists after commit")},
247 {"keep-local", opt_keep_local
, 0, N_("keep path in working copy")},
248 {"with-all-revprops", opt_with_all_revprops
, 0,
249 N_("retrieve all revision properties")},
250 {"with-revprop", opt_with_revprop
, 1,
251 N_("set revision property ARG in new revision\n"
253 "using the name[=value] format")},
254 {"parents", opt_parents
, 0, N_("make intermediate directories")},
255 {"use-merge-history", 'g', 0,
256 N_("use/display additional information from merge\n"
259 {"accept", opt_accept
, 1,
260 N_("specify automatic conflict resolution action\n"
262 "('" SVN_CL__ACCEPT_POSTPONE
"',"
263 " '" SVN_CL__ACCEPT_BASE
"',"
264 /* These two are not implemented yet, so don't
265 waste the user's time with them. */
266 /* " '" SVN_CL__ACCEPT_MINE_CONFLICT "'," */
267 /* " '" SVN_CL__ACCEPT_THEIRS_CONFLICT "'," */
268 " '" SVN_CL__ACCEPT_MINE_FULL
"',"
269 " '" SVN_CL__ACCEPT_THEIRS_FULL
"',"
271 " '" SVN_CL__ACCEPT_EDIT
"',"
272 " '" SVN_CL__ACCEPT_LAUNCH
"')")},
273 {"show-revs", opt_show_revs
, 1,
274 N_("specify which collection of revisions to display\n"
276 "('" SVN_CL__SHOW_REVS_MERGED
"',"
277 " '" SVN_CL__SHOW_REVS_ELIGIBLE
"')")},
278 {"reintegrate", opt_reintegrate
, 0,
279 N_("lump-merge all of source URL's unmerged changes")},
283 * These have NULL desriptions, but an option code that matches some
284 * other option (whose description should probably mention its aliases).
287 {"cl", opt_changelist
, 1, NULL
},
294 /*** Command dispatch. ***/
296 /* Our array of available subcommands.
298 * The entire list must be terminated with an entry of nulls.
300 * In most of the help text "PATH" is used where a working copy path is
301 * required, "URL" where a repository URL is required and "TARGET" when
302 * either a path or an url can be used. Hmm, should this be part of the
306 /* Options that apply to all commands. (While not every command may
307 currently require authentication or be interactive, allowing every
308 command to take these arguments allows scripts to just pass them
309 willy-nilly to every invocation of 'svn') . */
310 const int svn_cl__global_options
[] =
311 { opt_auth_username
, opt_auth_password
, opt_no_auth_cache
, opt_non_interactive
,
315 /* Options for giving a log message. (Some of these also have other uses.)
317 #define SVN_CL__LOG_MSG_OPTIONS 'm', 'F', \
323 const svn_opt_subcommand_desc2_t svn_cl__cmd_table
[] =
325 { "add", svn_cl__add
, {0}, N_
326 ("Put files and directories under version control, scheduling\n"
327 "them for addition to repository. They will be added in next commit.\n"
328 "usage: add PATH...\n"),
329 {opt_targets
, 'N', opt_depth
, 'q', opt_force
, opt_no_ignore
, opt_autoprops
,
330 opt_no_autoprops
, opt_parents
},
331 {{opt_parents
, N_("add intermediate parents")}} },
333 { "blame", svn_cl__blame
, {"praise", "annotate", "ann"}, N_
334 ("Output the content of specified files or\n"
335 "URLs with revision and author information in-line.\n"
336 "usage: blame TARGET[@REV]...\n"
338 " If specified, REV determines in which revision the target is first\n"
340 {'r', 'v', 'g', opt_incremental
, opt_xml
, 'x', opt_force
} },
342 { "cat", svn_cl__cat
, {0}, N_
343 ("Output the content of specified files or URLs.\n"
344 "usage: cat TARGET[@REV]...\n"
346 " If specified, REV determines in which revision the target is first\n"
350 { "changelist", svn_cl__changelist
, {"cl"}, N_
351 ("Associate (or dissociate) changelist CLNAME with the named files.\n"
352 "usage: 1. changelist CLNAME TARGET...\n"
353 " 2. changelist --remove TARGET...\n"),
354 { 'q', 'R', opt_depth
, opt_remove
, opt_targets
, opt_changelist
} },
356 { "checkout", svn_cl__checkout
, {"co"}, N_
357 ("Check out a working copy from a repository.\n"
358 "usage: checkout URL[@REV]... [PATH]\n"
360 " If specified, REV determines in which revision the URL is first\n"
363 " If PATH is omitted, the basename of the URL will be used as\n"
364 " the destination. If multiple URLs are given each will be checked\n"
365 " out into a sub-directory of PATH, with the name of the sub-directory\n"
366 " being the basename of the URL.\n"
368 " If --force is used, unversioned obstructing paths in the working\n"
369 " copy destination do not automatically cause the check out to fail.\n"
370 " If the obstructing path is the same type (file or directory) as the\n"
371 " corresponding path in the repository it becomes versioned but its\n"
372 " contents are left 'as-is' in the working copy. This means that an\n"
373 " obstructing directory's unversioned children may also obstruct and\n"
374 " become versioned. For files, any content differences between the\n"
375 " obstruction and the repository are treated like a local modification\n"
376 " to the working copy. All properties from the repository are applied\n"
377 " to the obstructing path.\n"),
378 {'r', 'q', 'N', opt_depth
, opt_force
, opt_ignore_externals
, opt_accept
} },
380 { "cleanup", svn_cl__cleanup
, {0}, N_
381 ("Recursively clean up the working copy, removing locks, resuming\n"
382 "unfinished operations, etc.\n"
383 "usage: cleanup [PATH...]\n"),
386 { "commit", svn_cl__commit
, {"ci"},
388 N_("Send changes from your working copy to the repository.\n"
389 "usage: commit [PATH...]\n"
391 " A log message must be provided, but it can be empty. If it is not\n"
392 " given by a --message or --file option, an editor will be started.\n"
393 " If any targets are (or contain) locked items, those will be\n"
394 " unlocked after a successful commit.\n"),
396 N_("Send changes from your working copy to the repository.\n"
397 "usage: commit [PATH...]\n"
399 " A log message must be provided, but it can be empty.\n"
400 " OS400 does not support the starting of an editor,\n"
401 " so --message or --file must be used. If any targets are\n"
402 " (or contain) locked items, those will be unlocked after a\n"
403 " successful commit.\n"),
405 {'q', 'N', opt_depth
, opt_targets
, opt_no_unlock
, SVN_CL__LOG_MSG_OPTIONS
,
406 opt_changelist
, opt_keep_changelists
} },
408 { "copy", svn_cl__copy
, {"cp"}, N_
409 ("Duplicate something in working copy or repository, remembering\n"
411 "usage: copy SRC[@REV]... DST\n"
413 "When copying multiple sources, they will be added as children of DST,\n"
414 "which must be a directory.\n"
416 " SRC and DST can each be either a working copy (WC) path or URL:\n"
417 " WC -> WC: copy and schedule for addition (with history)\n"
418 " WC -> URL: immediately commit a copy of WC to URL\n"
419 " URL -> WC: check out URL into WC, schedule for addition\n"
420 " URL -> URL: complete server-side copy; used to branch and tag\n"
421 " All the SRCs must be of the same type.\n"
423 "WARNING: For compatibility with previous versions of Subversion,\n"
424 "copies performed using two working copy paths (WC -> WC) will not\n"
425 "contact the repository. As such, they may not, by default, be able\n"
426 "to propagate merge tracking information from the source of the copy\n"
427 "to the destination.\n"),
428 {'r', 'q', opt_parents
, SVN_CL__LOG_MSG_OPTIONS
} },
430 { "delete", svn_cl__delete
, {"del", "remove", "rm"}, N_
431 ("Remove files and directories from version control.\n"
432 "usage: 1. delete PATH...\n"
433 " 2. delete URL...\n"
435 " 1. Each item specified by a PATH is scheduled for deletion upon\n"
436 " the next commit. Files, and directories that have not been\n"
437 " committed, are immediately removed from the working copy\n"
438 " unless the --keep-local option is given.\n"
439 " PATHs that are, or contain, unversioned or modified items will\n"
440 " not be removed unless the --force option is given.\n"
442 " 2. Each item specified by a URL is deleted from the repository\n"
443 " via an immediate commit.\n"),
444 {opt_force
, 'q', opt_targets
, SVN_CL__LOG_MSG_OPTIONS
, opt_keep_local
} },
446 { "diff", svn_cl__diff
, {"di"}, N_
447 ("Display the differences between two revisions or paths.\n"
448 "usage: 1. diff [-c M | -r N[:M]] [TARGET[@REV]...]\n"
449 " 2. diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] \\\n"
451 " 3. diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]\n"
453 " 1. Display the changes made to TARGETs as they are seen in REV between\n"
454 " two revisions. TARGETs may be all working copy paths or all URLs.\n"
455 " If TARGETs are working copy paths, N defaults to BASE and M to the\n"
456 " working copy; if URLs, N must be specified and M defaults to HEAD.\n"
457 " The '-c M' option is equivalent to '-r N:M' where N = M-1.\n"
458 " Using '-c -M' does the reverse: '-r M:N' where N = M-1.\n"
460 " 2. Display the differences between OLD-TGT as it was seen in OLDREV and\n"
461 " NEW-TGT as it was seen in NEWREV. PATHs, if given, are relative to\n"
462 " OLD-TGT and NEW-TGT and restrict the output to differences for those\n"
463 " paths. OLD-TGT and NEW-TGT may be working copy paths or URL[@REV].\n"
464 " NEW-TGT defaults to OLD-TGT if not specified. -r N makes OLDREV default\n"
465 " to N, -r N:M makes OLDREV default to N and NEWREV default to M.\n"
467 " 3. Shorthand for 'svn diff --old=OLD-URL[@OLDREV] --new=NEW-URL[@NEWREV]'\n"
469 " Use just 'svn diff' to display local modifications in a working copy.\n"),
470 {'r', 'c', opt_old_cmd
, opt_new_cmd
, 'N', opt_depth
, opt_diff_cmd
, 'x',
471 opt_no_diff_deleted
, opt_notice_ancestry
, opt_summarize
, opt_changelist
,
472 opt_force
, opt_xml
} },
474 { "export", svn_cl__export
, {0}, N_
475 ("Create an unversioned copy of a tree.\n"
476 "usage: 1. export [-r REV] URL[@PEGREV] [PATH]\n"
477 " 2. export [-r REV] PATH1[@PEGREV] [PATH2]\n"
479 " 1. Exports a clean directory tree from the repository specified by\n"
480 " URL, at revision REV if it is given, otherwise at HEAD, into\n"
481 " PATH. If PATH is omitted, the last component of the URL is used\n"
482 " for the local directory name.\n"
484 " 2. Exports a clean directory tree from the working copy specified by\n"
485 " PATH1, at revision REV if it is given, otherwise at WORKING, into\n"
486 " PATH2. If PATH2 is omitted, the last component of the PATH1 is used\n"
487 " for the local directory name. If REV is not specified, all local\n"
488 " changes will be preserved. Files not under version control will\n"
491 " If specified, PEGREV determines in which revision the target is first\n"
493 {'r', 'q', 'N', opt_depth
, opt_force
, opt_native_eol
, opt_ignore_externals
} },
495 { "help", svn_cl__help
, {"?", "h"}, N_
496 ("Describe the usage of this program or its subcommands.\n"
497 "usage: help [SUBCOMMAND...]\n"),
499 /* This command is also invoked if we see option "--help", "-h" or "-?". */
501 { "import", svn_cl__import
, {0}, N_
502 ("Commit an unversioned file or tree into the repository.\n"
503 "usage: import [PATH] URL\n"
505 " Recursively commit a copy of PATH to URL.\n"
506 " If PATH is omitted '.' is assumed.\n"
507 " Parent directories are created as necessary in the repository.\n"
508 " If PATH is a directory, the contents of the directory are added\n"
509 " directly under URL.\n"
510 " Unversionable items such as device files and pipes are ignored\n"
511 " if --force is specified.\n"),
512 {'q', 'N', opt_depth
, opt_autoprops
, opt_force
, opt_no_autoprops
,
513 SVN_CL__LOG_MSG_OPTIONS
, opt_no_ignore
} },
515 { "info", svn_cl__info
, {0}, N_
516 ("Display information about a local or remote item.\n"
517 "usage: info [TARGET[@REV]...]\n"
519 " Print information about each TARGET (default: '.')\n"
520 " TARGET may be either a working-copy path or URL. If specified, REV\n"
521 " determines in which revision the target is first looked up.\n"),
522 {'r', 'R', opt_depth
, opt_targets
, opt_incremental
, opt_xml
, opt_changelist
}
525 { "list", svn_cl__list
, {"ls"}, N_
526 ("List directory entries in the repository.\n"
527 "usage: list [TARGET[@REV]...]\n"
529 " List each TARGET file and the contents of each TARGET directory as\n"
530 " they exist in the repository. If TARGET is a working copy path, the\n"
531 " corresponding repository URL will be used. If specified, REV determines\n"
532 " in which revision the target is first looked up.\n"
534 " The default TARGET is '.', meaning the repository URL of the current\n"
535 " working directory.\n"
537 " With --verbose, the following fields will be shown for each item:\n"
539 " Revision number of the last commit\n"
540 " Author of the last commit\n"
541 " If locked, the letter 'O'. (Use 'svn info URL' to see details)\n"
543 " Date and time of the last commit\n"),
544 {'r', 'v', 'R', opt_depth
, opt_incremental
, opt_xml
} },
546 { "lock", svn_cl__lock
, {0}, N_
547 ("Lock working copy paths or URLs in the repository, so that\n"
548 "no other user can commit changes to them.\n"
549 "usage: lock TARGET...\n"
551 " Use --force to steal the lock from another user or working copy.\n"),
552 { opt_targets
, 'm', 'F', opt_force_log
, opt_encoding
, opt_force
},
553 {{'F', N_("read lock comment from file ARG")},
554 {'m', N_("specify lock comment ARG")},
555 {opt_force_log
, N_("force validity of lock comment source")}} },
557 { "log", svn_cl__log
, {0}, N_
558 ("Show the log messages for a set of revision(s) and/or file(s).\n"
559 "usage: 1. log [PATH]\n"
560 " 2. log URL[@REV] [PATH...]\n"
562 " 1. Print the log messages for a local PATH (default: '.').\n"
563 " The default revision range is BASE:1.\n"
565 " 2. Print the log messages for the PATHs (default: '.') under URL.\n"
566 " If specified, REV determines in which revision the URL is first\n"
567 " looked up, and the default revision range is REV:1; otherwise,\n"
568 " the URL is looked up in HEAD, and the default revision range is\n"
571 " With -v, also print all affected paths with each log message.\n"
572 " With -q, don't print the log message body itself (note that this is\n"
573 " compatible with -v).\n"
575 " Each log message is printed just once, even if more than one of the\n"
576 " affected paths for that revision were explicitly requested. Logs\n"
577 " follow copy history by default. Use --stop-on-copy to disable this\n"
578 " behavior, which can be useful for determining branchpoints.\n"
583 " svn log http://www.example.com/repo/project/foo.c\n"
584 " svn log http://www.example.com/repo/project foo.c bar.c\n"),
585 {'r', 'q', 'v', 'g', 'c', opt_targets
, opt_stop_on_copy
, opt_incremental
,
586 opt_xml
, 'l', opt_with_all_revprops
, opt_with_revprop
},
587 {{opt_with_revprop
, N_("retrieve revision property ARG")},
588 {'c', N_("the change made by ARG")}} },
590 { "merge", svn_cl__merge
, {0}, N_
591 ("Apply the differences between two sources to a working copy path.\n"
592 "usage: 1. merge sourceURL1[@N] sourceURL2[@M] [WCPATH]\n"
593 " 2. merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]\n"
594 " 3. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [WCPATH]\n"
596 " 1. In the first form, the source URLs are specified at revisions\n"
597 " N and M. These are the two sources to be compared. The revisions\n"
598 " default to HEAD if omitted.\n"
600 " 2. In the second form, the URLs corresponding to the source working\n"
601 " copy paths define the sources to be compared. The revisions must\n"
604 " 3. In the third form, SOURCE can be either a URL or a working copy\n"
605 " path (in which case its corresponding URL is used). SOURCE (in\n"
606 " revision REV) is compared as it existed between revisions N and M\n"
607 " for each revision range provided. If REV is not specified, HEAD\n"
608 " is assumed. '-c M' is equivalent to '-r <M-1>:M', and '-c -M'\n"
609 " does the reverse: '-r M:<M-1>'. If no revision ranges are\n"
610 " specified, the default range of 0:REV is used. Multiple '-c'\n"
611 " and/or '-r' instances may be specified, and mixing of forward\n"
612 " and reverse ranges is allowed.\n"
614 " WCPATH is the working copy path that will receive the changes.\n"
615 " If WCPATH is omitted, a default value of '.' is assumed, unless\n"
616 " the sources have identical basenames that match a file within '.':\n"
617 " in which case, the differences will be applied to that file.\n"
619 " NOTE: Subversion will only record metadata to track the merge\n"
620 " if the two sources are on the same line of history -- if the\n"
621 " first source is an ancestor of the second, or vice-versa. This is\n"
622 " guaranteed to be the case when using the third form listed above.\n"
623 " The --ignore-ancestry option overrides this, forcing Subversion to\n"
624 " regard the sources as unrelated and not to track the merge.\n"),
625 {'r', 'c', 'N', opt_depth
, 'q', opt_force
, opt_dry_run
, opt_merge_cmd
,
626 opt_record_only
, 'x', opt_ignore_ancestry
, opt_accept
, opt_reintegrate
} },
628 { "mergeinfo", svn_cl__mergeinfo
, {0}, N_
629 ("Query merge-related information.\n"
630 "usage: mergeinfo SOURCE-URL[@REV] [TARGET[@REV]]\n"
632 " Query information related to merges (or potential merges) between\n"
633 " SOURCE-URL and TARGET. If the --show-revs option is not provided,\n"
634 " display revisions which have been merged from SOURCE-URL to TARGET.\n"
635 " Otherwise, display the type of information specified by the\n"
636 " --show-revs option.\n"),
637 {'r', opt_show_revs
} },
639 { "mkdir", svn_cl__mkdir
, {0}, N_
640 ("Create a new directory under version control.\n"
641 "usage: 1. mkdir PATH...\n"
644 " Create version controlled directories.\n"
646 " 1. Each directory specified by a working copy PATH is created locally\n"
647 " and scheduled for addition upon the next commit.\n"
649 " 2. Each directory specified by a URL is created in the repository via\n"
650 " an immediate commit.\n"
652 " In both cases, all the intermediate directories must already exist,\n"
653 " unless the --parents option is given.\n"),
654 {'q', opt_parents
, SVN_CL__LOG_MSG_OPTIONS
} },
656 { "move", svn_cl__move
, {"mv", "rename", "ren"}, N_
657 ("Move and/or rename something in working copy or repository.\n"
658 "usage: move SRC... DST\n"
660 "When moving multiple sources, they will be added as children of DST,\n"
661 "which must be a directory.\n"
663 " Note: this subcommand is equivalent to a 'copy' and 'delete'.\n"
664 " Note: the --revision option has no use and is deprecated.\n"
666 " SRC and DST can both be working copy (WC) paths or URLs:\n"
667 " WC -> WC: move and schedule for addition (with history)\n"
668 " URL -> URL: complete server-side rename.\n"
669 " All the SRCs must be of the same type.\n"),
670 {'r', 'q', opt_force
, opt_parents
, SVN_CL__LOG_MSG_OPTIONS
} },
672 { "propdel", svn_cl__propdel
, {"pdel", "pd"}, N_
673 ("Remove a property from files, dirs, or revisions.\n"
674 "usage: 1. propdel PROPNAME [PATH...]\n"
675 " 2. propdel PROPNAME --revprop -r REV [TARGET]\n"
677 " 1. Removes versioned props in working copy.\n"
678 " 2. Removes unversioned remote prop on repos revision.\n"
679 " TARGET only determines which repository to access.\n"),
680 {'q', 'R', opt_depth
, 'r', opt_revprop
, opt_changelist
} },
683 { "propedit", svn_cl__propedit
, {"pedit", "pe"}, N_
684 ("Edit a property with an external editor.\n"
685 "usage: 1. propedit PROPNAME TARGET...\n"
686 " 2. propedit PROPNAME --revprop -r REV [TARGET]\n"
688 " 1. Edits versioned prop in working copy or repository.\n"
689 " 2. Edits unversioned remote prop on repos revision.\n"
690 " TARGET only determines which repository to access.\n"
692 "See 'svn help propset' for more on property setting.\n"),
693 {'r', opt_revprop
, SVN_CL__LOG_MSG_OPTIONS
, opt_force
} },
696 { "propget", svn_cl__propget
, {"pget", "pg"}, N_
697 ("Print the value of a property on files, dirs, or revisions.\n"
698 "usage: 1. propget PROPNAME [TARGET[@REV]...]\n"
699 " 2. propget PROPNAME --revprop -r REV [TARGET]\n"
701 " 1. Prints versioned props. If specified, REV determines in which\n"
702 " revision the target is first looked up.\n"
703 " 2. Prints unversioned remote prop on repos revision.\n"
704 " TARGET only determines which repository to access.\n"
706 " By default, this subcommand will add an extra newline to the end\n"
707 " of the property values so that the output looks pretty. Also,\n"
708 " whenever there are multiple paths involved, each property value\n"
709 " is prefixed with the path with which it is associated. Use\n"
710 " the --strict option to disable these beautifications (useful,\n"
711 " for example, when redirecting binary property values to a file).\n"),
712 {'R', opt_depth
, 'r', opt_revprop
, opt_strict
, opt_xml
, opt_changelist
} },
714 { "proplist", svn_cl__proplist
, {"plist", "pl"}, N_
715 ("List all properties on files, dirs, or revisions.\n"
716 "usage: 1. proplist [TARGET[@REV]...]\n"
717 " 2. proplist --revprop -r REV [TARGET]\n"
719 " 1. Lists versioned props. If specified, REV determines in which\n"
720 " revision the target is first looked up.\n"
721 " 2. Lists unversioned remote props on repos revision.\n"
722 " TARGET only determines which repository to access.\n"),
723 {'v', 'R', opt_depth
, 'r', 'q', opt_revprop
, opt_xml
, opt_changelist
} },
725 { "propset", svn_cl__propset
, {"pset", "ps"}, N_
726 ("Set the value of a property on files, dirs, or revisions.\n"
727 "usage: 1. propset PROPNAME PROPVAL PATH...\n"
728 " 2. propset PROPNAME --revprop -r REV PROPVAL [TARGET]\n"
730 " 1. Creates a versioned, local propchange in working copy.\n"
731 " 2. Creates an unversioned, remote propchange on repos revision.\n"
732 " TARGET only determines which repository to access.\n"
734 " The value may be provided with the --file option instead of PROPVAL.\n"
736 " Note: svn recognizes the following special versioned properties\n"
737 " but will store any arbitrary properties set:\n"
738 " svn:ignore - A newline separated list of file glob patterns to ignore.\n"
739 " svn:keywords - Keywords to be expanded. Valid keywords are:\n"
740 " URL, HeadURL - The URL for the head version of the object.\n"
741 " Author, LastChangedBy - The last person to modify the file.\n"
742 " Date, LastChangedDate - The date/time the object was last modified.\n"
743 " Rev, Revision, - The last revision the object changed.\n"
744 " LastChangedRevision\n"
745 " Id - A compressed summary of the previous\n"
747 " svn:executable - If present, make the file executable. Use\n"
748 " 'svn propdel svn:executable PATH...' to clear.\n"
749 " svn:eol-style - One of 'native', 'LF', 'CR', 'CRLF'.\n"
750 " svn:mime-type - The mimetype of the file. Used to determine\n"
751 " whether to merge the file, and how to serve it from Apache.\n"
752 " A mimetype beginning with 'text/' (or an absent mimetype) is\n"
753 " treated as text. Anything else is treated as binary.\n"
754 " svn:externals - A newline separated list of module specifiers,\n"
755 " each of which consists of a relative directory path, optional\n"
756 " revision flags and an URL. The ordering of the three elements\n"
757 " implements different behavior. Subversion 1.4 and earlier only\n"
758 " support the following formats and the URLs cannot have peg\n"
760 " foo http://example.com/repos/zig\n"
761 " foo/bar -r 1234 http://example.com/repos/zag\n"
762 " Subversion 1.5 and greater support the above formats and the\n"
763 " following formats where the URLs may have peg revisions:\n"
764 " http://example.com/repos/zig foo\n"
765 " -r 1234 http://example.com/repos/zig foo/bar\n"
766 " Relative URLs are supported in Subversion 1.5 and greater for\n"
767 " all above formats and are indicated by starting the URL with one\n"
768 " of the following strings\n"
769 " ../ to the parent directory of the extracted external\n"
770 " ^/ to the repository root\n"
771 " // to the scheme\n"
772 " / to the server root\n"
773 " The ambiguous format 'relative_path relative_path' is taken as\n"
774 " 'relative_url relative_path' with peg revision support.\n"
775 " svn:needs-lock - If present, indicates that the file should be locked\n"
776 " before it is modified. Makes the working copy file read-only\n"
777 " when it is not locked. Use 'svn propdel svn:needs-lock PATH...'\n"
780 " The svn:keywords, svn:executable, svn:eol-style, svn:mime-type and\n"
781 " svn:needs-lock properties cannot be set on a directory. A non-recursive\n"
782 " attempt will fail, and a recursive attempt will set the property\n"
783 " only on the file children of the directory.\n"),
784 {'F', opt_encoding
, 'q', 'r', opt_targets
, 'R', opt_depth
, opt_revprop
,
785 opt_force
, opt_changelist
},
786 {{'F', N_("read property value from file ARG")}} },
788 { "resolve", svn_cl__resolve
, {0}, N_
789 ("Resolve conflicts on working copy files or directories.\n"
790 "usage: resolve [PATH...]\n"
792 " Note: the --accept option is currently required.\n"),
793 {opt_targets
, 'R', opt_depth
, 'q', opt_accept
},
794 {{opt_accept
, N_("specify automatic conflict resolution source\n"
796 "('" SVN_CL__ACCEPT_BASE
"',"
797 " '" SVN_CL__ACCEPT_WORKING
"',"
798 /* These two are not implemented yet, so
799 don't waste the user's time with them. */
800 /* " '" SVN_CL__ACCEPT_MINE_CONFLICT "'," */
801 /* " '" SVN_CL__ACCEPT_THEIRS_CONFLICT "'," */
802 " '" SVN_CL__ACCEPT_MINE_FULL
"',"
803 " '" SVN_CL__ACCEPT_THEIRS_FULL
"')")}} },
805 { "resolved", svn_cl__resolved
, {0}, N_
806 ("Remove 'conflicted' state on working copy files or directories.\n"
807 "usage: resolved PATH...\n"
809 " Note: this subcommand does not semantically resolve conflicts or\n"
810 " remove conflict markers; it merely removes the conflict-related\n"
811 " artifact files and allows PATH to be committed again. It has been\n"
812 " deprecated in favor of running 'svn resolve --accept working'.\n"),
813 {opt_targets
, 'R', opt_depth
, 'q'} },
815 { "revert", svn_cl__revert
, {0}, N_
816 ("Restore pristine working copy file (undo most local edits).\n"
817 "usage: revert PATH...\n"
819 " Note: this subcommand does not require network access, and resolves\n"
820 " any conflicted states. However, it does not restore removed directories.\n"),
821 {opt_targets
, 'R', opt_depth
, 'q', opt_changelist
} },
823 { "status", svn_cl__status
, {"stat", "st"}, N_
824 ("Print the status of working copy files and directories.\n"
825 "usage: status [PATH...]\n"
827 " With no args, print only locally modified items (no network access).\n"
828 " With -q, print only summary information about locally modified items.\n"
829 " With -u, add working revision and server out-of-date information.\n"
830 " With -v, print full revision information on every item.\n"
832 " The first six columns in the output are each one character wide:\n"
833 " First column: Says if item was added, deleted, or otherwise changed\n"
834 " ' ' no modifications\n"
841 " 'X' item is unversioned, but is used by an externals definition\n"
842 " '?' item is not under version control\n"
843 " '!' item is missing (removed by non-svn command) or incomplete\n"
844 " '~' versioned item obstructed by some item of a different kind\n"
845 " Second column: Modifications of a file's or directory's properties\n"
846 " ' ' no modifications\n"
849 " Third column: Whether the working copy directory is locked\n"
852 " Fourth column: Scheduled commit will contain addition-with-history\n"
853 " ' ' no history scheduled with commit\n"
854 " '+' history scheduled with commit\n"
855 " Fifth column: Whether the item is switched relative to its parent\n"
858 " Sixth column: Repository lock token\n"
860 " ' ' no lock token\n"
861 " 'K' lock token present\n"
863 " ' ' not locked in repository, no lock token\n"
864 " 'K' locked in repository, lock toKen present\n"
865 " 'O' locked in repository, lock token in some Other working copy\n"
866 " 'T' locked in repository, lock token present but sTolen\n"
867 " 'B' not locked in repository, lock token present but Broken\n"
869 " The out-of-date information appears in the eighth column (with -u):\n"
870 " '*' a newer revision exists on the server\n"
871 " ' ' the working copy is up to date\n"
873 " Remaining fields are variable width and delimited by spaces:\n"
874 " The working revision (with -u or -v)\n"
875 " The last committed revision and last committed author (with -v)\n"
876 " The working copy path is always the final field, so it can\n"
884 " svn status -u wc\n"
887 " A + 965 wc/qax.c\n"
888 " Status against revision: 981\n"
890 " svn status --show-updates --verbose wc\n"
891 " M 965 938 kfogel wc/bar.c\n"
892 " * 965 922 sussman wc/foo.c\n"
893 " A + 965 687 joe wc/qax.c\n"
894 " 965 687 joe wc/zig.c\n"
895 " Status against revision: 981\n"),
896 { 'u', 'v', 'N', opt_depth
, 'q', opt_no_ignore
, opt_incremental
, opt_xml
,
897 opt_ignore_externals
, opt_changelist
} },
899 { "switch", svn_cl__switch
, {"sw"}, N_
900 ("Update the working copy to a different URL.\n"
901 "usage: 1. switch URL[@PEGREV] [PATH]\n"
902 " 2. switch --relocate FROM TO [PATH...]\n"
904 " 1. Update the working copy to mirror a new URL within the repository.\n"
905 " This behaviour is similar to 'svn update', and is the way to\n"
906 " move a working copy to a branch or tag within the same repository.\n"
907 " If specified, PEGREV determines in which revision the target is first\n"
910 " If --force is used, unversioned obstructing paths in the working\n"
911 " copy do not automatically cause a failure if the switch attempts to\n"
912 " add the same path. If the obstructing path is the same type (file\n"
913 " or directory) as the corresponding path in the repository it becomes\n"
914 " versioned but its contents are left 'as-is' in the working copy.\n"
915 " This means that an obstructing directory's unversioned children may\n"
916 " also obstruct and become versioned. For files, any content differences\n"
917 " between the obstruction and the repository are treated like a local\n"
918 " modification to the working copy. All properties from the repository\n"
919 " are applied to the obstructing path.\n"
921 " Use the --set-depth option to set a new working copy depth on the\n"
922 " targets of this operation. Currently, the depth of a working copy\n"
923 " directory can only be increased (telescoped more deeply); you cannot\n"
924 " make a directory more shallow.\n"
926 " 2. Rewrite working copy URL metadata to reflect a syntactic change only.\n"
927 " This is used when repository's root URL changes (such as a scheme\n"
928 " or hostname change) but your working copy still reflects the same\n"
929 " directory within the same repository.\n"),
930 { 'r', 'N', opt_depth
, opt_set_depth
, 'q', opt_merge_cmd
, opt_relocate
,
931 opt_ignore_externals
, opt_force
, opt_accept
} },
933 { "unlock", svn_cl__unlock
, {0}, N_
934 ("Unlock working copy paths or URLs.\n"
935 "usage: unlock TARGET...\n"
937 " Use --force to break the lock.\n"),
938 { opt_targets
, opt_force
} },
940 { "update", svn_cl__update
, {"up"}, N_
941 ("Bring changes from the repository into the working copy.\n"
942 "usage: update [PATH...]\n"
944 " If no revision given, bring working copy up-to-date with HEAD rev.\n"
945 " Else synchronize working copy to revision given by -r.\n"
947 " For each updated item a line will start with a character reporting the\n"
948 " action taken. These characters have the following meaning:\n"
957 " A character in the first column signifies an update to the actual file,\n"
958 " while updates to the file's properties are shown in the second column.\n"
959 " A 'B' in the third column signifies that the lock for the file has\n"
960 " been broken or stolen.\n"
962 " If --force is used, unversioned obstructing paths in the working\n"
963 " copy do not automatically cause a failure if the update attempts to\n"
964 " add the same path. If the obstructing path is the same type (file\n"
965 " or directory) as the corresponding path in the repository it becomes\n"
966 " versioned but its contents are left 'as-is' in the working copy.\n"
967 " This means that an obstructing directory's unversioned children may\n"
968 " also obstruct and become versioned. For files, any content differences\n"
969 " between the obstruction and the repository are treated like a local\n"
970 " modification to the working copy. All properties from the repository\n"
971 " are applied to the obstructing path. Obstructing paths are reported\n"
972 " in the first column with code 'E'.\n"
974 " Use the --set-depth option to set a new working copy depth on the\n"
975 " targets of this operation. Currently, the depth of a working copy\n"
976 " directory can only be increased (telescoped more deeply); you cannot\n"
977 " make a directory more shallow.\n"),
978 {'r', 'N', opt_depth
, opt_set_depth
, 'q', opt_merge_cmd
, opt_force
,
979 opt_ignore_externals
, opt_changelist
, opt_editor_cmd
, opt_accept
} },
981 { NULL
, NULL
, {0}, NULL
, {0} }
985 /* Version compatibility check */
987 check_lib_versions(void)
989 static const svn_version_checklist_t checklist
[] =
991 { "svn_subr", svn_subr_version
},
992 { "svn_client", svn_client_version
},
993 { "svn_wc", svn_wc_version
},
994 { "svn_ra", svn_ra_version
},
995 { "svn_delta", svn_delta_version
},
996 { "svn_diff", svn_diff_version
},
1000 SVN_VERSION_DEFINE(my_version
);
1001 return svn_ver_check_list(&my_version
, checklist
);
1005 /* A flag to see if we've been cancelled by the client or not. */
1006 static volatile sig_atomic_t cancelled
= FALSE
;
1008 /* A signal handler to support cancellation. */
1010 signal_handler(int signum
)
1012 apr_signal(signum
, SIG_IGN
);
1016 /* Our cancellation callback. */
1018 svn_cl__check_cancel(void *baton
)
1021 return svn_error_create(SVN_ERR_CANCELLED
, NULL
, _("Caught signal"));
1023 return SVN_NO_ERROR
;
1031 main(int argc
, const char *argv
[])
1034 apr_allocator_t
*allocator
;
1038 svn_cl__opt_state_t opt_state
= { 0, { 0 } };
1039 svn_client_ctx_t
*ctx
;
1040 apr_array_header_t
*received_opts
;
1042 const svn_opt_subcommand_desc2_t
*subcommand
= NULL
;
1043 const char *dash_m_arg
= NULL
, *dash_F_arg
= NULL
;
1044 const char *path_utf8
;
1045 apr_status_t apr_err
;
1046 svn_cl__cmd_baton_t command_baton
;
1047 svn_auth_baton_t
*ab
;
1049 svn_boolean_t descend
= TRUE
;
1050 svn_boolean_t interactive_conflicts
= FALSE
;
1051 apr_hash_t
*changelists
;
1053 /* Initialize the app. */
1054 if (svn_cmdline_init("svn", stderr
) != EXIT_SUCCESS
)
1055 return EXIT_FAILURE
;
1057 /* Create our top-level pool. Use a seperate mutexless allocator,
1058 * given this application is single threaded.
1060 if (apr_allocator_create(&allocator
))
1061 return EXIT_FAILURE
;
1063 apr_allocator_max_free_set(allocator
, SVN_ALLOCATOR_RECOMMENDED_MAX_FREE
);
1065 pool
= svn_pool_create_ex(NULL
, allocator
);
1066 apr_allocator_owner_set(allocator
, pool
);
1068 received_opts
= apr_array_make(pool
, SVN_OPT_MAX_OPTIONS
, sizeof(int));
1070 /* Check library versions */
1071 err
= check_lib_versions();
1073 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1075 #if defined(WIN32) || defined(__CYGWIN__)
1076 /* Set the working copy administrative directory name. */
1077 if (getenv("SVN_ASP_DOT_NET_HACK"))
1079 err
= svn_wc_set_adm_dir("_svn", pool
);
1081 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1085 /* Initialize the RA library. */
1086 err
= svn_ra_initialize(pool
);
1088 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1090 /* Init our changelists hash. */
1091 changelists
= apr_hash_make(pool
);
1093 /* Begin processing arguments. */
1094 opt_state
.start_revision
.kind
= svn_opt_revision_unspecified
;
1095 opt_state
.end_revision
.kind
= svn_opt_revision_unspecified
;
1096 opt_state
.revision_ranges
=
1097 apr_array_make(pool
, 0, sizeof(svn_opt_revision_range_t
*));
1098 opt_state
.depth
= svn_depth_unknown
;
1099 opt_state
.set_depth
= svn_depth_unknown
;
1100 opt_state
.accept_which
= svn_cl__accept_unspecified
;
1101 opt_state
.show_revs
= svn_cl__show_revs_merged
;
1103 /* No args? Show usage. */
1106 svn_cl__help(NULL
, NULL
, pool
);
1107 svn_pool_destroy(pool
);
1108 return EXIT_FAILURE
;
1111 /* Else, parse options. */
1112 err
= svn_cmdline__getopt_init(&os
, argc
, argv
, pool
);
1114 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1119 const char *opt_arg
;
1120 const char *utf8_opt_arg
;
1122 /* Parse the next option. */
1123 apr_err
= apr_getopt_long(os
, svn_cl__options
, &opt_id
, &opt_arg
);
1124 if (APR_STATUS_IS_EOF(apr_err
))
1128 svn_cl__help(NULL
, NULL
, pool
);
1129 svn_pool_destroy(pool
);
1130 return EXIT_FAILURE
;
1133 /* Stash the option code in an array before parsing it. */
1134 APR_ARRAY_PUSH(received_opts
, int) = opt_id
;
1140 opt_state
.limit
= strtol(opt_arg
, &end
, 10);
1141 if (end
== opt_arg
|| *end
!= '\0')
1143 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1144 _("Non-numeric limit argument given"));
1145 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1147 if (opt_state
.limit
<= 0)
1149 err
= svn_error_create(SVN_ERR_INCORRECT_PARAMS
, NULL
,
1150 _("Argument to --limit must be positive"));
1151 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1156 /* Note that there's no way here to detect if the log message
1157 contains a zero byte -- if it does, then opt_arg will just
1158 be shorter than the user intended. Oh well. */
1159 opt_state
.message
= apr_pstrdup(pool
, opt_arg
);
1160 dash_m_arg
= opt_arg
;
1165 svn_revnum_t changeno
;
1166 svn_opt_revision_range_t
*range
;
1168 if (opt_state
.old_target
)
1170 err
= svn_error_create
1171 (SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1172 _("Can't specify -c with --old"));
1173 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1178 /* Allow any number of 'r's to prefix a revision number.
1179 ### TODO: Any reason we're not just using opt.c's
1180 ### revision-parsing code here? Then -c could take
1181 ### "{DATE}" and the special words. */
1182 while (*opt_arg
== 'r')
1185 changeno
= strtol(opt_arg
, &end
, 10);
1186 if (end
== opt_arg
|| !(*end
== '\0' || *end
== ',') )
1188 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1189 _("Non-numeric change argument "
1191 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1196 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1197 _("There is no change 0"));
1198 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1202 /* Figure out the range:
1204 -c -N -> -r N:N-1 */
1205 range
= apr_palloc(pool
, sizeof(*range
));
1208 range
->start
.value
.number
= changeno
- 1;
1209 range
->end
.value
.number
= changeno
;
1213 changeno
= -changeno
;
1214 range
->start
.value
.number
= changeno
;
1215 range
->end
.value
.number
= changeno
- 1;
1217 opt_state
.used_change_arg
= TRUE
;
1218 range
->start
.kind
= svn_opt_revision_number
;
1219 range
->end
.kind
= svn_opt_revision_number
;
1220 APR_ARRAY_PUSH(opt_state
.revision_ranges
,
1221 svn_opt_revision_range_t
*) = range
;
1222 } while (*end
!= '\0');
1226 if (svn_opt_parse_revision_to_range(opt_state
.revision_ranges
,
1227 opt_arg
, pool
) != 0)
1229 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1231 err
= svn_error_createf
1232 (SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1233 _("Syntax error in revision argument '%s'"),
1235 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1239 opt_state
.verbose
= TRUE
;
1242 opt_state
.update
= TRUE
;
1246 opt_state
.help
= TRUE
;
1249 opt_state
.quiet
= TRUE
;
1251 case opt_incremental
:
1252 opt_state
.incremental
= TRUE
;
1255 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1257 err
= svn_stringbuf_from_file(&(opt_state
.filedata
),
1258 utf8_opt_arg
, pool
);
1260 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1261 dash_F_arg
= opt_arg
;
1265 svn_stringbuf_t
*buffer
, *buffer_utf8
;
1267 /* We need to convert to UTF-8 now, even before we divide
1268 the targets into an array, because otherwise we wouldn't
1269 know what delimiter to use for svn_cstring_split(). */
1271 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1274 err
= svn_stringbuf_from_file(&buffer
, utf8_opt_arg
, pool
);
1276 err
= svn_utf_stringbuf_to_utf8(&buffer_utf8
, buffer
, pool
);
1278 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1279 opt_state
.targets
= svn_cstring_split(buffer_utf8
->data
, "\n\r",
1284 opt_state
.force
= TRUE
;
1287 opt_state
.force_log
= TRUE
;
1290 opt_state
.dry_run
= TRUE
;
1293 opt_state
.revprop
= TRUE
;
1296 opt_state
.depth
= SVN_DEPTH_INFINITY_OR_FILES(TRUE
);
1302 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1304 return svn_cmdline_handle_exit_error
1305 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1306 _("Error converting depth "
1307 "from locale to UTF8")), pool
, "svn: ");
1308 opt_state
.depth
= svn_depth_from_word(utf8_opt_arg
);
1309 if (opt_state
.depth
== svn_depth_unknown
1310 || opt_state
.depth
== svn_depth_exclude
)
1312 return svn_cmdline_handle_exit_error
1313 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1314 _("'%s' is not a valid depth; try "
1315 "'empty', 'files', 'immediates', "
1317 utf8_opt_arg
), pool
, "svn: ");
1321 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1323 return svn_cmdline_handle_exit_error
1324 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1325 _("Error converting depth "
1326 "from locale to UTF8")), pool
, "svn: ");
1327 opt_state
.set_depth
= svn_depth_from_word(utf8_opt_arg
);
1328 if (opt_state
.set_depth
== svn_depth_unknown
1329 || opt_state
.set_depth
== svn_depth_exclude
)
1331 return svn_cmdline_handle_exit_error
1332 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1333 _("'%s' is not a valid depth; try "
1334 "'empty', 'files', 'immediates', "
1336 utf8_opt_arg
), pool
, "svn: ");
1340 opt_state
.version
= TRUE
;
1342 case opt_auth_username
:
1343 err
= svn_utf_cstring_to_utf8(&opt_state
.auth_username
,
1346 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1348 case opt_auth_password
:
1349 err
= svn_utf_cstring_to_utf8(&opt_state
.auth_password
,
1352 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1355 opt_state
.encoding
= apr_pstrdup(pool
, opt_arg
);
1358 opt_state
.xml
= TRUE
;
1360 case opt_stop_on_copy
:
1361 opt_state
.stop_on_copy
= TRUE
;
1364 opt_state
.strict
= TRUE
;
1367 opt_state
.no_ignore
= TRUE
;
1369 case opt_no_auth_cache
:
1370 opt_state
.no_auth_cache
= TRUE
;
1372 case opt_non_interactive
:
1373 opt_state
.non_interactive
= TRUE
;
1375 case opt_no_diff_deleted
:
1376 opt_state
.no_diff_deleted
= TRUE
;
1378 case opt_notice_ancestry
:
1379 opt_state
.notice_ancestry
= TRUE
;
1381 case opt_ignore_ancestry
:
1382 opt_state
.ignore_ancestry
= TRUE
;
1384 case opt_ignore_externals
:
1385 opt_state
.ignore_externals
= TRUE
;
1388 opt_state
.relocate
= TRUE
;
1391 err
= svn_utf_cstring_to_utf8(&opt_state
.extensions
, opt_arg
, pool
);
1393 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1396 opt_state
.diff_cmd
= apr_pstrdup(pool
, opt_arg
);
1399 opt_state
.merge_cmd
= apr_pstrdup(pool
, opt_arg
);
1401 case opt_record_only
:
1402 opt_state
.record_only
= TRUE
;
1404 case opt_editor_cmd
:
1405 opt_state
.editor_cmd
= apr_pstrdup(pool
, opt_arg
);
1408 if (opt_state
.used_change_arg
)
1410 err
= svn_error_create
1411 (SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1412 _("Can't specify -c with --old"));
1413 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1415 opt_state
.old_target
= apr_pstrdup(pool
, opt_arg
);
1418 opt_state
.new_target
= apr_pstrdup(pool
, opt_arg
);
1420 case opt_config_dir
:
1421 err
= svn_utf_cstring_to_utf8(&path_utf8
, opt_arg
, pool
);
1422 opt_state
.config_dir
= svn_path_canonicalize(path_utf8
, pool
);
1425 opt_state
.autoprops
= TRUE
;
1427 case opt_no_autoprops
:
1428 opt_state
.no_autoprops
= TRUE
;
1430 case opt_native_eol
:
1431 if ( !strcmp("LF", opt_arg
) || !strcmp("CR", opt_arg
) ||
1432 !strcmp("CRLF", opt_arg
))
1433 opt_state
.native_eol
= apr_pstrdup(pool
, opt_arg
);
1436 err
= svn_utf_cstring_to_utf8(&utf8_opt_arg
, opt_arg
, pool
);
1438 err
= svn_error_createf
1439 (SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1440 _("Syntax error in native-eol argument '%s'"),
1442 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1446 opt_state
.no_unlock
= TRUE
;
1449 opt_state
.summarize
= TRUE
;
1452 opt_state
.remove
= TRUE
;
1454 case opt_changelist
:
1455 opt_state
.changelist
= apr_pstrdup(pool
, opt_arg
);
1456 apr_hash_set(changelists
, opt_state
.changelist
,
1457 APR_HASH_KEY_STRING
, (void *)1);
1459 case opt_keep_changelists
:
1460 opt_state
.keep_changelists
= TRUE
;
1462 case opt_keep_local
:
1463 opt_state
.keep_local
= TRUE
;
1465 case opt_with_all_revprops
:
1466 /* If --with-all-revprops is specified along with one or more
1467 * --with-revprops options, --with-all-revprops takes precedence. */
1468 opt_state
.all_revprops
= TRUE
;
1470 case opt_with_revprop
:
1471 err
= svn_opt_parse_revprop(&opt_state
.revprop_table
, opt_arg
, pool
);
1472 if (err
!= SVN_NO_ERROR
)
1473 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1476 opt_state
.parents
= TRUE
;
1479 opt_state
.use_merge_history
= TRUE
;
1482 opt_state
.accept_which
= svn_cl__accept_from_word(opt_arg
);
1483 if (opt_state
.accept_which
== svn_cl__accept_invalid
)
1484 return svn_cmdline_handle_exit_error
1485 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1486 _("'%s' is not a valid --accept value"),
1491 opt_state
.show_revs
= svn_cl__show_revs_from_word(opt_arg
);
1492 if (opt_state
.show_revs
== svn_cl__show_revs_invalid
)
1493 return svn_cmdline_handle_exit_error
1494 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1495 _("'%s' is not a valid --show-revs value"),
1499 case opt_reintegrate
:
1500 opt_state
.reintegrate
= TRUE
;
1503 /* Hmmm. Perhaps this would be a good place to squirrel away
1504 opts that commands like svn diff might need. Hmmm indeed. */
1509 /* Turn our hash of changelists into an array of unique ones. */
1510 err
= svn_hash_keys(&(opt_state
.changelists
), changelists
, pool
);
1512 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1514 /* ### This really belongs in libsvn_client. The trouble is,
1515 there's no one place there to run it from, no
1516 svn_client_init(). We'd have to add it to all the public
1517 functions that a client might call. It's unmaintainable to do
1518 initialization from within libsvn_client itself, but it seems
1519 burdensome to demand that all clients call svn_client_init()
1520 before calling any other libsvn_client function... On the other
1521 hand, the alternative is effectively to demand that they call
1522 svn_config_ensure() instead, so maybe we should have a generic
1523 init function anyway. Thoughts? */
1524 err
= svn_config_ensure(opt_state
.config_dir
, pool
);
1526 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1528 /* If the user asked for help, then the rest of the arguments are
1529 the names of subcommands to get help on (if any), or else they're
1530 just typos/mistakes. Whatever the case, the subcommand to
1531 actually run is svn_cl__help(). */
1533 subcommand
= svn_opt_get_canonical_subcommand2(svn_cl__cmd_table
, "help");
1535 /* If we're not running the `help' subcommand, then look for a
1536 subcommand in the first argument. */
1537 if (subcommand
== NULL
)
1539 if (os
->ind
>= os
->argc
)
1541 if (opt_state
.version
)
1543 /* Use the "help" subcommand to handle the "--version" option. */
1544 static const svn_opt_subcommand_desc2_t pseudo_cmd
=
1545 { "--version", svn_cl__help
, {0}, "",
1546 {opt_version
, /* must accept its own option */
1547 'q', /* brief output */
1548 opt_config_dir
/* all commands accept this */
1551 subcommand
= &pseudo_cmd
;
1556 (svn_cmdline_fprintf(stderr
, pool
,
1557 _("Subcommand argument required\n")));
1558 svn_cl__help(NULL
, NULL
, pool
);
1559 svn_pool_destroy(pool
);
1560 return EXIT_FAILURE
;
1565 const char *first_arg
= os
->argv
[os
->ind
++];
1566 subcommand
= svn_opt_get_canonical_subcommand2(svn_cl__cmd_table
,
1568 if (subcommand
== NULL
)
1570 const char *first_arg_utf8
;
1571 err
= svn_utf_cstring_to_utf8(&first_arg_utf8
, first_arg
, pool
);
1573 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1575 (svn_cmdline_fprintf(stderr
, pool
,
1576 _("Unknown command: '%s'\n"),
1578 svn_cl__help(NULL
, NULL
, pool
);
1579 svn_pool_destroy(pool
);
1580 return EXIT_FAILURE
;
1585 /* Check that the subcommand wasn't passed any inappropriate options. */
1586 for (i
= 0; i
< received_opts
->nelts
; i
++)
1588 opt_id
= APR_ARRAY_IDX(received_opts
, i
, int);
1590 /* All commands implicitly accept --help, so just skip over this
1591 when we see it. Note that we don't want to include this option
1592 in their "accepted options" list because it would be awfully
1593 redundant to display it in every commands' help text. */
1594 if (opt_id
== 'h' || opt_id
== '?')
1597 if (! svn_opt_subcommand_takes_option3(subcommand
, opt_id
,
1598 svn_cl__global_options
))
1601 const apr_getopt_option_t
*badopt
=
1602 svn_opt_get_option_from_code2(opt_id
, svn_cl__options
,
1604 svn_opt_format_option(&optstr
, badopt
, FALSE
, pool
);
1605 if (subcommand
->name
[0] == '-')
1606 svn_cl__help(NULL
, NULL
, pool
);
1609 (svn_cmdline_fprintf
1610 (stderr
, pool
, _("Subcommand '%s' doesn't accept option '%s'\n"
1611 "Type 'svn help %s' for usage.\n"),
1612 subcommand
->name
, optstr
, subcommand
->name
));
1613 svn_pool_destroy(pool
);
1614 return EXIT_FAILURE
;
1618 /* Only merge supports multiple revisions/revision ranges. */
1619 if (subcommand
->cmd_func
!= svn_cl__merge
)
1621 if (opt_state
.revision_ranges
->nelts
> 1)
1623 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1624 _("Multiple revision arguments "
1625 "encountered; can't specify -c twice, "
1626 "or both -c and -r"));
1627 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1631 /* Merge doesn't support specifying a revision range
1632 when using --reintegrate. */
1633 if (subcommand
->cmd_func
== svn_cl__merge
1634 && opt_state
.revision_ranges
->nelts
1635 && opt_state
.reintegrate
)
1637 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1638 _("-r and -c can't be used with --reintegrate"));
1639 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1642 /* Disallow simultaneous use of both --depth and --set-depth. */
1643 if ((opt_state
.depth
!= svn_depth_unknown
)
1644 && (opt_state
.set_depth
!= svn_depth_unknown
))
1646 err
= svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1647 _("--depth and --set-depth are mutually "
1649 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1652 /* Ensure that 'revision_ranges' has at least one item, and that
1653 'start_revision' and 'end_revision' match that item. */
1654 if (opt_state
.revision_ranges
->nelts
== 0)
1656 svn_opt_revision_range_t
*range
= apr_palloc(pool
, sizeof(*range
));
1657 range
->start
.kind
= svn_opt_revision_unspecified
;
1658 range
->end
.kind
= svn_opt_revision_unspecified
;
1659 APR_ARRAY_PUSH(opt_state
.revision_ranges
,
1660 svn_opt_revision_range_t
*) = range
;
1662 opt_state
.start_revision
= APR_ARRAY_IDX(opt_state
.revision_ranges
, 0,
1663 svn_opt_revision_range_t
*)->start
;
1664 opt_state
.end_revision
= APR_ARRAY_IDX(opt_state
.revision_ranges
, 0,
1665 svn_opt_revision_range_t
*)->end
;
1667 /* If we're running a command that could result in a commit, verify
1668 that any log message we were given on the command line makes
1669 sense (unless we've also been instructed not to care). */
1670 if ((! opt_state
.force_log
)
1671 && (subcommand
->cmd_func
== svn_cl__commit
1672 || subcommand
->cmd_func
== svn_cl__copy
1673 || subcommand
->cmd_func
== svn_cl__delete
1674 || subcommand
->cmd_func
== svn_cl__import
1675 || subcommand
->cmd_func
== svn_cl__mkdir
1676 || subcommand
->cmd_func
== svn_cl__move
1677 || subcommand
->cmd_func
== svn_cl__lock
1678 || subcommand
->cmd_func
== svn_cl__propedit
))
1680 /* If the -F argument is a file that's under revision control,
1681 that's probably not what the user intended. */
1684 svn_wc_adm_access_t
*adm_access
;
1685 const svn_wc_entry_t
*e
;
1686 const char *fname_utf8
= svn_path_internal_style(dash_F_arg
, pool
);
1687 err
= svn_wc_adm_probe_open3(&adm_access
, NULL
, fname_utf8
,
1688 FALSE
, 0, NULL
, NULL
, pool
);
1690 err
= svn_wc_entry(&e
, fname_utf8
, adm_access
, FALSE
, pool
);
1691 if ((err
== SVN_NO_ERROR
) && e
)
1693 if (subcommand
->cmd_func
!= svn_cl__lock
)
1695 err
= svn_error_create
1696 (SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE
, NULL
,
1697 _("Log message file is a versioned file; "
1698 "use '--force-log' to override"));
1702 err
= svn_error_create
1703 (SVN_ERR_CL_LOG_MESSAGE_IS_VERSIONED_FILE
, NULL
,
1704 _("Lock comment file is a versioned file; "
1705 "use '--force-log' to override"));
1707 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1709 svn_error_clear(err
);
1712 /* If the -m argument is a file at all, that's probably not what
1713 the user intended. */
1717 if (apr_stat(&finfo
, dash_m_arg
,
1718 APR_FINFO_MIN
, pool
) == APR_SUCCESS
)
1720 if (subcommand
->cmd_func
!= svn_cl__lock
)
1722 err
= svn_error_create
1723 (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME
, NULL
,
1724 _("The log message is a pathname "
1725 "(was -F intended?); use '--force-log' to override"));
1729 err
= svn_error_create
1730 (SVN_ERR_CL_LOG_MESSAGE_IS_PATHNAME
, NULL
,
1731 _("The lock comment is a pathname "
1732 "(was -F intended?); use '--force-log' to override"));
1734 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1739 if (opt_state
.relocate
&& (opt_state
.depth
!= svn_depth_unknown
))
1741 err
= svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS
, NULL
,
1742 _("--relocate and --depth are mutually "
1744 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1747 /* Only a few commands can accept a revision range; the rest can take at
1748 most one revision number. */
1749 if (subcommand
->cmd_func
!= svn_cl__blame
1750 && subcommand
->cmd_func
!= svn_cl__diff
1751 && subcommand
->cmd_func
!= svn_cl__log
1752 && subcommand
->cmd_func
!= svn_cl__merge
)
1754 if (opt_state
.end_revision
.kind
!= svn_opt_revision_unspecified
)
1756 err
= svn_error_create(SVN_ERR_CLIENT_REVISION_RANGE
, NULL
, NULL
);
1757 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1761 /* -N has a different meaning depending on the command */
1762 if (descend
== FALSE
)
1764 if (subcommand
->cmd_func
== svn_cl__status
)
1766 opt_state
.depth
= SVN_DEPTH_INFINITY_OR_IMMEDIATES(FALSE
);
1768 else if (subcommand
->cmd_func
== svn_cl__revert
1769 || subcommand
->cmd_func
== svn_cl__add
)
1771 /* In pre-1.5 Subversion, some commands treated -N like
1772 --depth=empty, so . Also, with revert it makes sense to be
1773 especially conservative, since revert can lose data. */
1774 opt_state
.depth
= svn_depth_empty
;
1778 opt_state
.depth
= SVN_DEPTH_INFINITY_OR_FILES(FALSE
);
1781 /* Create a client context object. */
1782 command_baton
.opt_state
= &opt_state
;
1783 if ((err
= svn_client_create_context(&ctx
, pool
)))
1784 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1785 command_baton
.ctx
= ctx
;
1787 err
= svn_config_get_config(&(ctx
->config
),
1788 opt_state
.config_dir
, pool
);
1791 /* Fallback to default config if the config directory isn't readable. */
1792 if (err
->apr_err
== APR_EACCES
)
1794 svn_handle_warning(stderr
, err
);
1795 svn_error_clear(err
);
1798 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1801 cfg
= apr_hash_get(ctx
->config
, SVN_CONFIG_CATEGORY_CONFIG
,
1802 APR_HASH_KEY_STRING
);
1804 /* Update the options in the config */
1805 /* XXX: Only diff_cmd for now, overlay rest later and stop passing
1806 opt_state altogether? */
1807 if (opt_state
.diff_cmd
)
1808 svn_config_set(cfg
, SVN_CONFIG_SECTION_HELPERS
,
1809 SVN_CONFIG_OPTION_DIFF_CMD
, opt_state
.diff_cmd
);
1810 if (opt_state
.merge_cmd
)
1811 svn_config_set(cfg
, SVN_CONFIG_SECTION_HELPERS
,
1812 SVN_CONFIG_OPTION_DIFF3_CMD
, opt_state
.merge_cmd
);
1814 /* Check for mutually exclusive args --auto-props and --no-auto-props */
1815 if (opt_state
.autoprops
&& opt_state
.no_autoprops
)
1817 err
= svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS
, NULL
,
1818 _("--auto-props and --no-auto-props are "
1819 "mutually exclusive"));
1820 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1823 /* The --reintegrate option is mutually exclusive with both
1824 --ignore-ancestry and --record-only. */
1825 if (opt_state
.reintegrate
)
1827 if (opt_state
.ignore_ancestry
)
1829 if (opt_state
.record_only
)
1831 err
= svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS
, NULL
,
1832 _("--reintegrate cannot be used with "
1833 "--ignore-ancestry or "
1835 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1839 err
= svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS
, NULL
,
1840 _("--reintegrate cannot be used with "
1841 "--ignore-ancestry"));
1842 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1845 else if (opt_state
.record_only
)
1847 err
= svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS
, NULL
,
1848 _("--reintegrate cannot be used with "
1850 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
1854 /* Update auto-props-enable option, and populate the MIME types map,
1855 for add/import commands */
1856 if (subcommand
->cmd_func
== svn_cl__add
1857 || subcommand
->cmd_func
== svn_cl__import
)
1859 const char *mimetypes_file
;
1860 svn_config_get(cfg
, &mimetypes_file
,
1861 SVN_CONFIG_SECTION_MISCELLANY
,
1862 SVN_CONFIG_OPTION_MIMETYPES_FILE
, FALSE
);
1863 if (mimetypes_file
&& *mimetypes_file
)
1865 if ((err
= svn_io_parse_mimetypes_file(&(ctx
->mimetypes_map
),
1866 mimetypes_file
, pool
)))
1867 svn_handle_error2(err
, stderr
, TRUE
, "svn: ");
1870 if (opt_state
.autoprops
)
1872 svn_config_set_bool(cfg
, SVN_CONFIG_SECTION_MISCELLANY
,
1873 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS
, TRUE
);
1875 if (opt_state
.no_autoprops
)
1877 svn_config_set_bool(cfg
, SVN_CONFIG_SECTION_MISCELLANY
,
1878 SVN_CONFIG_OPTION_ENABLE_AUTO_PROPS
, FALSE
);
1882 /* Update the 'keep-locks' runtime option */
1883 if (opt_state
.no_unlock
)
1884 svn_config_set_bool(cfg
, SVN_CONFIG_SECTION_MISCELLANY
,
1885 SVN_CONFIG_OPTION_NO_UNLOCK
, TRUE
);
1887 /* Set the log message callback function. Note that individual
1888 subcommands will populate the ctx->log_msg_baton3. */
1889 ctx
->log_msg_func3
= svn_cl__get_log_message
;
1891 /* Set up our cancellation support. */
1892 ctx
->cancel_func
= svn_cl__check_cancel
;
1893 apr_signal(SIGINT
, signal_handler
);
1895 /* SIGBREAK is a Win32 specific signal generated by ctrl-break. */
1896 apr_signal(SIGBREAK
, signal_handler
);
1899 apr_signal(SIGHUP
, signal_handler
);
1902 apr_signal(SIGTERM
, signal_handler
);
1906 /* Disable SIGPIPE generation for the platforms that have it. */
1907 apr_signal(SIGPIPE
, SIG_IGN
);
1911 /* Disable SIGXFSZ generation for the platforms that have it, otherwise
1912 * working with large files when compiled against an APR that doesn't have
1913 * large file support will crash the program, which is uncool. */
1914 apr_signal(SIGXFSZ
, SIG_IGN
);
1917 /* Set up Authentication stuff. */
1918 if ((err
= svn_cmdline_setup_auth_baton(&ab
,
1919 opt_state
.non_interactive
,
1920 opt_state
.auth_username
,
1921 opt_state
.auth_password
,
1922 opt_state
.config_dir
,
1923 opt_state
.no_auth_cache
,
1928 svn_handle_error2(err
, stderr
, TRUE
, "svn: ");
1930 ctx
->auth_baton
= ab
;
1932 /* Set up conflict resolution callback. */
1933 if ((err
= svn_config_get_bool(cfg
, &interactive_conflicts
,
1934 SVN_CONFIG_SECTION_MISCELLANY
,
1935 SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS
,
1936 TRUE
))) /* ### interactivity on by default.
1937 we can change this. */
1938 svn_handle_error2(err
, stderr
, TRUE
, "svn: ");
1940 if ((opt_state
.accept_which
== svn_cl__accept_unspecified
1941 && (!interactive_conflicts
|| opt_state
.non_interactive
))
1942 || opt_state
.accept_which
== svn_cl__accept_postpone
)
1944 /* If no --accept option at all and we're non-interactive, we're
1945 leaving the conflicts behind, so don't need the callback. Same if
1946 the user said to postpone. */
1947 ctx
->conflict_func
= NULL
;
1948 ctx
->conflict_baton
= NULL
;
1952 svn_cmdline_prompt_baton_t
*pb
= apr_palloc(pool
, sizeof(*pb
));
1953 pb
->cancel_func
= ctx
->cancel_func
;
1954 pb
->cancel_baton
= ctx
->cancel_baton
;
1956 if (opt_state
.non_interactive
)
1958 if (opt_state
.accept_which
== svn_cl__accept_edit
)
1959 return svn_cmdline_handle_exit_error
1960 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1961 _("--accept=%s incompatible with"
1962 " --non-interactive"), SVN_CL__ACCEPT_EDIT
),
1964 if (opt_state
.accept_which
== svn_cl__accept_launch
)
1965 return svn_cmdline_handle_exit_error
1966 (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR
, NULL
,
1967 _("--accept=%s incompatible with"
1968 " --non-interactive"),
1969 SVN_CL__ACCEPT_LAUNCH
),
1973 ctx
->conflict_func
= svn_cl__conflict_handler
;
1974 ctx
->conflict_baton
= svn_cl__conflict_baton_make(
1975 opt_state
.accept_which
,
1977 opt_state
.editor_cmd
,
1982 /* And now we finally run the subcommand. */
1983 err
= (*subcommand
->cmd_func
)(os
, &command_baton
, pool
);
1986 svn_error_t
*tmp_err
;
1988 /* For argument-related problems, suggest using the 'help'
1990 if (err
->apr_err
== SVN_ERR_CL_INSUFFICIENT_ARGS
1991 || err
->apr_err
== SVN_ERR_CL_ARG_PARSING_ERROR
)
1993 err
= svn_error_quick_wrap(err
,
1994 _("Try 'svn help' for more info"));
1996 svn_handle_error2(err
, stderr
, FALSE
, "svn: ");
1998 /* Tell the user about 'svn cleanup' if any error on the stack
1999 was about locked working copies. */
2000 for (tmp_err
= err
; tmp_err
; tmp_err
= tmp_err
->child
)
2001 if (tmp_err
->apr_err
== SVN_ERR_WC_LOCKED
)
2004 (svn_cmdline_fputs(_("svn: run 'svn cleanup' to remove locks "
2005 "(type 'svn help cleanup' for details)\n"),
2010 svn_error_clear(err
);
2011 svn_pool_destroy(pool
);
2012 return EXIT_FAILURE
;
2016 /* Ensure that stdout is flushed, so the user will see any write errors.
2017 This makes sure that output is not silently lost. */
2018 err
= svn_cmdline_fflush(stdout
);
2020 return svn_cmdline_handle_exit_error(err
, pool
, "svn: ");
2022 svn_pool_destroy(pool
);
2023 return EXIT_SUCCESS
;