cvs2svn-migration/trunk: README mirror post_cvs2svn

saq cvs at pld-linux.org
Sat Oct 8 20:13:47 CEST 2005


Author: saq
Date: Sat Oct  8 20:13:22 2005
New Revision: 6436

Added:
   cvs2svn-migration/trunk/mirror   (contents, props changed)
Modified:
   cvs2svn-migration/trunk/README
   cvs2svn-migration/trunk/post_cvs2svn
Log:
- the have-traditional-SPECS hook

Modified: cvs2svn-migration/trunk/README
==============================================================================
--- cvs2svn-migration/trunk/README	(original)
+++ cvs2svn-migration/trunk/README	Sat Oct  8 20:13:22 2005
@@ -6,7 +6,8 @@
 2. Use migrator to reorganize the repo according to the dir-per-package scheme
 3. Perform some manual clean-ups.
 4. Use invoke_cvs2svn to generate svn entries and revisions.
-5. Use post_cvs2svn to reorganize the repo into $package/{trunk,tags,branches}.
+5. Use post_cvs2svn to install the hooks and reorganize the repo into
+   $package/{trunk,tags,branches}.
 6. Perform some manual clean-ups.
 7. Celebrate.
 
@@ -60,7 +61,9 @@
 
 Changes to the development environment:
 
-- topdir/S{PEC,OURCE}S are no more. topdir/{BUILD,{,S}RPMS} will stay there
+- topdir/SOURCES is no more. topdir/{BUILD,{,S}RPMS} will stay there
+- You can use topdir/SPECS the usual (deprecated) way. It is syncked with
+  the specs placed in packages' dirs.
 - topdir/foo looks like the right checkout spot for foo.spec and its sources
 - topdir/foo/foo-0.00.tar for distfiles
 - need new macros to find the sources in the new place

Added: cvs2svn-migration/trunk/mirror
==============================================================================
--- (empty file)
+++ cvs2svn-migration/trunk/mirror	Sat Oct  8 20:13:22 2005
@@ -0,0 +1,178 @@
+#!/usr/bin/python
+
+# SVN change mirrorer
+#
+# To make sure that two different paths in the repo carry the same contents.
+#
+# Usage:
+# $0 repo --pre txn
+#	sanity checks
+# $0 repo --post rev
+#	actual mirroring (if necessary)
+
+# Known bugs:
+# - removing a spec-containing directory (at any depth) isn't mirrored by
+#   removing the spec in the other location
+# - same with moving
+# - maybe SPECS/tags isn't really useful/necessary
+
+import os
+import re
+import sys
+import traceback
+
+from svn import core,fs,delta,repos
+
+# You may call these the "config" if you please
+
+place1_re=re.compile(r"^([^/]*)/(.*)/([^/]*)\.spec") # \1==\3==spec, \2==tag
+def match_place1(path):
+	match=place1_re.match(path)
+	if match is None: return None,None
+	if match.group(1)!=match.group(3): return None,None
+	return match.group(1),match.group(2)
+place2_re=re.compile(r"SPECS/(.*)/([^/]*)\.spec") # \1==tag, \2==spec
+def match_place2(path):
+	match=place2_re.match(path)
+	if match is None: return None,None
+	return match.group(2),match.group(1)
+
+def match_place(path):
+	spec,tag=match_place1(path)
+	if spec is not None: return 1,spec,tag
+	spec,tag=match_place2(path)
+	if spec is not None: return 2,spec,tag
+	return None,None,None
+def locations(spec,tag):
+	return ["%s/%s/%s.spec"%(spec,tag,spec),"SPECS/%s/%s.spec"%(tag,spec)]
+def trust_change(props):
+	log=props('svn:log')
+	author=props('svn:author')
+	# don't mirror mirror commits
+	if author=="mirror": return True
+	# I Know What I'm Doing
+	return author=="saq" and "IKWID" in log
+
+# go
+
+log=file("/home/users/saq/tmp/mirror.log.%d"%(os.getpid(),),"w")
+print >>log,"Starting",sys.argv
+
+class Txn:
+	def __init__(self,repo,rev,uname,commitmsg):
+		self.repo=repo
+		self.txn=repos.fs_begin_txn_for_commit(self.repo.repo,rev,uname,commitmsg,self.repo.pool)
+		self.base_root=self.repo.rev_root(rev)
+		self.root=fs.txn_root(self.txn,self.repo.pool)
+	def delete(self,path):
+		print >>log,"Deleting",path
+		fs.delete(self.root,path,self.repo.pool)
+	def mkdirs(self,path):
+		dir=path.rsplit("/",1)[0]
+		if dir==path: return
+		if fs.check_path(self.root,dir,self.repo.pool)==core.svn_node_none:
+			self.mkdirs(dir)
+			print >>log,"Mkdiring",dir
+			fs.make_dir(self.root,dir,self.repo.pool)
+	def copy(self,path_from,path_to):
+		if path_from==path_to: return
+		if fs.check_path(self.root,path_to,self.repo.pool)!=core.svn_node_none:
+			self.delete(path_to)
+		else:
+			self.mkdirs(path_to)
+		print >>log,"Copying",path_from,"to",path_to
+		fs.copy(self.base_root,path_from,self.root,path_to,self.repo.pool)
+		contents=self.repo.contents(path_from,root=self.root)
+		handler,baton=fs.apply_textdelta(self.root,path_to,None,None,self.repo.pool)
+		delta.svn_txdelta_send_string(contents,handler,baton,self.repo.pool)
+	def commit(self):
+		rev=repos.fs_commit_txn(self.repo.repo,self.txn,self.repo.pool)
+		print >>log,"Committed revision",rev
+
+class Repo:
+	def __init__(self,path,pool):
+		self.repo=repos.open(path,pool)
+		self.fs=repos.fs(self.repo)
+		self.pool=pool
+		self.roots={}
+	def txn_root(self,txn_name):
+		return fs.txn_root(fs.open_txn(self.fs,txn_name,self.pool),self.pool)
+	def rev_root(self,rev_no):
+		try:
+			return self.roots[rev_no]
+		except KeyError:
+			root=fs.revision_root(self.fs,rev_no,self.pool)
+			self.roots[rev_no]=root
+			return root
+	def txn_props(self,txn_name):
+		txn=fs.open_txn(self.fs,txn_name,self.pool)
+		def props(name):
+			return fs.txn_prop(txn,name,self.pool)
+		return props
+	def rev_props(self,rev_no):
+		def props(name):
+			return fs.revision_prop(self.fs,rev_no,name,self.pool)
+		return props
+	def changes(self,root):
+		collector=repos.ChangeCollector(self.fs,root,self.pool)
+		editor,editor_baton=delta.make_editor(collector,self.pool)
+		repos.replay(root,editor,editor_baton,self.pool)
+		return collector.get_changes()
+	def contents(self,path,rev=None,root=None):
+		if root is None:
+			if rev==-1: return None # file never existed
+			root=self.rev_root(rev)
+		subpool=core.svn_pool_create(self.pool)
+		try:
+			stream=core.Stream(fs.file_contents(root,path,subpool))
+			return stream.read()
+		finally:
+			core.svn_pool_destroy(subpool)
+
+def main(pool):
+	repo=Repo(sys.argv[1],pool)
+	if sys.argv[2]=="--pre":
+		root=repo.txn_root(sys.argv[3])
+		props=repo.txn_props(sys.argv[3])
+		mirror=False
+	elif sys.argv[2]=="--post":
+		created_rev=int(sys.argv[3])
+		root=repo.rev_root(created_rev)
+		props=repo.rev_props(created_rev)
+		mirror=True
+	else:
+		sys.exit("Illegal usage")
+	if trust_change(props):
+		print >>log,"This change is trusted, not mangling"
+		return
+	changes={}
+	for path,change in repo.changes(root).iteritems():
+		place,spec,tag=match_place(path)
+		if place is None: continue
+		if (spec,tag) in changes:
+			sys.exit("Two different changes for %s at %s"%(spec,tag))
+		changes[(spec,tag)]=place,change
+	for (spec,tag),(place,change) in changes.iteritems():
+		variants=set([repo.contents(path,rev=change.base_rev) for path in locations(spec,tag)])
+		if len(variants)!=1:
+			sys.exit("Differences before transaction amongst "+repr(locations(spec,tag)))
+		del variants # garbage collect it asap
+	if not mirror: return
+	if len(changes)==0:
+		print >>log,"No changes in specs"
+		return
+	txn=Txn(repo,created_rev,"mirror","- resync")
+	for (spec,tag),(place,change) in changes.iteritems():
+		for path in locations(spec,tag):
+			if change.path is None:
+				if path!=change.base_path: txn.delete(path)
+			else:
+				txn.copy(change.path,path)
+	txn.commit()
+	
+try:
+	core.run_app(main)
+except:
+	# TODO mail somebody if this is reached on --post (need manual care)
+	traceback.print_exc(file=log)
+	raise

Modified: cvs2svn-migration/trunk/post_cvs2svn
==============================================================================
--- cvs2svn-migration/trunk/post_cvs2svn	(original)
+++ cvs2svn-migration/trunk/post_cvs2svn	Sat Oct  8 20:13:22 2005
@@ -41,9 +41,21 @@
 	echo "$in_tags$in_branches"|tr \  \\n|grep "^$1/[^/]*/$2\$"
 }
 
-ls
+mirror() {
+	if [ "$1" = "SOURCES.old" -o "$1" = "SPECS.old" ]; then
+		return
+	fi
+	SVN mkdir $root/SPECS/$2
+	SVN cp $root/$1/$2/$1.spec $root/SPECS/$2/$1.spec
+}
 
 echo "1. Moving */foo to foo/*"
+echo "If you see that /SPECS/some_dir already exists, that's fine"
+echo "Same with 'some_spec does not exist'"
+# the latter being another sign of the PLD mess
+ls
+
+SVN mkdir $root/SPECS{,/trunk,/tags,/branches}
 for pkgdir in $in_trunk $in_tags $in_branches; do
 	pkg=$(echo $pkgdir|sed s,.*/,,)
 	pkg_for_var=$(echo $pkg|tr .+- ___)
@@ -54,12 +66,14 @@
 	SVN mkdir $root/$pkg
 	if [ "$pkgdir" = "trunk/$pkg" ]; then
 		SVN mv $root/trunk/$pkg $root/$pkg/trunk
+		mirror $pkg trunk
 	fi
 	if have tags $pkg; then
 		SVN mkdir $root/$pkg/tags
 		for dir in $(matching tags $pkg); do
 			name=$(echo $dir|cut -d/ -f2)
 			SVN mv $root/$dir $root/$pkg/tags/$name
+			mirror $pkg tags/$name
 		done
 	fi
 	if have branches $pkg; then
@@ -67,6 +81,7 @@
 		for dir in $(matching branches $pkg); do
 			name=$(echo $dir|cut -d/ -f2)
 			SVN mv $root/$dir $root/$pkg/branches/$name
+			mirror $pkg branches/$name
 		done
 	fi
 done
@@ -80,3 +95,16 @@
 fi
 # damn lucky there are no packages by these names
 SVN rm $root/{trunk,tags,branches}
+
+echo "3. Installing hooks"
+cp mirror $svndir/hooks
+cat>$svndir/hooks/pre-commit<<EOF
+#!/bin/sh
+$svndir/hooks/mirror "\$1" --pre "\$2"
+EOF
+cat>$svndir/hooks/post-commit<<EOF
+#!/bin/sh
+$svndir/hooks/mirror "\$1" --post "\$2"
+EOF
+chmod 755 $svndir/hooks/p{re,ost}-commit
+



More information about the pld-cvs-commit mailing list