mirror of
https://github.com/kennethreitz-archive/.com.git
synced 2026-06-21 07:40:58 +00:00
268 lines
7.8 KiB
HTML
268 lines
7.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>GitHub Syncer in Python</title>
|
|
<meta charset="utf-8" />
|
|
<link rel="stylesheet" href="./theme/css/main.css" type="text/css" />
|
|
<link href="./feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Kenneth's log ATOM Feed" />
|
|
|
|
|
|
|
|
|
|
<!--[if IE]>
|
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
|
|
|
|
<!--[if lte IE 7]>
|
|
<link rel="stylesheet" type="text/css" media="all" href="./css/ie.css"/>
|
|
<script src="./js/IE8.js" type="text/javascript"></script><![endif]-->
|
|
|
|
<!--[if lt IE 7]>
|
|
<link rel="stylesheet" type="text/css" media="all" href="./css/ie6.css"/><![endif]-->
|
|
|
|
</head>
|
|
|
|
<body id="index" class="home">
|
|
|
|
<a href="http://github.com/kennethreitz/">
|
|
|
|
<img style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png" alt="Fork me on GitHub" />
|
|
|
|
</a>
|
|
|
|
<header id="banner" class="body">
|
|
<h1>
|
|
<a href=".">Kenneth's log </a>
|
|
</h1>
|
|
|
|
<nav><ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li >
|
|
<a href="./category/Life.html">Life</a>
|
|
</li>
|
|
|
|
<li >
|
|
<a href="./category/Code.html">Code</a>
|
|
</li>
|
|
|
|
<li class="active">
|
|
<a href="./category/projects.html">projects</a>
|
|
</li>
|
|
|
|
|
|
</ul></nav>
|
|
|
|
</header><!-- /#banner -->
|
|
|
|
|
|
<section id="content" class="body">
|
|
<article>
|
|
<header> <h1 class="entry-title"><a href="github-syncer-in-python.html"
|
|
rel="bookmark" title="Permalink to GitHub Syncer in Python">GitHub Syncer in Python</a></h1> </header>
|
|
|
|
|
|
|
|
<p>Today I rewrote a little utility I've been using for a while to
|
|
keep all of my GitHub repos up to date and organized. It updates /
|
|
clones all private, public, and watched repositories from your
|
|
account. It also detects if your repo is a mirror or fork, and
|
|
files it accordingly. My watched list is huge, but I like to have a
|
|
local copy of my favorite libraries. You never know if the owner
|
|
will take it down, or worse, move it to another SCM! ;-) The script
|
|
depends on the <strong>GitHub2</strong> module. If you don't have it, you
|
|
can install it easily.:</p>
|
|
<pre class="literal-block">
|
|
$ pip install github2
|
|
</pre>
|
|
<p>I recommend running this from <tt class="docutils literal">~/repos/</tt>.</p>
|
|
<dl class="docutils">
|
|
<dt>::</dt>
|
|
<dd><p class="first">#!/usr/bin/env python #
|
|
-<em>- coding: utf-8 -</em>-</p>
|
|
<p>"""Kenneth Reitz's GitHub Syncer</p>
|
|
<p>This script uses the GitHub API to get a list of all forked, mirrored, public, and
|
|
private repos in your GitHub account. If the repo already exists locally, it will
|
|
update it via git-pull. Otherwise, it will properly clone the repo.</p>
|
|
<p>It will organize your repos into the following directory structure:</p>
|
|
<ul class="simple">
|
|
<li>repos
|
|
├── forks (public fork repos)
|
|
├── mirrors (public mirror repos)
|
|
├── private (private repos)
|
|
├── public (public repos)
|
|
├── watched (this script)
|
|
└── sync.py (this script)</li>
|
|
</ul>
|
|
<p>Requires Ask Solem's github2 (<a class="reference external" href="http://pypi.python.org/pypi/github2">http://pypi.python.org/pypi/github2</a>).</p>
|
|
<p>Inspired by Gisty (<a class="reference external" href="http://github.com/swdyh/gisty">http://github.com/swdyh/gisty</a>).
|
|
"""</p>
|
|
<p>import os
|
|
from commands import getoutput as cmd</p>
|
|
<p>from github2.client import Github</p>
|
|
<p># GitHub configurations
|
|
GITHUB_USER = cmd('git config github.user')
|
|
GITHUB_TOKEN = cmd('git config github.token')</p>
|
|
<p># API Object
|
|
github = Github(username=GITHUB_USER, api_token=GITHUB_TOKEN)</p>
|
|
<p># repo slots
|
|
repos = {}</p>
|
|
<p>repos['watched'] = [r for r in github.repos.watching(GITHUB_USER)]
|
|
repos['private'] = []
|
|
repos['mirrors'] = []
|
|
repos['public'] = []
|
|
repos['forks'] = []</p>
|
|
<p># Collect GitHub repos via API
|
|
for repo in github.repos.list():</p>
|
|
<blockquote>
|
|
<dl class="docutils">
|
|
<dt>if repo.private:</dt>
|
|
<dd>repos['private'].append(repo)</dd>
|
|
<dt>elif repo.fork:</dt>
|
|
<dd>repos['forks'].append(repo)</dd>
|
|
<dt>elif 'mirror' in repo.description.lower():</dt>
|
|
<dd># mirrors owned by self if mirror in description...
|
|
repos['mirrors'].append(repo)</dd>
|
|
<dt>else:</dt>
|
|
<dd>repos['public'].append(repo)</dd>
|
|
</dl>
|
|
</blockquote>
|
|
<dl class="last docutils">
|
|
<dt>for org, repos in repos.iteritems():</dt>
|
|
<dd><p class="first">for repo in repos:</p>
|
|
<blockquote class="last">
|
|
<p># create org directory (safely)
|
|
try:</p>
|
|
<div class="system-message">
|
|
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils"><string></tt>, line 88)</p>
|
|
Unexpected indentation.</div>
|
|
<blockquote>
|
|
os.makedirs(org)</blockquote>
|
|
<div class="system-message">
|
|
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 89)</p>
|
|
Block quote ends without a blank line; unexpected unindent.</div>
|
|
<dl class="docutils">
|
|
<dt>except OSError:</dt>
|
|
<dd>pass</dd>
|
|
</dl>
|
|
<p># enter org dir
|
|
os.chdir(org)</p>
|
|
<p># I own the repo
|
|
private = True if org in ('private', 'fork', 'mirror') else False</p>
|
|
<p># just <cite>git pull</cite> if it's already there
|
|
if os.path.exists(repo.name):</p>
|
|
<div class="system-message">
|
|
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils"><string></tt>, line 100)</p>
|
|
Unexpected indentation.</div>
|
|
<blockquote>
|
|
os.chdir(repo.name)
|
|
print('Updating repo: %s' % (repo.name))
|
|
os.system('git pull')
|
|
os.chdir('..')</blockquote>
|
|
<div class="system-message">
|
|
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 104)</p>
|
|
Block quote ends without a blank line; unexpected unindent.</div>
|
|
<dl class="docutils">
|
|
<dt>else:</dt>
|
|
<dd><dl class="first last docutils">
|
|
<dt>if private:</dt>
|
|
<dd>print('Cloning private repo: %s' % (repo.name))
|
|
os.system('git clone <a class="reference external" href="mailto:git@github.com">git@github.com</a>:%s/%s.git' % (repo.owner, repo.name))</dd>
|
|
<dt>else:</dt>
|
|
<dd>print('Cloning repo: %s' % (repo.name))
|
|
os.system('git clone git://github.com/%s/%s.git' % (repo.owner, repo.name))</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
<p># return to base
|
|
os.chdir('..')
|
|
print</p>
|
|
</blockquote>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
<p><a class="reference external" href="http://gist.github.com/619473">Source on GitHub</a> Enjoy!</p>
|
|
|
|
</div><!-- /.entry-content -->
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</section>
|
|
|
|
|
|
<section id="extras" class="body">
|
|
|
|
|
|
<div class="blogroll">
|
|
<h2>Links</h2>
|
|
<ul>
|
|
|
|
<li><a href="http://github.com/kennethreitz">GitHub Repos</a></li>
|
|
|
|
<li><a href="http://flickr.com/kennethreitz">Photography (Flickr)</a></li>
|
|
|
|
<li><a href="http://twitter.com/kennethreitz">Latest Tweets</a></li>
|
|
|
|
<li><a href="http://www.linkedin.com/in/kennethreitz">Résumé</a></li>
|
|
|
|
<li><a href="http://pick.im/kenneth-reitz">Design Portfolio</a></li>
|
|
|
|
<li><a href="http://laterstars.com/kennethreitz">Later Stars</a></li>
|
|
|
|
</ul>
|
|
</div><!-- /.blogroll -->
|
|
|
|
|
|
|
|
<div class="social">
|
|
|
|
<ul>
|
|
<li><a href="./feeds/all.atom.xml" rel="alternate">atom feed</a></li>
|
|
|
|
|
|
|
|
<li><a href="http://facebook.com/kennethreitz">Facebook</a></li>
|
|
|
|
</ul>
|
|
</div><!-- /.social -->
|
|
|
|
|
|
</section><!-- /#extras -->
|
|
|
|
<footer id="contentinfo" class="body">
|
|
<address id="about" class="vcard body">
|
|
© 2011 Kenneth Reitz & co. All Rights Reserved.
|
|
</address><!-- /#about -->
|
|
|
|
</footer><!-- /#contentinfo -->
|
|
|
|
|
|
|
|
<script type="text/javascript">
|
|
var disqus_shortname = 'kennethreitz';
|
|
(function () {
|
|
var s = document.createElement('script'); s.async = true;
|
|
s.type = 'text/javascript';
|
|
s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
|
|
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
|
|
}());
|
|
</script>
|
|
<script type="text/javascript" charset="utf-8">
|
|
var disqus_developer = 1;
|
|
</script>
|
|
|
|
</body>
|
|
</html> |