summaryrefslogblamecommitdiffstats
path: root/sync-github.py
blob: fcb1ef9d685d79facd696d02d5c2d6aca39e80a0 (plain) (tree)
1
2
3
4
5
6
7
8
                      
                            
          
         
              

           
                 












                                                                                   




                                                                                                                                                     


                                                                 
                                          


                                                                        

                                                                            

                                              





                                                                                                        









                               
                                                                  


                                                                              
        
                                                   
                                                



                                                                             
                                                                                                                                                                                             

                                 
                                                                                            
                                                                       



                                                                              
        







                                                                                                             

                                                                



                                                                                                                                                



                                
#!/usr/bin/env python2
from pygithub3 import Github
import sys
import os
import os.path
import stat
import uuid
import subprocess

class LocalRepo:
	def __init__(self, name, description, homepage, path):
		self.name = name
		self.description = description
		self.homepage = homepage
		self.path = path
	def __repr__(self):
		return "%s @ %s: %s" % (self.name, self.homepage, self.description)

def localRepos(repo_list, repo_base_dir, url_base, blacklist):
	repo_names = open(repo_list, "r")
	repos = []
	def gitSetting(repo_dir, key):
		value = subprocess.Popen(["git", "--git-dir=%s" % repo_dir, "config", "--get", key], stdout=subprocess.PIPE).communicate()[0].strip()
		if len(value) == 0:
			return None
		return value
	for repo_name in repo_names:
		repo_name = repo_name.rstrip()
		repo_dir = os.path.join(repo_base_dir, repo_name)
		repo_name = repo_name[:-4]
		description = gitSetting(repo_dir, "gitweb.description")
		homepage = gitSetting(repo_dir, "gitweb.homepage")
		if homepage == None:
			homepage = url_base + repo_name
		repo = LocalRepo(repo_name, description, homepage, repo_dir)
		if repo.name not in blacklist:
			repos.append(repo)
	def compareHeads(x, y):
		def mostRecentHeadTime(z):
			z = os.path.join(z, "refs/heads")
			return sorted([os.stat(os.path.join(z, f)).st_mtime for f in os.listdir(z)])[-1]
		return cmp(mostRecentHeadTime(x.path), mostRecentHeadTime(y.path))
	return sorted(repos, cmp=compareHeads)

def main(argv):
	if len(sys.argv) < 6:
		return 1
	user = argv[1]
	token = argv[2]
	repo_list = argv[3]
	repo_dir_base = argv[4]
	url_base = argv[5]
	
	github = Github(username=user, token=token, per_page=1000)
	
	print "[#] Collecting local repositories."
	local_repos = localRepos(repo_list, repo_dir_base, url_base, argv[6:])
	
	print "[#] Collecting remote repositories."
	remote_repos = github.repos.list().all()
	
	for repo in local_repos:
		if repo.name not in [remote.name for remote in remote_repos]:
			print "[+] Adding repository %s." % repo.name
			github.repos.create(dict(name=repo.name, description=repo.description, homepage=repo.homepage, private=False, has_issues=False, has_wiki=False, has_downloads=False))
	
	for repo in remote_repos:
		if repo.name not in [local.name for local in local_repos] and not repo.fork:
			print "[-] Deleting repository %s." % repo.name
			try:
				github.repos.delete(repo=repo.name, user=user)
			except:
				pass
	
	print "[#] Connecting to github ssh."
	control_master = os.path.abspath(os.path.dirname(__file__) + "/.ssh-control-" + str(uuid.uuid4()))
	ssh_cmd = control_master + ".cmd.sh"
	cmd_file = open(ssh_cmd, "w")
	cmd_file.write("#!/bin/sh\nexec ssh -o ControlMaster=no -o ControlPath=\"%s\" $@\n" % control_master)
	cmd_file.close()
	os.chmod(ssh_cmd, stat.S_IRWXU)	
	os.system("ssh -Nf -o ControlMaster=yes -o ControlPath=\"%s\" git@github.com" % control_master)
	for repo in local_repos:
		print "[^] Mirroring repository %s." % repo.name
		os.system("cd \"%s\"; GIT_SSH=\"%s\" git push --mirror git@github.com:%s/%s.git" % (repo.path, ssh_cmd, user, repo.name))	
	os.system("ssh -o ControlMaster=no -o ControlPath=\"%s\" -O exit -N git@github.com" % control_master)
	os.unlink(ssh_cmd)

	return 0

if __name__ == "__main__":
	sys.exit(main(sys.argv))