neartool 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. #! /usr/local/bin/bash
  2. #
  3. # neartool - a Clearcase emulator for working off-line.
  4. #
  5. # Usage:
  6. #
  7. # neartool mkelem [-c "comment"] [-nc] [-eltype type] filename
  8. # Marks a new file as a versioned element and checks it out.
  9. #
  10. # neartool mkdir [-c "comment"] [-nc] new_dir
  11. # Creates a new Clearcase directory.
  12. #
  13. # neartool mv old-file new-file
  14. # Renames or moves a versioned element.
  15. #
  16. # neartool mv file1 file2 file3 ... to-dir
  17. # Moves a number of versioned elements into a new directory.
  18. #
  19. # neartool (co|checkout) [-c "comment"] [-nc] filename
  20. # "checks out" a file by saving its current version and making a new
  21. # version writable. The file is also marked as "checked-out".
  22. #
  23. # neartool (unco|uncheckout) filename
  24. # Reverses the effect of the previous checkout.
  25. #
  26. # neartool (ci|checkin) [-c "comment"] [-nc] filename
  27. # Marks the file as "checked in" and finalizes its most recent
  28. # version, making it read-only.
  29. #
  30. # neartool revert filename
  31. # Backs up a version on a checked-in filename.
  32. #
  33. # neartool revertall filename
  34. # Reverts a filename all the way to its original state as extracted
  35. # from the Clearcase vobs.
  36. #
  37. # neartool collapse filename
  38. # Collapse all versioning information and mark the file as
  39. # "checked-in" and merged as is. Presumably this should only be
  40. # done after merging the changes back into the actual clearcase
  41. # vobs.
  42. #
  43. # neartool rmname filename
  44. # Removes a filename from a Clearcase directory.
  45. #
  46. # neartool find root [opts]
  47. # Finds all elements with versions at root or below. The options
  48. # are ignored. This is just a hack to support ctihave.
  49. #
  50. # neartool (lsco|lscheckout) [-l] file1 file2 file3...
  51. # Lists which of the files are currently checked out, if any. If no
  52. # filenames are given, lists all of the checked out files in the
  53. # current directory. The -l option is ignored.
  54. #
  55. # neartool diff [-pre] filename
  56. # Performs a diff between the indicated filename and its previous
  57. # version. The option -pre is ignored.
  58. #
  59. # neartool xdiff [-pre] filename
  60. # Performs an xdiff between the indicated filename and its previous
  61. # version. The option -pre is ignored.
  62. #
  63. #ENDCOMMENT
  64. #
  65. # get_nth_param ( param-no param1 param2 param3 ... )
  66. #
  67. # Sets the variable nth_param to the value of the parameter
  68. # corresponding to param-no.
  69. #
  70. function get_nth_param {
  71. local param_no=$1
  72. shift $param_no
  73. nth_param=$1
  74. }
  75. #
  76. # get_last_param ( param1 param2 param3 ... )
  77. #
  78. # Sets the variable last_param to the value of the last non-blank
  79. # parameter.
  80. #
  81. function get_last_param {
  82. last_param="$1"
  83. shift
  84. while [ ! -z "$*" ]; do
  85. last_param="$1"
  86. shift
  87. done
  88. }
  89. #
  90. # format_comment ( comment_str )
  91. #
  92. # Writes the parameter -c '$comment_str', or -nc if the comment is
  93. # empty, to the standard output. Handles nested quotes appropriately.
  94. #
  95. function format_comment {
  96. local comment="$*"
  97. if [ -z "$comment" ]; then
  98. echo "-nc"
  99. else
  100. # Escaping single quotes inside a single-quoted string doesn't
  101. # seem to work too reliably. Instead, we'll just remove single
  102. # quotes. So there.
  103. # This absurd number of backslashes is needed to output a single
  104. # backslash through all this nesting.
  105. # echo "-c '"`echo $comment | sed "s/'/\\\\\\\\'/g"`"'"
  106. echo "-c '"`echo $comment | sed "s/'//g"`"'"
  107. fi
  108. }
  109. #
  110. # list_comments ( dirname basename )
  111. #
  112. # Writes to stdout any comments associated with checked-out versions of
  113. # the indicated file, in order.
  114. #
  115. function list_comments {
  116. local dirname=$1
  117. local basename=$2
  118. local filename=$dirname/$basename
  119. local file comment version
  120. if [ -f $dirname/.ct0.$basename ]; then
  121. # Now look for comments, in version-number order.
  122. # We use a series of ls commands so we don't try to sort the
  123. # filenames between the one-, two-, and three-digit version
  124. # numbers.
  125. for file in `(cd $dirname; ls .ct[0-9].$basename; ls .ct[0-9][0-9].$basename; ls .ct[0-9][0-9][0-9].$basename) 2>/dev/null`; do
  126. version=`echo $file | sed "s/^\.ct\([0-9]*\).*$/\1/"`
  127. comment=$dirname/.ct${version}comment.$basename
  128. if [ -f $comment ]; then
  129. sed s'/^/ /' <$comment
  130. fi
  131. done
  132. fi
  133. }
  134. #
  135. # get_highest_version ( dirname basename )
  136. #
  137. # Sets the variable $version to the numeric value that is the highest
  138. # existing version number defined for the given filename. If the
  139. # filename has no previous version numbers, sets $version to -1.
  140. #
  141. function get_highest_version {
  142. local dirname=$1
  143. local basename=$2
  144. local filename=$dirname/$basename
  145. local last
  146. if [ -f $dirname/.ct0.$basename ]; then
  147. # If there are any versions at all, get the highest-numbered one
  148. # and return it.
  149. # We use a series of ls commands so we don't try to sort the
  150. # filenames between the one-, two-, and three-digit version
  151. # numbers.
  152. last=`(cd $dirname; ls .ct[0-9].$basename; ls .ct[0-9][0-9].$basename; ls .ct[0-9][0-9][0-9].$basename) 2>/dev/null | tail -1`
  153. version=`echo $last | sed "s/^\.ct\([0-9]*\).*$/\1/"`
  154. else
  155. # If there aren't any versions yet, the highest-numbered existing
  156. # version number is -1.
  157. version=-1
  158. fi
  159. }
  160. #
  161. # is_ctinternal ( basename )
  162. #
  163. # Returns success if the filename matches one of the internal filenames
  164. # generated by this script, failure if it is a perfectly ordinary
  165. # non-ct file.
  166. #
  167. function is_ctinternal {
  168. local basename=$1
  169. case $basename in
  170. .ct[0-9].*|ct[0-9][0-9].*|ct[0-9][0-9][0-9].*|\
  171. .ct[0-9]comment.*|.ct[0-9][0-9]comment.*|.ct[0-9][0-9][0-9]comment*|\
  172. .ctco.*|.ctnew.*)
  173. return 0;;
  174. esac
  175. return 1
  176. }
  177. #
  178. # is_install_dir ( dirname )
  179. #
  180. # Returns success if the directory is any of the directories known to
  181. # be install directories, such as inc, lib, lib/ss, etc.
  182. #
  183. function is_install_dir {
  184. local dirname=$1
  185. get_rel_dir $projroot $dirname
  186. case $rel_dir in
  187. inc) return 0;;
  188. inc/*) return 0;;
  189. include/*) return 0;;
  190. lib) return 0;;
  191. lib/*) return 0;;
  192. esac
  193. return 1
  194. }
  195. #
  196. # rm_all_ctinternals ( dirname basename )
  197. #
  198. # Removes all the ctinternal files associated with the indicated file.
  199. #
  200. function rm_all_ctinternals {
  201. local dirname=$1
  202. local basename=$2
  203. rm -f $dirname/.ct[0-9].$basename
  204. rm -f $dirname/.ct[0-9][0-9].$basename
  205. rm -f $dirname/.ct[0-9][0-9][0-9].$basename
  206. rm -f $dirname/.ct[0-9]comment.$basename
  207. rm -f $dirname/.ct[0-9][0-9]comment.$basename
  208. rm -f $dirname/.ct[0-9][0-9][0-9]comment.$basename
  209. rm -f $dirname/.ctnew.$basename
  210. rm -f $dirname/.ctco.$basename
  211. }
  212. #
  213. # sane_filename ( dirname basename )
  214. #
  215. # Performs some sanity checks on the filename. If the file is
  216. # unusable, exits the script with a status of 1.
  217. #
  218. function sane_filename {
  219. local dirname=$1
  220. local basename=$2
  221. local filename=$dirname/$basename
  222. if [ -z "$basename" ]; then
  223. echo "Filename unspecified." 1>&2
  224. exit 1
  225. fi
  226. if is_ctinternal $basename; then
  227. echo "$filename is an internal filename and should not be checked out." 1>&2
  228. exit 1
  229. fi
  230. # It's easy to accidentally attempt to check something out from the
  231. # inc directory. Let's detect this.
  232. if is_install_dir $dirname; then
  233. echo "$basename is in an install directory." 1>&2
  234. echo "It should probably not be checked out." 1>&2
  235. exit 1
  236. fi
  237. if [ -d $filename ]; then
  238. # Let's just quietly ignore directories. If we issue the warning
  239. # statement, it makes ctaddtgt and ctaddpkg seem like they're
  240. # failing.
  241. # echo "Cannot operate on directories." 1>&2
  242. exit 0
  243. fi
  244. }
  245. #
  246. # get_fullpath ( local_dir )
  247. #
  248. # Sets $fullpath to the fully-qualified pathname associated with $local_dir.
  249. #
  250. function get_fullpath {
  251. local local_dir=$1
  252. if [ -z "$local_dir" ]; then
  253. fullpath=`pwd`
  254. else
  255. if [ ! -d "$local_dir" ]; then
  256. echo "Invalid directory: $local_dir" 1>&2
  257. exit 1
  258. fi
  259. # If we use pwd instead of /bin/pwd, $PWD will be used, which will give
  260. # the wrong answer
  261. fullpath=`(cd $local_dir; /bin/pwd)`
  262. fi
  263. }
  264. #
  265. # get_rel_dir ( root_dir local_dir )
  266. #
  267. # Sets $rel_dir to the string which represents $local_dir relative to
  268. # $root_dir. This is a simple string-prefix operation, and could fail
  269. # in some obscure cases.
  270. #
  271. function get_rel_dir {
  272. get_fullpath $1
  273. local root_dir=$fullpath
  274. get_fullpath $2
  275. local local_dir=$fullpath
  276. # Now remove the initial prefix.
  277. if [ "$root_dir" = "$local_dir" ]; then
  278. rel_dir="."
  279. else
  280. rel_dir=`echo $local_dir | sed 's:^'$root_dir/'::'`
  281. if [ "$rel_dir" = "$local_dir" ]; then
  282. echo "$local_dir is not a directory within $root_dir." 1>&2
  283. exit 1
  284. fi
  285. fi
  286. }
  287. function ctmkelem {
  288. local filename dirname basename
  289. local comment eltype
  290. eltype=text_file
  291. while getopts c:n:e: flag; do
  292. case $flag in
  293. c) comment="$OPTARG";;
  294. n) comment="";;
  295. e) case $OPTARG in
  296. ltype) get_nth_param $OPTIND "$@"
  297. eltype=$nth_param
  298. OPTIND=`expr $OPTIND + 1`;;
  299. *) echo Invalid switch -e$OPTARG
  300. exit 1;
  301. esac;;
  302. \?) exit 1;
  303. esac
  304. done
  305. shift `expr $OPTIND - 1`
  306. if [ -z "$1" ]; then
  307. echo "No filenames given."
  308. exit 1
  309. fi
  310. for filename in "$@"; do
  311. dirname=`dirname $filename`
  312. basename=`basename $filename`
  313. sane_filename $dirname $basename
  314. ctco=$dirname/.ctco.$basename
  315. if [ -f $ctco ]; then
  316. echo "$filename is already checked out." 1>&2
  317. exit 1
  318. fi
  319. if [ ! -f $filename ]; then
  320. # If the file doesn't exist, create it.
  321. echo -n "" >$filename
  322. fi
  323. get_highest_version $dirname $basename
  324. if [ $version -ne -1 ]; then
  325. echo "$filename already has versions." 1>&2
  326. exit 1
  327. fi
  328. if [ ! -w $filename ]; then
  329. echo "$filename has no write permission, it's probably already a versioned element." 1>&2
  330. exit 1
  331. fi
  332. # Create a ctnew file to indicate the file is newly created.
  333. ctnew=$dirname/.ctnew.$basename
  334. echo $eltype >$ctnew
  335. chmod uga-w $ctnew
  336. # Now "check out" the new filename by creating an empty first version.
  337. next=$dirname/.ct0.$basename
  338. nextcomment=$dirname/.ct0comment.$basename
  339. if [ ! -z "$comment" ]; then
  340. echo $comment >$nextcomment
  341. chmod uga-w $nextcomment
  342. fi
  343. echo -n "" > $next
  344. date >$ctco
  345. done
  346. }
  347. function ctmkdir {
  348. local filename dirname basename
  349. local comment
  350. while getopts c:n: flag; do
  351. case $flag in
  352. c) comment="$OPTARG";;
  353. n) comment="";;
  354. \?) exit 1;
  355. esac
  356. done
  357. shift `expr $OPTIND - 1`
  358. if [ -z "$1" ]; then
  359. echo "No filenames given."
  360. exit 1
  361. fi
  362. for filename in "$@"; do
  363. dirname=`dirname $filename`
  364. basename=`basename $filename`
  365. if [ -z "$basename" ]; then
  366. echo "Filename unspecified." 1>&2
  367. exit 1
  368. fi
  369. if is_ctinternal $basename; then
  370. echo "$filename is an internal filename and should not be checked out." 1>&2
  371. exit 1
  372. fi
  373. if mkdir $filename; then
  374. # The directory is successfully made; record this in the
  375. # Clearcase instructions.
  376. get_rel_dir $projroot $dirname
  377. echo "ctco -nc $rel_dir" >>$projroot/.ctcmds
  378. echo "ctmkdir `format_comment $comment` $rel_dir/$basename" >>$projroot/.ctcmds
  379. else
  380. echo "Unable to create directory $filename." 1>&2
  381. fi
  382. done
  383. }
  384. #
  385. # do_ctmv ( oldname newname )
  386. #
  387. # The implementation of ctmv. This renames a single file, possibly
  388. # placing it in a new directory.
  389. #
  390. function do_ctmv {
  391. local oldfilename olddirname oldbasename
  392. local newfilename newdirname newbasename
  393. oldfilename=$1
  394. olddirname=`dirname $oldfilename`
  395. oldbasename=`basename $oldfilename`
  396. newfilename=$2
  397. newdirname=`dirname $newfilename`
  398. newbasename=`basename $newfilename`
  399. sane_filename $olddirname $oldbasename
  400. sane_filename $newdirname $newbasename
  401. if [ ! -f $oldfilename ]; then
  402. echo "$oldfilename does not exist." 1>&2
  403. exit 1
  404. fi
  405. if [ -f $newfilename ]; then
  406. echo "$newfilename already exists--remove it first." 1>&2
  407. exit 1
  408. fi
  409. oldctnew=$olddirname/.ctnew.$oldfilename
  410. if [ ! -f $oldctnew ]; then
  411. # The filename exists on the actual Clearcase vobs. We need to
  412. # record the renaming.
  413. get_rel_dir $projroot $olddirname
  414. local oldroot=$rel_dir
  415. get_rel_dir $projroot $newdirname
  416. local newroot=$rel_dir
  417. echo "ctco -nc $oldroot" >> $projroot/.ctcmds
  418. if [ "$oldroot" != "$newroot" ]; then
  419. echo "ctco -nc $newroot" >> $projroot/.ctcmds
  420. fi
  421. echo "ctmv $oldroot/$oldbasename $newroot/$newbasename" >> $projroot/.ctcmds
  422. fi
  423. # Now rename our local copy, and all of its version tracking stuff.
  424. get_fullpath $newdirname
  425. local newroot=$fullpath
  426. (cd $olddirname;
  427. for file in \
  428. `ls .ct[0-9].$oldbasename \
  429. .ct[0-9][0-9].$oldbasename \
  430. .ct[0-9][0-9][0-9].$oldbasename \
  431. .ct[0-9]comment.$oldbasename \
  432. .ct[0-9][0-9]comment.$oldbasename \
  433. .ct[0-9][0-9][0-9]comment.$oldbasename \
  434. .ctnew.$oldbasename \
  435. .ctco.$oldbasename \
  436. $oldbasename 2>/dev/null`; do
  437. ctprefix=`echo $file | sed 's:'$oldbasename'$::'`
  438. mv -i $file $newroot/$ctprefix$newbasename
  439. done)
  440. }
  441. function ctmv {
  442. local source destination
  443. while getopts "" flag; do
  444. case $flag in
  445. \?) exit 1;
  446. esac
  447. done
  448. shift `expr $OPTIND - 1`
  449. get_last_param "$@"
  450. destination=$last_param;
  451. if [ ! -d "$destination" ]; then
  452. # If we're not moving to a directory, we are renaming a file--and
  453. # thus we can only allow two parameters.
  454. source=$1
  455. shift 2
  456. if [ ! -z "$*" ]; then
  457. echo Last filename must be a directory.
  458. exit 1
  459. fi
  460. do_ctmv $source $destination
  461. else
  462. # Otherwise, we're moving a slew of files to a directory. Get
  463. # each filename and move it.
  464. for source in "$@"; do
  465. if [ "$source" != "$destination" ]; then
  466. do_ctmv $source $destination/$source
  467. fi
  468. done
  469. fi
  470. }
  471. function ctco {
  472. local filename dirname basename
  473. while getopts c:n: flag; do
  474. case $flag in
  475. c) comment="$OPTARG";;
  476. n) comment="";;
  477. \?) exit 1;
  478. esac
  479. done
  480. shift `expr $OPTIND - 1`
  481. if [ -z "$1" ]; then
  482. echo "No filenames given."
  483. exit 1
  484. fi
  485. for filename in "$@"; do
  486. dirname=`dirname $filename`
  487. basename=`basename $filename`
  488. sane_filename $dirname $basename
  489. okflag=y
  490. if [ ! -f $filename ]; then
  491. echo "$filename does not exist." 1>&2
  492. okflag=
  493. else
  494. ctco=$dirname/.ctco.$basename
  495. if [ -f $ctco ]; then
  496. echo "$filename is already checked out." 1>&2
  497. okflag=
  498. else
  499. if [ -w $filename ]; then
  500. echo "$filename has write permission, it's probably not a versioned element." 1>&2
  501. echo "Try neartool mkelem $filename." 1>&2
  502. okflag=
  503. fi
  504. fi
  505. fi
  506. if [ ! -z "$okflag" ]; then
  507. get_highest_version $dirname $basename
  508. next=$dirname/.ct`expr $version + 1`.$basename
  509. nextcomment=$dirname/.ct`expr $version + 1`comment.$basename
  510. if [ ! -z "$comment" ]; then
  511. echo $comment >$nextcomment
  512. chmod uga-w $nextcomment
  513. fi
  514. mv $filename $next
  515. cp $next $filename
  516. chmod ug+w $filename
  517. date >$ctco
  518. fi
  519. done
  520. }
  521. function ctunco {
  522. local ignore filename dirname basename
  523. while getopts "r:" flag; do
  524. case $flag in
  525. r) ignore=;;
  526. \?) exit 1;
  527. esac
  528. done
  529. shift `expr $OPTIND - 1`
  530. if [ -z "$1" ]; then
  531. echo "No filenames given."
  532. exit 1
  533. fi
  534. for filename in "$@"; do
  535. dirname=`dirname $filename`
  536. basename=`basename $filename`
  537. sane_filename $dirname $basename
  538. if [ ! -f $filename ]; then
  539. echo "$filename does not exist." 1>&2
  540. exit 1
  541. fi
  542. ctco=$dirname/.ctco.$basename
  543. if [ ! -f $ctco ]; then
  544. echo "$filename is not checked out." 1>&2
  545. exit 1
  546. fi
  547. get_highest_version $dirname $basename
  548. last=$dirname/.ct$version.$basename
  549. lastcomment=$dirname/.ct${version}comment.$basename
  550. mv -f $last $filename
  551. rm -f $lastcomment
  552. rm $ctco
  553. touch $filename # For emacs, and correct make behavior.
  554. done
  555. }
  556. function ctci {
  557. local filename dirname basename
  558. local comment
  559. while getopts c:n: flag; do
  560. case $flag in
  561. c) comment="$OPTARG";;
  562. n) comment="";;
  563. \?) exit 1;
  564. esac
  565. done
  566. shift `expr $OPTIND - 1`
  567. if [ -z "$1" ]; then
  568. echo "No filenames given."
  569. exit 1
  570. fi
  571. for filename in "$@"; do
  572. dirname=`dirname $filename`
  573. basename=`basename $filename`
  574. sane_filename $dirname $basename
  575. if [ ! -f $filename ]; then
  576. echo "$filename does not exist." 1>&2
  577. exit 1
  578. fi
  579. ctco=$dirname/.ctco.$basename
  580. if [ ! -f $ctco ]; then
  581. echo "$filename is not checked out." 1>&2
  582. exit 1
  583. fi
  584. # We touch the file, so emacs will note that it has changed.
  585. touch $filename
  586. chmod uga-w $filename
  587. rm $ctco
  588. done
  589. }
  590. function ctrevert {
  591. local filename dirname basename
  592. while getopts "" flag; do
  593. case $flag in
  594. \?) exit 1;
  595. esac
  596. done
  597. shift `expr $OPTIND - 1`
  598. if [ -z "$1" ]; then
  599. echo "No filenames given."
  600. exit 1
  601. fi
  602. for filename in "$@"; do
  603. dirname=`dirname $filename`
  604. basename=`basename $filename`
  605. sane_filename $dirname $basename
  606. if [ ! -f $filename ]; then
  607. echo "$filename does not exist." 1>&2
  608. exit 1
  609. fi
  610. ctco=$dirname/.ctco.$basename
  611. if [ -f $ctco ]; then
  612. echo "$filename is currently checked out. Use neartool unco $filename." 1>&2
  613. exit 1
  614. fi
  615. get_highest_version $dirname $basename
  616. if [ $version -eq -1 ]; then
  617. echo "$filename has no versions." 1>&2
  618. exit 1
  619. fi
  620. last=$dirname/.ct$version.$basename
  621. lastcomment=$dirname/.ct${version}comment.$basename
  622. mv -f $last $filename
  623. rm -f $lastcomment
  624. if [ $version -eq 0 ]; then
  625. ctnew=$dirname/.ctnew.$basename
  626. if [ -f $ctnew ]; then
  627. echo "Removing newly created element $filename." 1>&2
  628. rm -f $ctnew $filename
  629. fi
  630. fi
  631. done
  632. }
  633. function ctrevertall {
  634. local filename dirname basename
  635. while getopts "" flag; do
  636. case $flag in
  637. \?) exit 1;
  638. esac
  639. done
  640. shift `expr $OPTIND - 1`
  641. if [ -z "$1" ]; then
  642. echo "No filenames given."
  643. exit 1
  644. fi
  645. for filename in "$@"; do
  646. dirname=`dirname $filename`
  647. basename=`basename $filename`
  648. sane_filename $dirname $basename
  649. if [ ! -f $filename ]; then
  650. echo "$filename does not exist." 1>&2
  651. exit 1
  652. fi
  653. ct0=$dirname/.ct0.$basename
  654. if [ ! -f $ct0 ]; then
  655. echo "$filename has no versions." 1>&2
  656. else
  657. ctnew=$dirname/.ctnew.$basename
  658. if [ ! -f $ctnew ]; then
  659. # If we didn't newly create this file, preserve its original version.
  660. mv -f $ct0 $filename
  661. fi
  662. rm_all_ctinternals $dirname $basename
  663. fi
  664. done
  665. }
  666. function ctcollapse {
  667. local filename dirname basename
  668. while getopts "" flag; do
  669. case $flag in
  670. \?) exit 1;
  671. esac
  672. done
  673. shift `expr $OPTIND - 1`
  674. if [ -z "$1" ]; then
  675. echo "No filenames given."
  676. exit 1
  677. fi
  678. for filename in "$@"; do
  679. dirname=`dirname $filename`
  680. basename=`basename $filename`
  681. sane_filename $dirname $basename
  682. if [ ! -f $filename ]; then
  683. echo "$filename does not exist." 1>&2
  684. exit 1
  685. fi
  686. rm_all_ctinternals $dirname $basename
  687. chmod uga-w $filename
  688. touch $filename # For Emacs' benefit.
  689. done
  690. }
  691. function ctrmname {
  692. local filename dirname basename
  693. while getopts "" flag; do
  694. case $flag in
  695. \?) exit 1;
  696. esac
  697. done
  698. shift `expr $OPTIND - 1`
  699. if [ -z "$1" ]; then
  700. echo "No filenames given."
  701. exit 1
  702. fi
  703. for filename in "$@"; do
  704. dirname=`dirname $filename`
  705. basename=`basename $filename`
  706. sane_filename $dirname $basename
  707. if [ ! -f $filename ]; then
  708. echo "$filename does not exist." 1>&2
  709. exit 1
  710. fi
  711. ctnew=$dirname/.ctnew.$basename
  712. if [ ! -f $ctnew ]; then
  713. # The filename exists on the actual Clearcase vobs. We need to
  714. # record the removing.
  715. get_rel_dir $projroot $dirname
  716. local root=$rel_dir
  717. echo "ctco -nc $root" >> $projroot/.ctcmds
  718. echo "ctrm $root/$basename" >> $projroot/.ctcmds
  719. fi
  720. # Now remove all of the versioned stuff.
  721. ctcollapse $filename
  722. # And remove the file itself.
  723. rm -f $filename
  724. done
  725. }
  726. function ctfind {
  727. local root=$1
  728. if [ -z "$root" ]; then
  729. echo "Specify a starting point of the find." 1>&2
  730. exit 1
  731. fi
  732. find $root -name .ct0.\* -print | sed 's/\.ct0\.//'
  733. }
  734. function ctdescribe {
  735. local filename dirname basename
  736. while getopts "" flag; do
  737. case $flag in
  738. \?) exit 1;
  739. esac
  740. done
  741. shift `expr $OPTIND - 1`
  742. if [ -z "$1" ]; then
  743. echo "No filenames given."
  744. exit 1
  745. fi
  746. for filename in `ls "$@"`; do
  747. dirname=`dirname $filename`
  748. basename=`basename $filename`
  749. ctco=$dirname/.ctco.$basename
  750. get_highest_version $dirname $basename
  751. version=`expr $version + 1`
  752. if [ -f $ctco ]; then
  753. if [ $version -eq 0 ]; then
  754. echo "$filename is checked out with no versions."
  755. else
  756. echo "$filename is checked out as version $version."
  757. list_comments $dirname $basename
  758. fi
  759. else
  760. if [ $version -eq 0 ]; then
  761. echo "$filename has not been checked out and has no versions."
  762. else
  763. echo "$filename is checked in as version $version."
  764. list_comments $dirname $basename
  765. fi
  766. fi
  767. done
  768. }
  769. function ctlsco {
  770. local filename dirname basename
  771. local ignore
  772. while getopts "l" flag; do
  773. case $flag in
  774. l) ignore=;;
  775. \?) exit 1;
  776. esac
  777. done
  778. shift `expr $OPTIND - 1`
  779. for filename in `ls "$@"`; do
  780. dirname=`dirname $filename`
  781. basename=`basename $filename`
  782. ctco=$dirname/.ctco.$basename
  783. if [ -f $ctco ]; then
  784. ctdescribe $filename
  785. fi
  786. done
  787. }
  788. function ctdiff {
  789. local filename dirname basename
  790. local graphical
  791. local ignore
  792. local diff
  793. while getopts "gp:" flag; do
  794. case $flag in
  795. g) graphical=y;;
  796. p) ignore=;;
  797. \?) exit 1;
  798. esac
  799. done
  800. shift `expr $OPTIND - 1`
  801. diff=diff
  802. if [ $graphical ]; then
  803. # The user requested a graphical difference; use gdiff if we can
  804. # find it. Otherwise, fall back to diff.
  805. if which gdiff 2>/dev/null >/dev/null; then
  806. diff=gdiff
  807. fi
  808. fi
  809. if [ -z "$1" ]; then
  810. echo "No filenames given."
  811. exit 1
  812. fi
  813. for filename in "$@"; do
  814. dirname=`dirname $filename`
  815. basename=`basename $filename`
  816. sane_filename $dirname $basename
  817. if [ ! -f $filename ]; then
  818. echo "$filename does not exist." 1>&2
  819. exit 1
  820. fi
  821. get_highest_version $dirname $basename
  822. if [ $version -eq -1 ]; then
  823. echo "$filename has no versions." 1>&2
  824. exit 1
  825. fi
  826. last=$dirname/.ct$version.$basename
  827. # First, call diff (the real diff) just to see if the files are
  828. # different at all.
  829. if diff $last $filename >/dev/null; then
  830. echo Files are identical.
  831. else
  832. # If the files ARE different, then invoke diff again (which
  833. # might be gdiff, this time) to actually report the differences.
  834. # We must do it twice like this because gdiff might not return
  835. # non-zero if the files are different.
  836. $diff $last $filename
  837. fi
  838. done
  839. }
  840. function usage {
  841. sed '/#ENDCOMMENT/,$d' <$0 >&2
  842. exit 1
  843. }
  844. #
  845. # Main entry point
  846. #
  847. command=$1
  848. if [ -z "$command" ]; then
  849. usage
  850. fi
  851. shift
  852. projroot=`ctproj -r`
  853. if [ -z "$projroot" ]; then
  854. echo "Not currently in a project tree." 1>&2
  855. exit 1
  856. fi
  857. case $command in
  858. mkelem) ctmkelem "$@";;
  859. mkdir) ctmkdir "$@";;
  860. mv) ctmv "$@";;
  861. co|checkout) ctco "$@";;
  862. unco|uncheckout) ctunco "$@";;
  863. ci|checkin) ctci "$@";;
  864. revert) ctrevert "$@";;
  865. revertall) ctrevertall "$@";;
  866. collapse) ctcollapse "$@";;
  867. rmname) ctrmname "$@";;
  868. find) ctfind "$@";;
  869. lsco|lscheckout) ctlsco "$@";;
  870. describe) ctdescribe "$@";;
  871. diff) ctdiff "$@";;
  872. xdiff) ctdiff -g "$@";;
  873. h|help|-h) usage;;
  874. *) echo "Invalid option: $command" 1>&2
  875. exit 1;
  876. esac