Skip to content

Commit d4b7d0a

Browse files
committed
Make it clear when there's no change (fixes #52)
1 parent e69eb3b commit d4b7d0a

File tree

3 files changed

+64
-6
lines changed

3 files changed

+64
-6
lines changed

webdiff/static/css/style.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,17 @@ ul.file-list {
118118
table .side-a, table .side-b {
119119
background: url(/static/img/trans_bg.gif);
120120
}
121+
122+
.no-changes {
123+
background-color: rgb(252, 248, 227);
124+
border: 1px solid rgb(245, 231, 158);
125+
border-radius: 4px;
126+
color: rgb(138, 109, 59);
127+
text-align: center;
128+
padding: 5px 5px;
129+
margin-bottom: 10px;
130+
}
131+
132+
.image-diff .no-changes {
133+
margin-top: 10px;
134+
}

webdiff/static/js/components.jsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,32 @@ var DiffView = React.createClass({
252252
}
253253
});
254254

255+
// A "no changes" sign which only appears when applicable.
256+
var NoChanges = React.createClass({
257+
propTypes: {
258+
filePair: React.PropTypes.object.isRequired
259+
},
260+
render: function() {
261+
if (this.props.filePair.no_changes) {
262+
return <div className="no-changes">(No Changes)</div>;
263+
} else {
264+
return null;
265+
}
266+
}
267+
});
268+
255269
// A side-by-side diff of source code.
256270
var CodeDiff = React.createClass({
257271
propTypes: {
258272
filePair: React.PropTypes.object.isRequired
259273
},
260274
render: function() {
261-
return <div key={this.props.filePair.idx}>Loading&hellip;</div>;
275+
return (
276+
<div style={{display: 'table'}}>
277+
<NoChanges filePair={this.props.filePair} />
278+
<div ref="codediff" key={this.props.filePair.idx}>Loading&hellip;</div>
279+
</div>
280+
);
262281
},
263282
renderDiff: function() {
264283
// Either side can be empty (i.e. an add or a delete), in which case
@@ -274,7 +293,7 @@ var CodeDiff = React.createClass({
274293
$.when(beforeDeferred, afterDeferred).done((before, after) => {
275294
if (!this.isMounted()) return;
276295
// Call out to codediff.js to construct the side-by-side diff.
277-
$(this.getDOMNode()).empty().append(
296+
$(this.refs.codediff.getDOMNode()).empty().append(
278297
renderDiff(pair.a, pair.b, before[0], after[0]));
279298
})
280299
.fail((e) => alert("Unable to get diff!"));
@@ -333,6 +352,7 @@ var ImageDiff = React.createClass({
333352
<label htmlFor="shrink-to-fit"> Shrink to fit</label>
334353
</div>
335354
<div className={'image-diff ' + mode}>
355+
<NoChanges filePair={this.props.filePair} />
336356
{image}
337357
</div>
338358
</div>;

webdiff/util.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,19 @@ def _convert_to_pair_objects(pairs):
7676

7777

7878
def _annotate_file_pair(d, a_dir, b_dir):
79+
a_path = os.path.join(a_dir, d['a']) if d['a'] else None
80+
b_path = os.path.join(b_dir, d['b']) if d['b'] else None
81+
7982
# Attach image metadata if applicable.
8083
if is_image_diff(d):
8184
d['is_image_diff'] = True
82-
if d['a']: d['image_a'] = _image_metadata(os.path.join(a_dir, d['a']))
83-
if d['b']: d['image_b'] = _image_metadata(os.path.join(b_dir, d['b']))
85+
if d['a']: d['image_a'] = _image_metadata(a_path)
86+
if d['b']: d['image_b'] = _image_metadata(b_path)
8487

85-
# TODO: diffstats
88+
if a_path and b_path:
89+
d['no_changes'] = _are_files_identical(a_path, b_path)
90+
else:
91+
d['no_changes'] = False
8692

8793

8894
def annotate_file_pairs(file_pairs, a_dir, b_dir):
@@ -97,7 +103,7 @@ def annotate_file_pairs(file_pairs, a_dir, b_dir):
97103

98104
def find_moves(diff, a_dir, b_dir):
99105
def hash(d, path):
100-
return hashlib.sha512(open(os.path.join(d, path)).read()).digest()
106+
return _contentHash(os.path.join(d, path))
101107

102108
out = copy.deepcopy(diff)
103109
add_delete_pairs = defaultdict(lambda: [None,None])
@@ -144,6 +150,24 @@ def is_image(path):
144150
return False
145151

146152

153+
hash_cache = {}
154+
def _contentHash(path):
155+
global hash_cache
156+
if path in hash_cache:
157+
return hash_cache[path]
158+
sha = hashlib.sha512(open(path).read()).digest()
159+
hash_cache[path] = sha
160+
return sha
161+
162+
163+
def _are_files_identical(path1, path2):
164+
# Check if anything has changed.
165+
# Compare lengths & then checksums.
166+
if os.path.getsize(path1) != os.path.getsize(path2):
167+
return False
168+
return _contentHash(path1) == _contentHash(path2)
169+
170+
147171
def _image_metadata(path):
148172
md = { 'num_bytes': os.path.getsize(path) }
149173
try:

0 commit comments

Comments
 (0)