1717from flask import (Flask , render_template , send_from_directory , send_file ,
1818 request , jsonify , Response )
1919
20+ import diff
2021import util
2122import argparser
2223
@@ -46,8 +47,6 @@ class Config:
4647app .config .from_object (Config )
4748app .config .from_envvar ('WEBDIFF_CONFIG' , silent = True )
4849
49- A_DIR = None
50- B_DIR = None
5150DIFF = None
5251PORT = None
5352
@@ -75,20 +74,31 @@ def update_last_request_ms():
7574 LAST_REQUEST_MS = time .time () * 1000
7675
7776
77+ def error (code , message ):
78+ e = {"code" : code , "message" : message }
79+ response = jsonify (e )
80+ response .status_code = 400
81+ return response
82+
83+
7884@app .route ("/<side>/get_contents" , methods = ['POST' ])
7985def get_contents (side ):
80- assert side in ('a' , 'b' )
86+ if side not in ('a' , 'b' ):
87+ return error ('invalid side' , 'Side must be "a" or "b", got %s' % side )
88+
89+ # TODO: switch to index? might be simpler
8190 path = request .form .get ('path' , '' )
8291 if not path :
83- e = {"code" : "incomplete" ,
84- "message" : "Incomplete request (need path)" }
85- response = jsonify (e )
86- response .status_code = 400
87- return response
92+ return error ('incomplete' , 'Incomplete request (need path)' )
93+
94+ idx = diff .find_diff_index (DIFF , side , path )
95+ if idx is None :
96+ return error ('not found' , 'Invalid path on side %s: %s' % (side , path ))
97+
98+ d = DIFF [idx ]
99+ abs_path = d .a_path if side == 'a' else d .b_path
88100
89101 try :
90- abs_path = os .path .join (A_DIR if side == 'a' else B_DIR ,
91- os .path .normpath (path )) # / --> \ on windows
92102 is_binary = util .is_binary_file (abs_path )
93103 if is_binary :
94104 size = os .path .getsize (abs_path )
@@ -97,51 +107,43 @@ def get_contents(side):
97107 contents = open (abs_path ).read ()
98108 return Response (contents , mimetype = 'text/plain' )
99109 except Exception :
100- e = {"code" : "read-error" ,
101- "message" : "Unable to read %s" % abs_path }
102- response = jsonify (e )
103- response .status_code = 400
104- return response
110+ return error ('read-error' , 'Unable to read %s' % abs_path )
105111
106112
107113@app .route ("/<side>/image/<path:path>" )
108114def get_image (side , path ):
109- assert side in ('a' , 'b' )
115+ if side not in ('a' , 'b' ):
116+ return error ('invalid side' , 'Side must be "a" or "b", got %s' % side )
117+
118+ # TODO: switch to index? might be simpler
110119 if not path :
111- e = {"code" : "incomplete" ,
112- "message" : "Incomplete request (need path)" }
113- response = jsonify (e )
114- response .status_code = 400
115- return response
120+ return error ('incomplete' , 'Incomplete request (need path)' )
116121
117122 mime_type , enc = mimetypes .guess_type (path )
118123 if not mime_type or not mime_type .startswith ('image/' ) or enc is not None :
119- e = {"code" : "wrongtype" ,
120- "message" : "Requested file of type (%s, %s) as image" % (
121- mime_type , enc )}
122- response = jsonify (e )
123- response .status_code = 400
124- return response
124+ return error ('wrongtype' , 'Requested file of type (%s, %s) as image' % (
125+ mime_type , enc ))
126+
127+ idx = diff .find_diff_index (DIFF , side , path )
128+ if idx is None :
129+ return error ('not found' , 'Invalid path on side %s: %s' % (side , path ))
130+
131+ d = DIFF [idx ]
132+ abs_path = d .a_path if side == 'a' else d .b_path
125133
126134 try :
127- abs_path = os .path .join (A_DIR if side == 'a' else B_DIR ,
128- os .path .normpath (path )) # / --> \ on windows
129135 contents = open (abs_path ).read ()
130136 return Response (contents , mimetype = mime_type )
131137 except Exception :
132- e = {"code" : "read-error" ,
133- "message" : "Unable to read %s" % abs_path }
134- response = jsonify (e )
135- response .status_code = 400
136- return response
138+ return error ('read-error' , 'Unable to read %s' % abs_path )
137139
138140
139141@app .route ("/pdiff/<int:idx>" )
140142def get_pdiff (idx ):
141143 idx = int (idx )
142- pair = DIFF [idx ]
144+ d = DIFF [idx ]
143145 try :
144- _ , pdiff_image = util .generate_pdiff_image (pair [ ' a_path' ], pair [ ' b_path' ] )
146+ _ , pdiff_image = util .generate_pdiff_image (d . a_path , d . b_path )
145147 dilated_image = util .generate_dilated_pdiff_image (pdiff_image )
146148 except util .ImageMagickNotAvailableError :
147149 return 'ImageMagick is not available' , 501
@@ -153,9 +155,9 @@ def get_pdiff(idx):
153155@app .route ("/pdiffbbox/<int:idx>" )
154156def get_pdiff_bbox (idx ):
155157 idx = int (idx )
156- pair = DIFF [idx ]
158+ d = DIFF [idx ]
157159 try :
158- _ , pdiff_image = util .generate_pdiff_image (pair [ ' a_path' ], pair [ ' b_path' ] )
160+ _ , pdiff_image = util .generate_pdiff_image (d . a_path , d . b_path )
159161 bbox = util .get_pdiff_bbox (pdiff_image )
160162 except util .ImageMagickNotAvailableError :
161163 return 'ImageMagick is not available' , 501
@@ -173,10 +175,17 @@ def index():
173175@app .route ("/<int:idx>" )
174176def file_diff (idx ):
175177 idx = int (idx )
178+ pairs = diff .get_thin_list (DIFF )
176179 return render_template ('file_diff.html' ,
177180 idx = idx ,
178181 has_magick = util .is_imagemagick_available (),
179- pairs = DIFF )
182+ pairs = pairs )
183+
184+
185+ @app .route ('/thick/<int:idx>' )
186+ def thick_diff (idx ):
187+ idx = int (idx )
188+ return jsonify (diff .get_thick_dict (DIFF [idx ]))
180189
181190
182191@app .route ('/favicon.ico' )
@@ -254,24 +263,23 @@ def is_webdiff_from_head():
254263
255264
256265def run ():
257- global A_DIR , B_DIR , DIFF , PORT
266+ global DIFF , PORT
258267 try :
259268 parsed_args = argparser .parse (sys .argv [1 :])
260269 except argparser .UsageError as e :
261270 sys .stderr .write ('Error: %s\n \n ' % e .message )
262271 usage_and_die ()
263272
264- A_DIR , B_DIR , DIFF = util .diff_for_args (parsed_args )
273+ DIFF = argparser .diff_for_args (parsed_args )
265274
266275 if app .config ['TESTING' ] or app .config ['DEBUG' ]:
267- sys .stderr .write ('Diffing: \n A: %s \n B: %s \n \n ' % ( A_DIR , B_DIR ) )
276+ sys .stderr .write ('Diff: \n %s ' % DIFF )
268277
269278 PORT = pick_a_port (parsed_args )
270279
271280 sys .stderr .write ('''Serving diffs on http://localhost:%s
272281Close the browser tab or hit Ctrl-C when you're done.
273282''' % PORT )
274- logging .info ('Diff: %r' , DIFF )
275283 Timer (0.1 , open_browser ).start ()
276284 app .run (host = '0.0.0.0' , port = PORT )
277285
0 commit comments