Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0a7ac88

Browse files
author
Alex Sparrow
committed
Big restructuring
Trying to make it resemble a real Python package. Learning distutils as I go.
1 parent 0eddfed commit 0a7ac88

File tree

9 files changed

+178
-11
lines changed

9 files changed

+178
-11
lines changed
File renamed without changes.
File renamed without changes.

gitwalker/__init__.py

Whitespace-only changes.
File renamed without changes.

gitwalker/git.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import subprocess
2+
import os.path
3+
from datetime import datetime
4+
5+
from util import get_output
6+
7+
def git_cmd(path, *args, **kwargs):
8+
repo = os.path.join(path, ".git")
9+
return get_output(["git", "--git-dir", repo, "--work-tree", path]+list(args), **kwargs)
10+
11+
def git_clone(path, target):
12+
get_output(["git", "clone", path, target])
13+
14+
def git_log(path):
15+
outp = git_cmd(path, "rev-list", "--date=iso", "--all", "--pretty=medium")
16+
out = {}
17+
for l in outp.splitlines():
18+
if l.startswith("commit"): out["commit"] = l.split()[1]
19+
elif l.startswith("Author"): out["author"] = l.split(":")[1].strip().rstrip()
20+
elif l.startswith("Date"):
21+
out["date"] = datetime.strptime(l.split(":",1)[1].split("+")[0].strip().rstrip(), "%Y-%m-%d %H:%M:%S")
22+
if "commit" in out and "author" in out and "date" in out:
23+
yield out
24+
out = {}
25+
26+
def git_checkout(path, commit):
27+
git_cmd(path, "checkout", commit, stderr=subprocess.PIPE)

gitwalker/main.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import sys, json, shutil, tempfile, pprint, optparse
2+
from tools import CmdError, word_count, du
3+
from datetime import datetime
4+
from util import log
5+
from git import git_clone, git_log, git_checkout
6+
7+
def setupCmdLine(cmds):
8+
parser = optparse.OptionParser()
9+
parser.add_option("--in", action="append", type="str",
10+
default = [],
11+
dest = "in_paths", help="Read JSON file")
12+
parser.add_option("--out", action="store", type="str",
13+
dest="out_path",
14+
default="out.json", help="Output JSON file")
15+
parser.add_option("--reload", action="store_true", help="Refetch info")
16+
parser.add_option("--debug", action="store_true", help="Debug commands")
17+
cmdgroup = optparse.OptionGroup(parser, "Commands", "Command codes")
18+
for c in cmds:
19+
opt = c.primary_opt()
20+
opt.kwargs["default"] = None
21+
opt.kwargs["dest"] = c.name
22+
cmdgroup.add_option("--%s" % c.name, *opt.args, **opt.kwargs)
23+
parser.add_option_group(cmdgroup)
24+
return parser
25+
26+
def main():
27+
cmds = [word_count, du]
28+
parser = setupCmdLine(cmds)
29+
opts, args = parser.parse_args()
30+
try: git_repo = args[0]
31+
except:
32+
parser.print_usage()
33+
sys.exit(1)
34+
runlist = []
35+
for c in cmds:
36+
runcmd = getattr(opts, c.name, None)
37+
if runcmd:
38+
runlist.append(c(runcmd, debug=opts.debug))
39+
if len(runlist) == 0:
40+
print "Must specify a command to be run"
41+
sys.exit(0)
42+
out = {}
43+
for in_path in opts.in_paths:
44+
d = json.load(open(in_path, "r"))
45+
for commit, vals in d.iteritems():
46+
if not commit in out: out[commit] = vals
47+
else: out[commit]["results"].update(vals["results"])
48+
49+
try:
50+
git_new = tempfile.mkdtemp()
51+
log("Temp dir created: %s", git_new)
52+
log("Cloning repo: %s -> %s", git_repo, git_new)
53+
git_clone(git_repo, git_new)
54+
commits = list(git_log(git_new))
55+
log("%d commits found" % len(commits))
56+
for idx, comm in enumerate(commits):
57+
sha1 = comm["commit"]
58+
if sha1 in out:
59+
rec = out[sha1]
60+
else:
61+
rec = {
62+
"date" : comm["date"].strftime("%d/%m/%Y"),
63+
"author" : comm["author"],
64+
"results" : {}
65+
}
66+
if opts.reload: schedule = runlist
67+
else: schedule = [cmd for cmd in runlist if cmd.name not in rec["results"]]
68+
if len(schedule) == 0:
69+
log("Skipping revision %s [%d/%d]", comm["commit"], idx+1, len(commits))
70+
continue
71+
log("Checking out revision %s [%d/%d]", comm["commit"], idx+1, len(commits))
72+
git_checkout(git_new, sha1)
73+
74+
for cmd in schedule:
75+
rec["results"][cmd.name] = {}
76+
try: rec["results"][cmd.name] = cmd.run(git_new)
77+
except CmdError,e:
78+
log("Command '%r' failed with %d", e.cmd, e.ret)
79+
log("Output: %s", e.out)
80+
except Exception, e:
81+
log("Failed to get output of command: %r",e)
82+
log("[%s] %s", cmd.name, pprint.pformat(rec["results"][cmd.name]))
83+
out[sha1] = rec
84+
85+
log("Writing output file: %s", opts.out_path)
86+
json.dump(out, open(opts.out_path, "w"), indent=1)
87+
except CmdError, e:
88+
print "Command '%r' failed with %d" % (e.cmd, e.ret)
89+
finally:
90+
log("Tidying temp dir: %s", git_new)
91+
shutil.rmtree(git_new)
92+
93+
if __name__ == "__main__":
94+
main()

tools.py renamed to gitwalker/tools.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
from util import log, CmdError, get_output
1+
from util import log, get_output
22
import os.path
33

4+
script_dir = os.path.dirname(os.path.realpath(__file__))
5+
tex_count_path = os.path.normpath(os.path.join(script_dir, "bin/texcount.pl"))
6+
47
class Func:
58
def __init__(self, *args, **kwargs):
69
self.args = args
@@ -9,6 +12,10 @@ def __init__(self, *args, **kwargs):
912
class Cmd(object):
1013
def __init__(self, val): pass
1114

15+
class CmdError(Exception):
16+
def __init__(self, ret, cmd, out): self.ret, self.cmd, self.out = ret, cmd, out
17+
18+
1219
class du(Cmd):
1320
name = "du"
1421
@staticmethod
@@ -26,13 +33,12 @@ def primary_opt():
2633
return Func(action="store", type="str", metavar="TEXFILE",
2734
help="Word count a TeX file")
2835

29-
def __init__(self, fname):
36+
def __init__(self, fname, debug=False, *args, **kwargs):
3037
self.fname = fname
31-
38+
self.debug = debug
3239
def word_count(self, base, path):
33-
script_dir = os.path.dirname(os.path.realpath(__file__))
34-
tex_count_path = os.path.join(script_dir, "texcount.pl")
35-
out = get_output([tex_count_path, "-inc", path], cwd=base)
40+
out = get_output(["perl", tex_count_path, "-inc", path], cwd=base)
41+
if self.debug: log("TeXCount: %s", out)
3642
results = {}
3743
name = None
3844
for l in out.splitlines():
@@ -45,7 +51,7 @@ def word_count(self, base, path):
4551
name = "total"
4652
results[name] = {}
4753
elif name is not None: results[name][k] = v
48-
return results
54+
return (out, results)
4955

5056
def extract_wordcount(self, d):
5157
fields = [
@@ -65,4 +71,7 @@ def extract_wordcount(self, d):
6571
return out
6672

6773
def run(self, path):
68-
return self.extract_wordcount(self.word_count(path, self.fname)["total"])
74+
if not os.path.exists(os.path.join(path, self.fname)): raise IOError("Couldn't find TeX file: %s" % self.fname)
75+
(out, wc) = self.word_count(path, self.fname)
76+
if not "total" in wc: raise ValueError("Error parsing output: %s" % out)
77+
else: return self.extract_wordcount(wc["total"])

util.py renamed to gitwalker/util.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import subprocess
22

3-
class CmdError(Exception):
4-
def __init__(self, ret, cmd, out): self.ret, self.cmd, self.out = ret, cmd, out
5-
63
def log(msg, *args):
74
print ">>> " + msg % args
85

setup.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from setuptools import setup
2+
import os
3+
4+
version = '0.1'
5+
6+
description = "A tool for collecting data from git repositories."
7+
cur_dir = os.path.dirname(__file__)
8+
try:
9+
long_description = open(os.path.join(cur_dir, 'README.md')).read()
10+
except:
11+
long_description = description
12+
13+
setup(
14+
name = "gitwalker",
15+
version = version,
16+
url = 'https://github.com/alexsparrow/gitwalker',
17+
license = 'GPL',
18+
description = description,
19+
long_description = long_description,
20+
author = 'Alex Sparrow',
21+
author_email = '[email protected]',
22+
packages = ['gitwalker'],
23+
package_data = {"gitwalker":["bin/texcount.pl"]},
24+
install_requires = ['setuptools'],
25+
entry_points="""
26+
[console_scripts]
27+
gitwalk = gitwalker.main:main
28+
""",
29+
# classifiers=[
30+
# 'Development Status :: 4 - Beta',
31+
# 'Environment :: Console',
32+
# 'Intended Audience :: Developers',
33+
# 'Intended Audience :: System Administrators',
34+
# 'License :: OSI Approved :: BSD License',
35+
# 'Operating System :: MacOS :: MacOS X',
36+
# 'Operating System :: POSIX',
37+
# 'Programming Language :: Python',
38+
# 'Topic :: Software Development :: Bug Tracking',
39+
# ],
40+
)

0 commit comments

Comments
 (0)