summaryrefslogtreecommitdiffstats
path: root/cvstogit
blob: d3fcb0eb012dbcacdee7eaa4c9b694f7539c4038 (plain)
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
#!/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="Ken Dreyer <ktdreyer@ktdreyer.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" \
		$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
		'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
			if [[ $repo == 'nonfree' ]]; 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