synchronized developers and entries
This commit is contained in:
parent
8a08425e09
commit
625871062f
@ -186,7 +186,7 @@ class DevelopersMaintainer:
|
|||||||
if not self.developers:
|
if not self.developers:
|
||||||
print('developers not yet loaded')
|
print('developers not yet loaded')
|
||||||
return
|
return
|
||||||
developer_names = [x['Name'] for x in self.developers]
|
developer_names = list(self.developers.keys())
|
||||||
for index, name in enumerate(developer_names):
|
for index, name in enumerate(developer_names):
|
||||||
for other_name in developer_names[index + 1:]:
|
for other_name in developer_names[index + 1:]:
|
||||||
if osg.name_similarity(name, other_name) > 0.8:
|
if osg.name_similarity(name, other_name) > 0.8:
|
||||||
@ -197,9 +197,9 @@ class DevelopersMaintainer:
|
|||||||
if not self.developers:
|
if not self.developers:
|
||||||
print('developers not yet loaded')
|
print('developers not yet loaded')
|
||||||
return
|
return
|
||||||
for dev in self.developers:
|
for dev in self.developers.values():
|
||||||
if not dev['Games']:
|
if not dev['Games']:
|
||||||
print(' {} has no "Games" field'.format(dev['Name']))
|
print(' {} has no games'.format(dev['Name']))
|
||||||
print('orphanes checked')
|
print('orphanes checked')
|
||||||
|
|
||||||
def check_for_missing_developers_in_entries(self):
|
def check_for_missing_developers_in_entries(self):
|
||||||
@ -209,7 +209,7 @@ class DevelopersMaintainer:
|
|||||||
if not self.entries:
|
if not self.entries:
|
||||||
print('entries not yet loaded')
|
print('entries not yet loaded')
|
||||||
return
|
return
|
||||||
for dev in self.developers:
|
for dev in self.developers.values():
|
||||||
dev_name = dev['Name']
|
dev_name = dev['Name']
|
||||||
for entry_name in dev['Games']:
|
for entry_name in dev['Games']:
|
||||||
x = [x for x in self.entries if x['Title'] == entry_name]
|
x = [x for x in self.entries if x['Title'] == entry_name]
|
||||||
@ -222,6 +222,29 @@ class DevelopersMaintainer:
|
|||||||
print('Entry "{}" listed in developer "{}" but not listed in that entry'.format(entry_name, dev_name))
|
print('Entry "{}" listed in developer "{}" but not listed in that entry'.format(entry_name, dev_name))
|
||||||
print('missed developer checked')
|
print('missed developer checked')
|
||||||
|
|
||||||
|
def update_developers_from_entries(self):
|
||||||
|
if not self.developers:
|
||||||
|
print('developer not yet loaded')
|
||||||
|
return
|
||||||
|
if not self.entries:
|
||||||
|
print('entries not yet loaded')
|
||||||
|
return
|
||||||
|
# loop over all developers and delete all games
|
||||||
|
for dev in self.developers.values():
|
||||||
|
dev['Games'] = []
|
||||||
|
# loop over all entries and add this game to all developers of this game
|
||||||
|
for entry in self.entries:
|
||||||
|
entry_name = entry['Title']
|
||||||
|
entry_devs = entry.get('Developer', [])
|
||||||
|
for entry_dev in entry_devs:
|
||||||
|
entry_dev = entry_dev.value # ignored the comment
|
||||||
|
if entry_dev in self.developers:
|
||||||
|
self.developers[entry_dev]['Games'].append(entry_name)
|
||||||
|
else:
|
||||||
|
# completely new developer
|
||||||
|
self.developers[entry_dev] = {'Name': entry_dev, 'Games': entry_name}
|
||||||
|
print('developers updated')
|
||||||
|
|
||||||
def read_entries(self):
|
def read_entries(self):
|
||||||
self.entries = osg.read_entries()
|
self.entries = osg.read_entries()
|
||||||
print('{} entries read'.format(len(self.entries)))
|
print('{} entries read'.format(len(self.entries)))
|
||||||
@ -237,6 +260,7 @@ if __name__ == "__main__":
|
|||||||
'Check for duplicates': m.check_for_duplicates,
|
'Check for duplicates': m.check_for_duplicates,
|
||||||
'Check for orphans': m.check_for_orphans,
|
'Check for orphans': m.check_for_orphans,
|
||||||
'Check for games in developers not listed': m.check_for_missing_developers_in_entries,
|
'Check for games in developers not listed': m.check_for_missing_developers_in_entries,
|
||||||
|
'Update developers from entries': m.update_developers_from_entries,
|
||||||
'Read entries': m.read_entries
|
'Read entries': m.read_entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +35,14 @@ generic_comment_string = '[comment]: # (partly autogenerated content, edit with
|
|||||||
# these fields have to be present in each entry (in this order)
|
# these fields have to be present in each entry (in this order)
|
||||||
essential_fields = ('File', 'Title', 'Home', 'State', 'Keywords', 'Code repository', 'Code language', 'Code license')
|
essential_fields = ('File', 'Title', 'Home', 'State', 'Keywords', 'Code repository', 'Code language', 'Code license')
|
||||||
|
|
||||||
# only these fields can be used currently (in this order)
|
valid_properties = ('Home', 'Media', 'Inspirations', 'State', 'Play', 'Download', 'Platform', 'Keywords', 'Code repository', 'Code language',
|
||||||
valid_fields = (
|
'Code license', 'Code dependencies', 'Assets license', 'Developer')
|
||||||
'File', 'Title', 'Home', 'Media', 'Inspirations', 'State', 'Play', 'Download', 'Platform', 'Keywords', 'Code repository', 'Code language',
|
|
||||||
'Code license', 'Code dependencies', 'Assets license', 'Developer', 'Note', 'Building')
|
|
||||||
|
|
||||||
valid_building_fields = ('Build system', 'Build instructions')
|
# only these fields can be used currently (in this order)
|
||||||
|
valid_fields = ('File', 'Title') + valid_properties + ('Note', 'Building')
|
||||||
|
|
||||||
|
valid_building_properties = ('Build system', 'Build instructions')
|
||||||
|
valid_building_fields = valid_building_properties + ('Note',)
|
||||||
|
|
||||||
# these are the only valid platforms currently (and must be given in this order)
|
# these are the only valid platforms currently (and must be given in this order)
|
||||||
valid_platforms = ('Windows', 'Linux', 'macOS', 'Android', 'iOS', 'Web')
|
valid_platforms = ('Windows', 'Linux', 'macOS', 'Android', 'iOS', 'Web')
|
||||||
|
@ -326,6 +326,9 @@ def read_developers():
|
|||||||
if any(not (x.startswith('http://') or x.startswith('https://')) for x in content):
|
if any(not (x.startswith('http://') or x.startswith('https://')) for x in content):
|
||||||
raise RuntimeError('Invalid URL in field "{}" in developer {}.'.format(field, dev['Name']))
|
raise RuntimeError('Invalid URL in field "{}" in developer {}.'.format(field, dev['Name']))
|
||||||
|
|
||||||
|
# convert to dictionary
|
||||||
|
developers = {x['Name']: x for x in developers}
|
||||||
|
|
||||||
return developers
|
return developers
|
||||||
|
|
||||||
|
|
||||||
@ -334,6 +337,9 @@ def write_developers(developers):
|
|||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
# convert dictionary to list
|
||||||
|
developers = list(developers.values())
|
||||||
|
|
||||||
# comment
|
# comment
|
||||||
content = '{}\n'.format(generic_comment_string)
|
content = '{}\n'.format(generic_comment_string)
|
||||||
|
|
||||||
@ -517,7 +523,23 @@ def check_and_process_entry(entry):
|
|||||||
# check for essential fields
|
# check for essential fields
|
||||||
for field in essential_fields:
|
for field in essential_fields:
|
||||||
if field not in entry:
|
if field not in entry:
|
||||||
message += 'essential property "{}" missing\n'.format(field)
|
message += 'Essential property "{}" missing\n'.format(field)
|
||||||
|
|
||||||
|
# now the same treatment for building
|
||||||
|
building = entry['Building']
|
||||||
|
d = {}
|
||||||
|
for field, value in building:
|
||||||
|
if field in d:
|
||||||
|
message += 'Field "{}" appears twice\n'.format(field)
|
||||||
|
d[field] = value
|
||||||
|
building = d
|
||||||
|
|
||||||
|
# check valid fields TODO should also check order
|
||||||
|
for field in building.keys():
|
||||||
|
if field not in valid_building_fields:
|
||||||
|
message += 'Building field "{}" invalid\n'.format(field)
|
||||||
|
entry['Building'] = building
|
||||||
|
|
||||||
|
|
||||||
# check canonical file name
|
# check canonical file name
|
||||||
file = entry['File']
|
file = entry['File']
|
||||||
@ -551,7 +573,7 @@ def write_entry(entry):
|
|||||||
# TODO check entry
|
# TODO check entry
|
||||||
|
|
||||||
# get path
|
# get path
|
||||||
entry_path = os.path.join(entries_path, entry['file'])
|
entry_path = os.path.join(entries_path, entry['File'])
|
||||||
|
|
||||||
# create output content
|
# create output content
|
||||||
content = create_entry_content(entry)
|
content = create_entry_content(entry)
|
||||||
@ -571,10 +593,11 @@ def create_entry_content(entry):
|
|||||||
content = '# {}\n\n'.format(entry['Title'])
|
content = '# {}\n\n'.format(entry['Title'])
|
||||||
|
|
||||||
# now properties in the recommended order
|
# now properties in the recommended order
|
||||||
for field in valid_fields:
|
for field in valid_properties:
|
||||||
if field in entry:
|
if field in entry:
|
||||||
c = entry[field]
|
c = entry[field]
|
||||||
c = ['"{}"'.format(x) if ',' in x else x for x in c]
|
c = ['"{}"'.format(x) if ',' in x else x for x in c]
|
||||||
|
c = [str(x) for x in c]
|
||||||
content += '- {}: {}\n'.format(field, ', '.join(c))
|
content += '- {}: {}\n'.format(field, ', '.join(c))
|
||||||
content += '\n'
|
content += '\n'
|
||||||
|
|
||||||
@ -587,12 +610,15 @@ def create_entry_content(entry):
|
|||||||
|
|
||||||
# building properties if present
|
# building properties if present
|
||||||
has_properties = False
|
has_properties = False
|
||||||
for field in valid_building_fields:
|
for field in valid_building_properties:
|
||||||
if field in entry['Building']:
|
if field in entry['Building']:
|
||||||
if not has_properties:
|
if not has_properties:
|
||||||
has_properties = True
|
has_properties = True
|
||||||
content += '\n'
|
content += '\n'
|
||||||
content += '- {}: {}\n'.format(field, ', '.join(entry['Building'][field]))
|
c = entry['Building'][field]
|
||||||
|
c = ['"{}"'.format(x) if ',' in x else x for x in c]
|
||||||
|
c = [str(x) for x in c]
|
||||||
|
content += '- {}: {}\n'.format(field, ', '.join(c))
|
||||||
|
|
||||||
# if there is a note, insert it
|
# if there is a note, insert it
|
||||||
if 'Note' in entry['Building']:
|
if 'Note' in entry['Building']:
|
||||||
|
@ -121,7 +121,6 @@ class ValueWithComment:
|
|||||||
else:
|
else:
|
||||||
return '{}'.format(self.value)
|
return '{}'.format(self.value)
|
||||||
|
|
||||||
|
|
||||||
def parse(parser, transformer, content):
|
def parse(parser, transformer, content):
|
||||||
tree = parser.parse(content)
|
tree = parser.parse(content)
|
||||||
value = transformer.transform(tree)
|
value = transformer.transform(tree)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[comment]: # (partly autogenerated content, edit with care, read the manual before)
|
[comment]: # (partly autogenerated content, edit with care, read the manual before)
|
||||||
# Developer [369]
|
# Developer [378]
|
||||||
|
|
||||||
## Akira Higuchi [1]
|
## Akira Higuchi [1]
|
||||||
|
|
||||||
@ -46,6 +46,10 @@
|
|||||||
|
|
||||||
- Games: Maxit
|
- Games: Maxit
|
||||||
|
|
||||||
|
## Amer Koleci [7]
|
||||||
|
|
||||||
|
- Games: Vortice
|
||||||
|
|
||||||
## Anders Svensson [1]
|
## Anders Svensson [1]
|
||||||
|
|
||||||
- Games: Alex the Allegator 4
|
- Games: Alex the Allegator 4
|
||||||
@ -87,6 +91,10 @@
|
|||||||
- Games: Advanced Strategic Command
|
- Games: Advanced Strategic Command
|
||||||
- Contact: armin906@SF
|
- Contact: armin906@SF
|
||||||
|
|
||||||
|
## Armin Rigo [18]
|
||||||
|
|
||||||
|
- Games: The Bub's Brothers
|
||||||
|
|
||||||
## Arne Reiners [1]
|
## Arne Reiners [1]
|
||||||
|
|
||||||
- Games: GL-117
|
- Games: GL-117
|
||||||
@ -184,6 +192,10 @@
|
|||||||
- Games: Advanced Strategic Command
|
- Games: Advanced Strategic Command
|
||||||
- Contact: Ed-von-Schleck@GH
|
- Contact: Ed-von-Schleck@GH
|
||||||
|
|
||||||
|
## Chua Kong Sian [9]
|
||||||
|
|
||||||
|
- Games: GNU Chess
|
||||||
|
|
||||||
## Chuck Simmons [1]
|
## Chuck Simmons [1]
|
||||||
|
|
||||||
- Games: VMS Empire
|
- Games: VMS Empire
|
||||||
@ -779,6 +791,10 @@
|
|||||||
|
|
||||||
- Games: Trip on the Funny Boat
|
- Games: Trip on the Funny Boat
|
||||||
|
|
||||||
|
## Kriss [8]
|
||||||
|
|
||||||
|
- Games: GameCake
|
||||||
|
|
||||||
## krys [1]
|
## krys [1]
|
||||||
|
|
||||||
- Games: Krystal Drop
|
- Games: Krystal Drop
|
||||||
@ -848,6 +864,10 @@
|
|||||||
|
|
||||||
- Games: Tactics Squad
|
- Games: Tactics Squad
|
||||||
|
|
||||||
|
## Lukas Geyer [9]
|
||||||
|
|
||||||
|
- Games: GNU Chess
|
||||||
|
|
||||||
## Lukas Löhrer [1]
|
## Lukas Löhrer [1]
|
||||||
|
|
||||||
- Games: Amphetamine
|
- Games: Amphetamine
|
||||||
@ -997,6 +1017,10 @@
|
|||||||
|
|
||||||
- Games: GJID
|
- Games: GJID
|
||||||
|
|
||||||
|
## Mike Strobel [9]
|
||||||
|
|
||||||
|
- Games: Supremacy
|
||||||
|
|
||||||
## Mikey Lubker [1]
|
## Mikey Lubker [1]
|
||||||
|
|
||||||
- Games: Snowballz
|
- Games: Snowballz
|
||||||
@ -1353,6 +1377,10 @@
|
|||||||
|
|
||||||
- Games: Simon Tatham's Portable Puzzle Collection
|
- Games: Simon Tatham's Portable Puzzle Collection
|
||||||
|
|
||||||
|
## Simon Waters [9]
|
||||||
|
|
||||||
|
- Games: GNU Chess
|
||||||
|
|
||||||
## Sixth Floor Labs [1]
|
## Sixth Floor Labs [1]
|
||||||
|
|
||||||
- Games: Project Alexandria
|
- Games: Project Alexandria
|
||||||
@ -1415,6 +1443,10 @@
|
|||||||
|
|
||||||
- Games: Blinken
|
- Games: Blinken
|
||||||
|
|
||||||
|
## Stuart Cracraft [9]
|
||||||
|
|
||||||
|
- Games: GNU Chess
|
||||||
|
|
||||||
## Sylvain Beucler [1]
|
## Sylvain Beucler [1]
|
||||||
|
|
||||||
- Games: GNU FreeDink
|
- Games: GNU FreeDink
|
||||||
@ -1578,3 +1610,7 @@
|
|||||||
|
|
||||||
- Games: Necklace of the Eye
|
- Games: Necklace of the Eye
|
||||||
|
|
||||||
|
## Андрей Питько [13]
|
||||||
|
|
||||||
|
- Games: Wizards Magic
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user