import win32com.client
import pythoncom
import sys
import time
import os
import pysvn
import stat

#===============================================================================
# Global info

TYPE_PROJECT = 0
TYPE_FILE = 1

VSSFLAG_REPREPLACE = 0x00000080

# Path to SourceSafe .ini file
database = "\\Path\\to\\srcsafe.ini"

# Project to export in VSS path format
project = "$\\Path\\to\\project"

# VSS Username and Password
username = "vssuser"
password = "vsspassword"

# Path to target subversion repository
subversion = "svn://path//to//svn//project//trunk"

# Path to branch point in svn repos
subversionBranchRoot = "svn://path//to//svn//project//labels"

globals()["svnuser"] = ""
globals()["globalSvnUser"] = "vss_migration"
svnpass = ""

# True if the script should set dates in the svn repository
globals()["setDate"] = True

#===============================================================================
def GetItemPathName(item):
	root = ss.VSSItem(project).Name
	node = item.Name
	path = ""
	if item.Name != root:
		while item.Parent.Name != root:
			path = "\\" + item.Parent.Name + path
			item = item.Parent
	
	path = path + "\\" + node
	return path

#===============================================================================
def SvnLogin(realm, username, may_save):
	print "Login : %s %s" % (globals()["svnuser"], svnpass)
	return True, globals()["svnuser"].encode(), svnpass, False

#===============================================================================
def SvnCommit(logMessage, user, date):
	user = user.lower()
	if len(logMessage) == 0:
		logMessage = " "

	globals()["svn"].checkin("temp\\"+user, logMessage)
	if globals()["setDate"]:
		svndate = time.strftime("%Y-%m-%dT%H:%M:%S.0Z", time.gmtime(date))
		globals()["svn"].revpropset("svn:date", svndate, subversion)
	
#===============================================================================
def GetLabels(folder):
	labels = []
	vers = folder.Versions
	for v in vers:
		if v.Label:
			labels += [v]
	return labels

#===============================================================================
# Recursively create the files under 'folder' (which should be a VSSItem). Also
# create a temp folder structure to hold checkouts.
def CreateFileList(list, folder):

	SwitchLocalCopy(globals()["globalSvnUser"])

	if not os.access("temp\\"+globalSvnUser, os.F_OK):
		os.makedirs("temp\\"+globalSvnUser)
	
	for i in folder.Items:
		if i.Type == TYPE_PROJECT:
			path = "temp\\" + globalSvnUser + "\\" + GetItemPathName(i)
			if not os.access(path, os.F_OK):
				os.mkdir(path)
				globals()["svn"].add(path)
				globals()["svn"].checkin("temp\\" + globalSvnUser, "Created folder structure")
			list = CreateFileList(list, i)
		else:
			versionArray = []
			vers = i.Versions
			for v in vers:
				# weed out labels
				if v.Label == "":
					versionArray += [(v, False)]

			list[GetItemPathName(i)] = versionArray

	return list

#===============================================================================
# Functions required to sort our version tuple array
def cmp(a,b):
	if a < b:
		return -1
	
	if a ==b:
		return 0
	
	if a > b:
		return 1

def key(x):
	return x[2]

#===============================================================================
# Function required for SVN branching
globalLogMessage = ""
def LogMessage():
	return True, globalLogMessage.encode()

#===============================================================================

def SwitchLocalCopy(name):
	name = name.lower()
	if globals()["svnuser"] != name:
		globals()["svnuser"] = name
		del globals()["svn"]
		globals()["svn"] = pysvn.Client()
		globals()["svn"].callback_get_login = SvnLogin
		globals()["svn"].callback_get_log_message = LogMessage
		if not os.access("temp\\" + name, os.F_OK):
			os.makedirs("temp\\" + name)
		globals()["svn"].checkout(subversion, "temp\\" + name)
			

#===============================================================================

globals()["svn"] = pysvn.Client()
globals()["svn"].callback_get_login = SvnLogin
globals()["svn"].callback_get_log_message = LogMessage

print "Connecting to SourceSafe..."
ss = win32com.client.Dispatch("SourceSafe")
ss.Open(database, username, password)
item = ss.VSSItem(project)
print "\t >> %s" % project

print "Getting labels..."
labels = GetLabels(item)

print "Building file list..."
fmap = {}
fmap = CreateFileList(fmap, item)

print "Creating checkin record..."
print "\tFiles..."
checkins = []
for f in fmap:
	for vers in fmap[f]:
		x = "%s"%vers[0].Date
		d1 = time.strptime(x, "%m/%d/%y %H:%M:%S")
		z = (GetItemPathName(vers[0].VSSItem), vers[0].VersionNumber, time.mktime(d1), vers[0])
		checkins += [z]

print "\tLabels..."
for l in labels:
	x = "%s"%l.Date
	d1 = time.strptime(x, "%m/%d/%y %H:%M:%S")
	z = ("Label -> %s"%l.Label, l.VersionNumber, time.mktime(d1), l)
	checkins += [z]

print "\tSorting..."
checkins.sort(cmp, key)

print "Transferring data..."

atomicArray = []

for i in range(0, len(checkins)-1):
	if (checkins[i][2] == checkins[i+1][2]) and (checkins[i][3].Comment == checkins[i+1][3].Comment):
		if(len(atomicArray)==0):
			atomicArray += [checkins[i]]
		atomicArray += [checkins[i+1]]
	else:
		if(len(atomicArray) > 0):
			SwitchLocalCopy(atomicArray[0][3].Username)
			for a in atomicArray:
				print "\t%s [%d] >> %s" % (a[0], a[1], "temp\\"+globals()["svnuser"]+a[0])
				a[3].VSSItem.Get("temp\\"+globals()["svnuser"]+a[0], VSSFLAG_REPREPLACE)
				os.chmod("temp\\"+globals()["svnuser"]+a[0], stat.S_IRWXU)
				try:
					globals()["svn"].status(subversion+checkins[i][0])
				except:
					globals()["svn"].add("temp\\"+globals()["svnuser"]+a[0])
			del atomicArray
			atomicArray = []
			SvnCommit(a[3].Comment, a[3].Username, a[2])
		else:
			print "%s [%d]" % (checkins[i][0], checkins[i][1])
			if checkins[i][0][0:5] == "Label":
				branch = subversionBranchRoot + checkins[i][0][9:]
				globalLogMessage = checkins[i][3].LabelComment
				if globalLogMessage[:28] == "This version merged with SVN":
					globalLogMessage = " "
				print "%s->%s [%s]"%(subversion, branch, globalLogMessage)
				SwitchLocalCopy(checkins[i][3].Username)
				globals()["svn"].copy(subversion, branch)
				if globals()["setDate"]:
					svndate = time.strftime("%Y-%m-%dT%H:%M:%S.0Z", time.gmtime(checkins[i][2]))
					globals()["svn"].revpropset("svn:date", svndate, subversion)
			else:
				SwitchLocalCopy(checkins[i][3].Username)
				checkins[i][3].VSSItem.Get("temp\\"+globals()["svnuser"]+checkins[i][0], VSSFLAG_REPREPLACE)
				os.chmod("temp\\"+globals()["svnuser"]+checkins[i][0], stat.S_IRWXU)
				try:
					globals()["svn"].status(subversion+checkins[i][0])
				except:
					globals()["svn"].add("temp\\"+globals()["svnuser"]+checkins[i][0])
				SvnCommit(checkins[i][3].Comment, checkins[i][3].Username, checkins[i][2])

	
print
print " == Process Complete! =="