Skip to content

Commit 4a0b672

Browse files
committed
Split off githubdiff
1 parent 21a14fb commit 4a0b672

File tree

3 files changed

+84
-79
lines changed

3 files changed

+84
-79
lines changed

webdiff/argparser.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55

66
import dirdiff
7+
import githubdiff
78
import github_fetcher
89
from localfilediff import LocalFileDiff
910

@@ -96,4 +97,4 @@ def diff_for_args(args):
9697

9798
if 'github' in args:
9899
gh = args['github']
99-
return github_fetcher.fetch_pull_request(gh['owner'], gh['repo'], gh['num'])
100+
return githubdiff.fetch_pull_request(gh['owner'], gh['repo'], gh['num'])

webdiff/github_fetcher.py

Lines changed: 3 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -6,76 +6,19 @@
66
# Use this PR for testing to see all four types of change at once:
77
# https://github.com/danvk/test-repo/pull/2/
88

9-
import atexit
109
from collections import OrderedDict
11-
import errno
1210
import os
1311
import re
1412
import subprocess
15-
import sys
16-
import tempfile
1713

1814
from github import Github, UnknownObjectException
1915

2016
from util import memoize
2117

2218

23-
class GitHubDiff(object):
24-
def __init__(self, pr, github_file):
25-
self._pr = pr
26-
self._file = github_file
27-
self.type = {
28-
'modified': 'change',
29-
'renamed': 'move',
30-
'added': 'add',
31-
'removed': 'delete'
32-
}[github_file.status]
33-
self._a_path = None
34-
self._b_path = None
35-
36-
@property
37-
def a(self):
38-
if self.type == 'move':
39-
return self._file.raw_data['previous_filename']
40-
elif self.type == 'add':
41-
return None
42-
else:
43-
return self._file.filename
44-
45-
@property
46-
def b(self):
47-
if self.type == 'delete':
48-
return None
49-
else:
50-
return self._file.filename
51-
52-
# NB: these are @memoize'd via fetch()
53-
@property
54-
def a_path(self):
55-
return fetch(self._pr.base.repo, self.a, self._pr.base.sha)
56-
57-
@property
58-
def b_path(self):
59-
return fetch(self._pr.head.repo, self.b, self._pr.head.sha)
60-
61-
def __repr__(self):
62-
return '%s (%s)' % (self.a or self.b, self.type)
63-
64-
# TOOD: diffstats are accessible via file.{changes,additions,deletions}
65-
66-
6719
@memoize
68-
def fetch(repo, filename, sha):
69-
if filename is None: return None
70-
data = repo.get_file_contents(filename, sha).decoded_content
71-
_, ext = os.path.splitext(filename)
72-
fd, path = tempfile.mkstemp(suffix=ext)
73-
open(path, 'wb').write(data)
74-
return path
75-
76-
77-
@memoize
78-
def _github():
20+
def github():
21+
'''Returns a GitHub API object with auth, if it's available.'''
7922
def simple_fallback(message=None):
8023
if message: sys.stderr.write(message + '\n')
8124
return Github()
@@ -102,17 +45,6 @@ def simple_fallback(message=None):
10245
return Github()
10346

10447

105-
def fetch_pull_request(owner, repo, num):
106-
'''Return a list of Diff objects for a pull request.'''
107-
sys.stderr.write('Loading pull request %s/%s#%s from github...\n' % (
108-
owner, repo, num))
109-
g = _github()
110-
pr = g.get_user(owner).get_repo(repo).get_pull(num)
111-
files = pr.get_files()
112-
113-
return [GitHubDiff(pr, f) for f in files]
114-
115-
11648
class NoRemoteError(Exception):
11749
pass
11850

@@ -132,7 +64,7 @@ def get_pr_repo(num):
13264
'directory. Are you in a git repo? Try running '
13365
'`git remote -v` to debug.')
13466

135-
g = _github()
67+
g = github()
13668
for remote in remotes:
13769
owner = remote['owner']
13870
repo = remote['repo']
@@ -189,10 +121,3 @@ def _get_remotes():
189121
['git', 'remote', '-v'], stdout=subprocess.PIPE).communicate()[0].split('\n')
190122
return _parse_remotes(remote_lines)
191123

192-
193-
194-
@atexit.register
195-
def _cleanup():
196-
"""Delete any temporary directories which were created by two_folders()."""
197-
#for d in temp_dirs:
198-
# os.removedirs(d)

webdiff/githubdiff.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'''Diff class for GitHub pull requests.
2+
3+
The main feature of note is that this fetches files from GitHub lazily when
4+
a_path and b_path are accessed. This allows large PRs to be loaded quickly
5+
--more quickly than GitHub's UI does it!
6+
'''
7+
8+
import os
9+
import tempfile
10+
import sys
11+
12+
from util import memoize
13+
from github_fetcher import github
14+
15+
16+
class GitHubDiff(object):
17+
'''pr and github_file are objects from the Python GitHub API.'''
18+
def __init__(self, pr, github_file):
19+
self._pr = pr
20+
self._file = github_file
21+
self.type = {
22+
'modified': 'change',
23+
'renamed': 'move',
24+
'added': 'add',
25+
'removed': 'delete'
26+
}[github_file.status]
27+
self._a_path = None
28+
self._b_path = None
29+
30+
@property
31+
def a(self):
32+
if self.type == 'move':
33+
return self._file.raw_data['previous_filename']
34+
elif self.type == 'add':
35+
return None
36+
else:
37+
return self._file.filename
38+
39+
@property
40+
def b(self):
41+
if self.type == 'delete':
42+
return None
43+
else:
44+
return self._file.filename
45+
46+
# NB: these are @memoize'd via fetch()
47+
@property
48+
def a_path(self):
49+
return fetch(self._pr.base.repo, self.a, self._pr.base.sha)
50+
51+
@property
52+
def b_path(self):
53+
return fetch(self._pr.head.repo, self.b, self._pr.head.sha)
54+
55+
def __repr__(self):
56+
return '%s (%s)' % (self.a or self.b, self.type)
57+
58+
# TOOD: diffstats are accessible via file.{changes,additions,deletions}
59+
60+
61+
def fetch_pull_request(owner, repo, num):
62+
'''Return a list of Diff objects for a pull request.'''
63+
sys.stderr.write('Loading pull request %s/%s#%s from github...\n' % (
64+
owner, repo, num))
65+
g = github()
66+
pr = g.get_user(owner).get_repo(repo).get_pull(num)
67+
files = pr.get_files()
68+
69+
return [GitHubDiff(pr, f) for f in files]
70+
71+
72+
@memoize
73+
def fetch(repo, filename, sha):
74+
if filename is None: return None
75+
data = repo.get_file_contents(filename, sha).decoded_content
76+
_, ext = os.path.splitext(filename)
77+
fd, path = tempfile.mkstemp(suffix=ext)
78+
open(path, 'wb').write(data)
79+
return path

0 commit comments

Comments
 (0)