77from pathlib import Path
88import sys
99from enum import Enum , unique
10- import struct ;
10+ import struct
1111
1212
1313# TODO: make this even nicer by using https://github.com/pytorch/add-annotations-github-action
6464]
6565
6666LICENSE_TYPES = [
67- 1 , # Open source
68- 2 , # Freeware
69- 3 , # Trial/Demo
67+ 1 , # Open source
68+ 2 , # Freeware
69+ 3 , # Trial/Demo
7070]
7171
72+
7273def get_valid_keys (section_name ):
7374 return KEYS [section_name ]
7475
76+
7577all_names = {}
7678all_urls = {}
7779g_current_section = None
@@ -93,7 +95,7 @@ def __init__(self):
9395
9496 def add (self , line , column , problem ):
9597 self ._problems += 1
96- print (' {col}: {msg}' .format (col = line .location (column ), msg = problem ))
98+ print (" {col}: {msg}" .format (col = line .location (column ), msg = problem ))
9799 print (line .text ())
98100 idx = column - 1 + len ("b'" ) # Offset the b' prefix
99101 print (' ' * idx + '^' )
@@ -158,15 +160,25 @@ def _parse_section(self, reporter, stripped):
158160
159161 if section_name not in KEYS :
160162 help = 'should always be "Section"'
161- reporter .add (self , self ._text .index (section_name ) + 1 ,
162- 'Invalid section name: "{sec}", {msg}' .format (sec = section_name , msg = help ))
163+ reporter .add (
164+ self ,
165+ self ._text .index (section_name ) + 1 ,
166+ 'Invalid section name: "{sec}", {msg}' .format (
167+ sec = section_name , msg = help
168+ ),
169+ )
163170 elif not locale :
164171 self .main_section = True
165172
166173 if locale :
167174 if len (locale ) not in (2 , 4 ) or not all (c in HEXDIGITS for c in locale ):
168- reporter .add (self , self ._text .index (locale ) + 1 ,
169- 'Invalid locale{extra}: "{loc}"' .format (extra = extra_locale , loc = locale ))
175+ reporter .add (
176+ self ,
177+ self ._text .index (locale ) + 1 ,
178+ 'Invalid locale{extra}: "{loc}"' .format (
179+ extra = extra_locale , loc = locale
180+ ),
181+ )
170182
171183 if arch :
172184 if arch not in ALL_ARCH :
@@ -205,43 +217,71 @@ def _parse_key_value(self, reporter, parts):
205217 textval = self .val .decode ()
206218
207219 if self .key not in get_valid_keys (g_current_section ):
208- reporter .add (self , 0 , 'Unknown key: "{key}"' .format (key = textkey ))
220+ reporter .add (self , 0 , 'Unknown key: "{key}"' .format (key = textkey ))
209221
210222 if self .key in [b'LicenseType' ]:
211223 v = int (textval , base = 10 )
212224 if v not in LICENSE_TYPES :
213- reporter .add (self , 0 , 'Invalid value: "{val}" in {key}' .format (val = v , key = textkey ))
225+ reporter .add (self , 0 , 'Invalid value: "{val}" in {key}' .format (val = v , key = textkey ))
214226
215227 if self .key in [b'License' ]:
216228 v = textval
217229 if v .casefold () == 'Unknown' .casefold ():
218230 # TODO: Reporter should be enabled when the existing DB entries are fixed:
219231 # reporter.add(self, 0, 'Invalid value: "{val}" in {key}'.format(val = v, key = textkey))
220- print ('Warning: {key} is "{val}" ({file})' .format (val = v , key = textkey , file = self ._file .filename ))
232+ print (
233+ 'Warning: {key} is "{val}" ({file})' .format (
234+ val = v , key = textkey , file = self ._file .filename
235+ )
236+ )
221237
222238 if self .key in [b'Scope' ]:
223239 v = textval
224240 if v .casefold () not in ['user' , 'machine' ]:
225- print ('Warning: {key} is "{val}" ({file})' .format (val = v , key = textkey , file = self ._file .filename ))
241+ print (
242+ 'Warning: {key} is "{val}" ({file})' .format (
243+ val = v , key = textkey , file = self ._file .filename
244+ )
245+ )
226246
227247 def location (self , column ):
228- return '{file}({line}:{col})' .format (file = self ._file .filename , line = self ._lineno , col = column )
248+ return "{file}({line}:{col})" .format (
249+ file = self ._file .filename , line = self ._lineno , col = column
250+ )
229251
230252 def text (self ):
231253 return self ._text
232254
233255
256+ def verify_unique (reporter , lines , line , name ):
257+ first = lines .get (name , None )
258+ if first :
259+ reporter .add (line , 0 , "Duplicate value found: {name}" .format (name = name ))
260+ reporter .add (first , 0 , 'First occurence:' )
261+ else :
262+ lines [name ] = line
263+
264+
265+ def verify_uniqueness (name , ver , url , reporter ):
266+ # Verify that the application name and version is unique
267+ if name :
268+ if ver :
269+ verify_unique (reporter , all_names , name , name .val + b', version ' + ver .val )
270+ else :
271+ verify_unique (reporter , all_names , name , name .val )
272+
273+ # Verify that the download URL is unique
274+ if url :
275+ verify_unique (reporter , all_urls , url , url .val )
276+
277+
234278class RappsFile :
235279 def __init__ (self , fullname ):
236280 self .path = fullname
237281 self .filename = fullname .name
238282 self ._sections = []
239283
240- def parse (self , reporter ):
241- with open (str (self .path ), 'rb' ) as f :
242- lines = [RappsLine (self , idx + 1 , line ) for idx , line in enumerate (f .readlines ())]
243-
244- # Create sections from all lines, and add keyvalue entries in their own section
284+ def _parse_lines (self , lines , reporter ):
245285 section = None
246286 for line in lines :
247287 linetype = line .parse (reporter )
@@ -254,6 +294,13 @@ def parse(self, reporter):
254294 assert section , "Got no section yet?"
255295 section .add (line )
256296
297+ def parse (self , reporter ):
298+ with open (str (self .path ), 'rb' ) as f :
299+ lines = [RappsLine (self , idx + 1 , line ) for idx , line in enumerate (f .readlines ())]
300+
301+ # Create sections from all lines, and add keyvalue entries in their own section
302+ self ._parse_lines (lines , reporter )
303+
257304 all_sections = []
258305 main_section = None
259306 name = None
@@ -270,41 +317,19 @@ def parse(self, reporter):
270317 main_section = section
271318 for key in REQUIRED_SECTION_KEYS :
272319 if not section [key ]:
273- reporter .add (section , 0 , 'Main section has no {key} key!' .format (key = key ))
320+ reporter .add (section , 0 , 'Main section has no {key} key!' .format (key = key ))
274321 if section [b'URLDownload' ] and not section [b'SizeBytes' ]:
275322 # We allow this, if the main section has a SizeBytes (alternate mirror without duplicating the info)
276323 if section == main_section or main_section and not main_section [b'SizeBytes' ]:
277324 reporter .add (section , 0 , 'Section has URLDownload but no SizeBytes!' )
278325
279- if section [b'Name' ] and not name :
280- name = section [b'Name' ]
281- if section [b'Version' ] and not ver :
282- ver = section [b'Version' ]
283- if section [b'URLDownload' ] and not url :
284- url = section [b'URLDownload' ]
285-
286- # Verify that the application name and version is unique
287- if name :
288- global all_names
289- if ver :
290- verify_unique (reporter , all_names , name , name .val + b', version ' + ver .val )
291- else :
292- verify_unique (reporter , all_names , name , name .val )
326+ name = name if name else section [b'Name' ]
327+ ver = ver if ver else section [b'Version' ]
328+ url = url if url else section [b'URLDownload' ]
293329
294- # Verify that the download URL is unique
295- if url :
296- global all_urls
297- verify_unique (reporter , all_urls , url , url .val )
330+ verify_uniqueness (name , ver , url , reporter )
298331
299332
300- def verify_unique (reporter , lines , line , name ):
301- first = lines .get (name , None )
302- if first :
303- reporter .add (line , 0 , 'Duplicate value found: {name}' .format (name = name ))
304- reporter .add (first , 0 , 'First occurence:' )
305- else :
306- lines [name ] = line
307-
308333def validate_single_icon (icon , reporter ):
309334 try :
310335 with open (str (icon ), 'rb' ) as f :
@@ -323,6 +348,7 @@ def validate_single_icon(icon, reporter):
323348 except Exception as e :
324349 reporter .add_file ('icons/' + icon .name , 'Exception while reading icon: ' + str (e ))
325350
351+
326352def validate_icons (ico_dir , reporter ):
327353 for icon in ico_dir .glob ('*.ico' ):
328354 validate_single_icon (icon , reporter )
0 commit comments