chiark / gitweb /
Add a "make tags" target
[stgit] / contrib / stg-cvs
1 #!/bin/bash
2 set -e
3
4 # stg-cvs - helper script to manage a mixed cvs/stgit working copy.
5
6 # Allows quick synchronization of a cvs mirror branch (does not try to
7 # reconstruct patchsets, creates "jumbo" commits), and commits stgit
8 # patches to CVS.
9
10 # Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
11 # Subject to the GNU GPL, version 2.
12
13 # NOTES
14 # - you want to add a "CVS" line to .git/info/exclude
15 # - you may want to add a ".git" line to the top .cvsignore
16
17 # LIMITATIONS
18 # - this is only a proof-of-concept prototype
19 # - lacks an "init" command
20 # - "commit" does not ensure the base is uptodate before trying to
21 #   commit (but hey, it's CVS ;)
22 # - "commit" can only commit a single patch
23 # - not much robustness here
24 # - still bad support for files removed in cvs (should catch "no
25 #   longer in the repository" message)
26 # - while fetching, if a file change was not git-update-index'd when
27 #   cvs-update'd (eg. because of a stg-cvs bug), it is not seen on further
28 #   fetches until it changes again, since we scan "cvs update" output.
29 #   This yields possible inconsistencies with CVS.
30 # - similarly, any conflict while cvs-updating (whether due to illegal
31 #   changes to the cvs-mirror-branch, or due to files added to cvs but
32 #   already-existing in working copy, or to directory moves inside the
33 #   cvs repository, or <fill here>) has to be dealt with by hand (although
34 #   the situation is better here: cvs sees the conflict on subsequent tries)
35 # - this only deals with CVS but could surely be extended to any other
36 #   VCS
37 # - bad/no support for cvsutils:
38 #   - stg push/pop operations confuse cvsu because of timestamp changes
39 #   - cvspurge/cvsco would nuke .git => does not make it easy to ensure
40 #     synchronisation
41 # - should use a separate workspace for cvs branch like tailor does
42 # - lacks synchronisation of .cvsignore <-> .gitignore
43 # - no support for filenames with spaces (stg lacks --zero output format)
44 # - git-commit is too chatty when it finds nothing to commit
45 # - lacks a "quick cvs commit" feature
46 # - confused by cvs keyword substitution
47
48 usage()
49 {
50     [ "$#" = 0 ] || echo "ERROR: $*"
51     echo "Usage: $(basename $0) <command>"
52     echo " commands: $(do_commands)"
53     exit 1
54 }
55
56 do_commands()
57 {
58     echo $(grep '^[a-z-]*)' $0 | cut -d')' -f1)
59 }
60
61 do_fetch()
62 {
63     local return=0
64     local path
65
66     local parent="$1"
67     local branch="$2"
68
69     # record changes from cvs into index
70     stg branch "$parent" || exit $?
71     cvs -fq update -dP | grep -v '^\? ' | tee /dev/tty | while read status path; do
72         if [ -e "$path" ]; then
73             git update-index --add "$path" || exit $?
74         else
75             git update-index --remove "$path" || exit $?
76         fi
77         # cvs update: `FELIN1_PEP/src/java/com/sagem/felin/ui/widget/PEPRifStateIcon.java' is no longer in the repository
78     done
79
80     # create commit
81     if git commit -m "stg-cvs sync"; then
82         :
83     else
84         return=$?
85     fi
86
87     # back to branch
88     stg branch "$branch" || exit $?
89
90     return $return
91 }
92
93 cvs_add_dir()
94 {
95     local parent=$(dirname "$1")
96     if [ ! -e "$parent/CVS" ]; then
97         cvs_add_dir "$parent"
98     fi
99
100     cvs add "$1"
101 }
102
103 # get context
104 branch=$(stg branch)
105 parent=$(git-repo-config "branch.${branch}.merge") || 
106     usage "no declared parent for '$branch' - set branch.${branch}.merge"
107
108 # extract command
109
110 [ "$#" -ge 1 ] || usage
111 command="$1"
112 shift
113
114 case "$command" in
115 fetch)
116     do_fetch "$parent" "$branch"
117     ;;
118
119 pull)
120     if do_fetch "$parent" "$branch"; then
121         # update
122         #  --merged
123         stg rebase "$parent"
124         stg clean --applied
125     fi
126     ;;
127
128 commit)
129     # sanity asserts
130     [ $(stg applied | wc -l) = 1 ] ||
131         usage "you don't have exactly one patch applied"
132
133     # context
134     patch=$(stg top)
135     
136     # adds
137     stg files | grep ^A | cut -c3- | while read file; do
138         parent=$(dirname "$file")
139         if [ ! -e "$parent/CVS" ]; then
140             cvs_add_dir "$parent"
141         fi
142         cvs -f add "$file"
143     done
144
145     # removes
146     stg files | grep ^D | cut -c3- | xargs -r cvs -f remove
147
148     # commit
149     stg files --bare | xargs -r cvs -fq commit \
150         -F ".git/patches/$branch/patches/$patch/description"
151
152     # sync the parent branch
153     stg branch "$parent"
154     git-cherry-pick "patches/${branch}/${patch}"
155     stg branch "${branch}"
156
157     # update
158     # --merged
159     stg rebase "$parent"
160     stg clean --applied
161     ;;
162
163 _commands)
164     # hint for bash-completion people :)
165     do_commands
166     ;;
167
168 *)
169     usage "unknown command '$command'"
170     ;;
171 esac