-
Notifications
You must be signed in to change notification settings - Fork 2
/
cvstogit
executable file
·329 lines (290 loc) · 8.76 KB
/
cvstogit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#!/bin/bash
# Convert RPM Fusion packages from CVS to Git.
# This script will convert the packages in the "free" and "nonfree" CVS
# repositories to Git. It downloads the owners.list file, and then cycles
# through each package in the list.
# The script converts each package to Git using the "git cvsimport" command.
# After "cvsimport", the branches are not usable, so we have to transform each
# subdirectory in CVS into a proper Git branch.
# The script also does some miscellaneous cleanups like moving .cvsignore to
# .gitignore and removing stray CVS files.
# Lastly the script automatically merges any branches that are identical to
# master. This allows git's fast-forward merges to work between branches.
# To skip a git-cvsimport bug triggered by a tag in the RPM Fusion dosemu
# package CVS repo, you will need the following patch to git-cvsimport:
# https://bugzilla.redhat.com/850640
# This setting is used for the conversion commit.
#AUTHOR="RPM Fusion Sysadmins <rpmfusion-sysadmin@lists.rpmfusion.org>"
AUTHOR="Nicolas Chauvet <kwizart@gmail.com>"
RF_CVSROOT=":pserver:anonymous@cvs.rpmfusion.org:/cvs"
# CVS-to-Git dist name translations.
declare -A BRANCHES
BRANCHES=(
['devel']='master'
['F-21']='f21'
['F-20']='f20'
['F-19']='f19'
['F-18']='f18'
['F-17']='f17'
['F-16']='f16'
['F-15']='f15'
['F-14']='f14'
['F-13']='f13'
['F-12']='f12'
['F-11']='f11'
['F-10']='f10'
['F-9']='f9'
['F-8']='f8'
['F-7']='f7'
['F-6']='f6'
['F-5']='f5'
['F-4']='f4'
['EL-6']='el6'
['EL-5']='el5'
['EL-4']='el4'
)
# Import a remote RPM Fusion CVS repo into a local git repo, using the
# git-cvsimport command, and writing into a "$package.cvsimport" directory. If
# the directory already exists, cvsimport will pull in any updates from the
# remote repo into the local Git version.
# Arguments:
# - RPM Fusion repo (free or nonfree)
# - RPM Fusion package (eg ffmpeg or openafs)
git_cvsimport() {
if [ -z "$1" ]; then
echo "Error: specify a repository (free or nonfree)"
exit 1
fi
repo=$1
if [ -z "$2" ]; then
echo "Error: specify a package (eg. ffmpeg)"
exit 1
fi
package=$2
# Import from CVS into a Git repository.
# TODO: use "-A <author-conv-file>" to convert authors' Unix account
# names to Git author emails.
git cvsimport -a \
-d "$RF_CVSROOT/$repo" \
-A ../rpmfusion-cvs-users.txt \
-S 'branch' \
$package \
-C "$package.cvsimport" || exit 1
}
# This function takes a raw "git-cvsimport" git repository with subdirectories,
# such as:
# openafs/
# F-12/
# F-13/
# F-14/
# and moves each subdirectory into unique Git branches, following the branch
# naming mappings in the $BRANCHES array.
# Arguments:
# - location to a git directory on disk.
convert_branches() {
if [ -z "$1" ]; then
echo "Error: specify a git repository directory"
exit 1
fi
pushd $1
# http://stackoverflow.com/questions/359424/detach-subdirectory-into-separate-git-repository
for cvsbranch in "${!BRANCHES[@]}"; do
# cvs branch name is $cvsbranch
# git branch name is ${BRANCHES["$branch"]}
gitbranch=${BRANCHES[$cvsbranch]}
# Only operate on branches that exist
if [[ ! -d $cvsbranch ]]; then
# This branch does not exist in CVS; skip it.
continue;
fi
# Debugging
echo "Converting $cvsbranch to $gitbranch"
# git-cvsimport creates an "origin" branch, and we'll use that
# as our "base" as we create our other branches.
# Create a new Git branch.
# (We can skip creating a "master" branch, because cvsimport
# already has already created one for us.
if [[ $gitbranch != 'master' ]]; then
git branch $gitbranch origin
fi
# Switch to our new branch.
git checkout $gitbranch
# Remove Makefile and branch along with moving .cvsignore to .gitignore
# Rewrite this branch, isolating the changes from this one
# directory in CVS.
git filter-branch \
--tag-name-filter cat --prune-empty --subdirectory-filter $cvsbranch \
--tree-filter 'rm -f branch Makefile ; if [ -f .cvsignore ] ; then git mv .cvsignore .gitignore ; fi' \
HEAD
# Cleanup after filter-branch.
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
# Maybe we could do these two at the end of the loop, rather than
# running after each branch?
git reflog expire --expire=now --all
git gc --aggressive --prune=now
git checkout origin
done
popd
}
# This function takes a git repository with branches, and checks each branch
# against master, and attempts to merge any identical branches into master.
# Arguments:
# - location to a git directory on disk.
merge_branches() {
if [ -z "$1" ]; then
echo "Error: specify a git repository directory"
exit 1
fi
pushd $1
# If the contents of a branch are identical to master, merge them
# together. For example:
# git checkout master
# git merge f17
# git checkout f17
# git merge master
# First part: merge any eligible $gitbranch into master.
declare -a gitbranches
declare -a mergedbranches
gitbranches=$(git branch | cut -c 3-)
for gitbranch in $gitbranches; do
# Skip these two $gitbranch's:
case $gitbranch in
'master')
# We won't be merging master with itself. Skip this one.
continue
;;
'origin')
# Don't bother the origin branch
continue
;;
esac
# Compare this $gitbranch to master.
diffs=$(git diff master..${gitbranch})
if [[ $diffs == '' ]]; then
# This $gitbranch is identical to master; merge them
# together.
git checkout master
git merge $gitbranch -m "Merge branch '$gitbranch'"
# Record this $gitbranch for later, so we can go back
# and merge master into it.
mergedbranches+=( $gitbranch )
fi
done
# Debugging
echo
echo "Found the following total branches in Git:"
echo ${gitbranches[@]}
echo "I have merged the following Git branches with master:"
echo ${mergedbranches[@]}
echo
# Second part: Now ff-merge master into all our $mergedbranches.
for gitbranch in ${mergedbranches[@]}; do
git checkout $gitbranch
# This should be a fast-forward merge.
git merge master $gitbranch
done
# We're done using the "origin" branch, so remove it.
git checkout master
git branch -D origin
popd
}
# Convert an entire RPM Fusion CVS repo tree to git modules.
# This function will write everything into a directory "$repo".
# Arguments:
# - RPM Fusion repo (free or nonfree)
do_repotree() {
if [ -z "$1" ]; then
echo "Error: specify a repository (free or nonfree)"
exit 1
fi
repo=$1
if [[ ! -d $repo ]]; then
mkdir $repo || exit 1
fi
pushd $repo
# Grab the owners.list for this repo
if [[ -d 'owners' ]]; then
# We already downloaded an owners.list. Just update it.
pushd owners
cvs up
popd
else
# Do a fresh owners.list checkout.
cvs -d "$RF_CVSROOT/$repo" co owners
fi
# Cycle through each package.
packages=$(grep -v "^#" owners/owners.list | cut -d \| -f 2)
for package in $packages; do
# Skip these packages.
case $package in
'rpmfusion-package-config-smart')
#fatal: refs/heads/origin: not a valid SHA1
continue
;;
'spek')
# Present in CVS, but cannot do a checkout.
# https://bugzilla.rpmfusion.org/2946
continue
;;
'vlc-phonon-backend')
# Invalid CVS module. "phonon-backend-vlc" is the correct one.
# https://bugzilla.rpmfusion.org/1309#c20
# https://bugzilla.rpmfusion.org/2949
continue
;;
'xmms-aac')
# Listed in free owners.list, but does not exist in CVS.
# I emailed Orcan, and he said he cannot remember this one.
# Perhaps it was orphaned and retired long ago.
# https://bugzilla.rpmfusion.org/2947
continue
;;
'slmodem')
# Present in nonfree CVS, but cannot do a checkout.
# (Similar symptoms to "spek".)
# https://bugzilla.rpmfusion.org/2946
continue
;;
'slmodem-kmod')
# Present in nonfree CVS, but cannot do a checkout.
# (Similar symptoms to "spek".)
# https://bugzilla.rpmfusion.org/2946
continue
;;
'vboxgtk')
# Listed in nonfree owners.list, but does not exist in nonfree CVS.
# Need to remove this from nonfree owners.list, and add to free list.
# https://bugzilla.rpmfusion.org/2948
continue
;;
'bsnes')
continue
;;
'xmris')
# Cannot write branch origin for update
continue
;;
*)
# Test if the directory already exists, in which case we do not convert again
if [ -d $package ] ; then
continue
fi
;;
esac
echo "Importing $repo $package"
# TODO: if git-cvsimport says "Already up-to-date.", then we don't need to
# rewrite the whole git repo again, and we can skip over the package at
# that point to save time.
git_cvsimport $repo $package
rm -rf $package
cp -r "$package.cvsimport" $package
# Do the rest of the conversion steps.
convert_branches $package
merge_branches $package
done
popd
}
do_repotree 'free'
do_repotree 'nonfree'
# vim: tabstop=2 shiftwidth=2