Improving catalog generation
Support multiple primary aircraft in a package, which has several aircraft developers have requested. This adjusts the handling of the variant-of and primary-set tags. Additionally, this adds partial unit-test coverage for -set.xml scanning and catalog XML generation. Run ./test_catalog to run unit-tests of the catalog generation.
This commit is contained in:
parent
e86954cc7f
commit
7eb3a8886f
229
catalog/catalog.py
Normal file
229
catalog/catalog.py
Normal file
@ -0,0 +1,229 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import lxml.etree as ET
|
||||
import os
|
||||
import re
|
||||
import sgprops
|
||||
import sys
|
||||
import catalogTags
|
||||
|
||||
CATALOG_VERSION = 4
|
||||
|
||||
# xml node (robust) get text helper
|
||||
def get_xml_text(e):
|
||||
if e != None and e.text != None:
|
||||
return e.text
|
||||
else:
|
||||
return ''
|
||||
|
||||
# return all available aircraft information from the set file as a
|
||||
# dict
|
||||
def scan_set_file(aircraft_dir, set_file, includes):
|
||||
base_file = os.path.basename(set_file)
|
||||
base_id = base_file[:-8]
|
||||
set_path = os.path.join(aircraft_dir, set_file)
|
||||
|
||||
includes.append(aircraft_dir)
|
||||
root_node = sgprops.readProps(set_path, includePaths = includes)
|
||||
|
||||
if not root_node.hasChild("sim"):
|
||||
return None
|
||||
|
||||
sim_node = root_node.getChild("sim")
|
||||
if sim_node == None:
|
||||
return None
|
||||
|
||||
variant = {}
|
||||
variant['name'] = sim_node.getValue("description", None)
|
||||
variant['status'] = sim_node.getValue("status", None)
|
||||
variant['author'] = sim_node.getValue("author", None)
|
||||
variant['description'] = sim_node.getValue("long-description", None)
|
||||
variant['id'] = base_id
|
||||
|
||||
# allow -set.xml files to declare themselves as primary.
|
||||
# we use this avoid needing a variant-of in every other -set.xml
|
||||
variant['primary-set'] = sim_node.getValue('primary-set', False)
|
||||
|
||||
# extract and record previews for each variant
|
||||
if sim_node.hasChild('previews'):
|
||||
variant['previews'] = extract_previews(sim_node.getChild('previews'), aircraft_dir)
|
||||
|
||||
if sim_node.hasChild('rating'):
|
||||
rating_node = sim_node.getChild("rating")
|
||||
variant['rating_FDM'] = rating_node.getValue("FDM", 0)
|
||||
variant['rating_systems'] = rating_node.getValue("systems", 0)
|
||||
variant['rating_cockpit'] = rating_node.getValue("cockpit", 0)
|
||||
variant['rating_model'] = rating_node.getValue("model", 0)
|
||||
|
||||
if sim_node.hasChild('tags'):
|
||||
variant['tags'] = extract_tags(sim_node.getChild('tags'), set_file)
|
||||
|
||||
if sim_node.hasChild('thumbnail'):
|
||||
variant['thumbnail'] = sim_node.getValue("thumbnail", None)
|
||||
|
||||
variant['variant-of'] = sim_node.getValue("variant-of", None)
|
||||
#print ' ', variant
|
||||
return variant
|
||||
|
||||
def extract_previews(previews_node, aircraft_dir):
|
||||
result = []
|
||||
for node in previews_node.getChildren("preview"):
|
||||
previewType = node.getValue("type", None)
|
||||
previewPath = node.getValue("path", None)
|
||||
|
||||
# check path exists in base-name-dir
|
||||
fullPath = os.path.join(aircraft_dir, previewPath)
|
||||
if not os.path.isfile(fullPath):
|
||||
print "Bad preview path, skipping:" + fullPath
|
||||
continue
|
||||
result.append({'type':previewType, 'path':previewPath})
|
||||
|
||||
return result
|
||||
|
||||
def extract_tags(tags_node, set_path):
|
||||
result = []
|
||||
for node in tags_node.getChildren("tag"):
|
||||
tag = node.value
|
||||
# check tag is in the allowed list
|
||||
if not catalogTags.isValidTag(tag):
|
||||
print "Unknown tag value:", tag, " in ", set_path
|
||||
result.append(tag)
|
||||
|
||||
return result
|
||||
|
||||
# scan all the -set.xml files in an aircraft directory. Returns a
|
||||
# package dict and a list of variants.
|
||||
def scan_aircraft_dir(aircraft_dir, includes):
|
||||
setDicts = []
|
||||
primaryAircraft = []
|
||||
package = None
|
||||
|
||||
files = os.listdir(aircraft_dir)
|
||||
for file in sorted(files, key=lambda s: s.lower()):
|
||||
if file.endswith('-set.xml'):
|
||||
try:
|
||||
d = scan_set_file(aircraft_dir, file, includes)
|
||||
if d == None:
|
||||
continue
|
||||
except:
|
||||
print "Skipping set file since couldn't be parsed:", os.path.join(aircraft_dir, file), sys.exc_info()[0]
|
||||
continue
|
||||
|
||||
setDicts.append(d)
|
||||
if d['primary-set']:
|
||||
# ensure explicit primary-set aircraft goes first
|
||||
primaryAircraft.insert(0, d)
|
||||
elif d['variant-of'] == None:
|
||||
primaryAircraft.append(d)
|
||||
|
||||
if len(setDicts) == 0:
|
||||
return None
|
||||
|
||||
# use the first one
|
||||
if len(primaryAircraft) == 0:
|
||||
print "Aircraft has no primary aircraft at all:", aircraft_dir
|
||||
primaryAircraft = [setDicts[0]]
|
||||
|
||||
package = primaryAircraft[0]
|
||||
if not 'thumbnail' in package:
|
||||
package['thumbnail'] = "thumbnail.jpg"
|
||||
|
||||
# variants is just all the set dicts except the first one
|
||||
variants = setDicts
|
||||
variants.remove(package)
|
||||
return (package, variants)
|
||||
|
||||
# create an xml node with text content
|
||||
def make_xml_leaf(name, text):
|
||||
leaf = ET.Element(name)
|
||||
if text != None:
|
||||
if isinstance(text, (int, long)):
|
||||
leaf.text = str(text)
|
||||
else:
|
||||
leaf.text = text
|
||||
else:
|
||||
leaf.text = ''
|
||||
return leaf
|
||||
|
||||
def append_preview_nodes(node, variant, download_base, package_name):
|
||||
if not 'previews' in variant:
|
||||
return
|
||||
|
||||
for preview in variant['previews']:
|
||||
preview_node = ET.Element('preview')
|
||||
preview_url = download_base + 'previews/' + package_name + '_' + preview['path']
|
||||
preview_node.append( make_xml_leaf('type', preview['type']) )
|
||||
preview_node.append( make_xml_leaf('url', preview_url) )
|
||||
preview_node.append( make_xml_leaf('path', preview['path']) )
|
||||
node.append(preview_node)
|
||||
|
||||
def append_tag_nodes(node, variant):
|
||||
if not 'tags' in variant:
|
||||
return
|
||||
|
||||
for tag in variant['tags']:
|
||||
node.append(make_xml_leaf('tag', tag))
|
||||
|
||||
def make_aircraft_node(aircraftDirName, package, variants, downloadBase):
|
||||
#print "package:", package
|
||||
#print "variants:", variants
|
||||
package_node = ET.Element('package')
|
||||
package_node.append( make_xml_leaf('name', package['name']) )
|
||||
package_node.append( make_xml_leaf('status', package['status']) )
|
||||
package_node.append( make_xml_leaf('author', package['author']) )
|
||||
package_node.append( make_xml_leaf('description', package['description']) )
|
||||
if 'rating_FDM' in package or 'rating_systems' in package \
|
||||
or 'rating_cockpit' in package or 'rating_model' in package:
|
||||
rating_node = ET.Element('rating')
|
||||
package_node.append(rating_node)
|
||||
rating_node.append( make_xml_leaf('FDM',
|
||||
package['rating_FDM']) )
|
||||
rating_node.append( make_xml_leaf('systems',
|
||||
package['rating_systems']) )
|
||||
rating_node.append( make_xml_leaf('cockpit',
|
||||
package['rating_cockpit']) )
|
||||
rating_node.append( make_xml_leaf('model',
|
||||
package['rating_model']) )
|
||||
package_node.append( make_xml_leaf('id', package['id']) )
|
||||
for variant in variants:
|
||||
variant_node = ET.Element('variant')
|
||||
package_node.append(variant_node)
|
||||
variant_node.append( make_xml_leaf('id', variant['id']) )
|
||||
variant_node.append( make_xml_leaf('name', variant['name']) )
|
||||
if 'description' in variant:
|
||||
variant_node.append( make_xml_leaf('description', variant['description']) )
|
||||
|
||||
if 'author' in variant:
|
||||
variant_node.append( make_xml_leaf('author', variant['author']) )
|
||||
|
||||
if 'thumbnail' in variant:
|
||||
# note here we prefix with the package name, since the thumbnail path
|
||||
# is assumed to be unique within the package
|
||||
thumbUrl = downloadBase + "thumbnails/" + aircraftDirName + '_' + variant['thumbnail']
|
||||
variant_node.append(make_xml_leaf('thumbnail', thumbUrl))
|
||||
variant_node.append(make_xml_leaf('thumbnail-path', variant['thumbnail']))
|
||||
|
||||
variantOf = variant['variant-of']
|
||||
if variantOf is None:
|
||||
variant_node.append(make_xml_leaf('variant-of', '_primary_'))
|
||||
else:
|
||||
variant_node.append(make_xml_leaf('variant-of', variantOf))
|
||||
|
||||
append_preview_nodes(variant_node, variant, downloadBase, aircraftDirName)
|
||||
append_tag_nodes(variant_node, variant)
|
||||
|
||||
package_node.append( make_xml_leaf('dir', aircraftDirName) )
|
||||
|
||||
download_url = downloadBase + aircraftDirName + '.zip'
|
||||
thumbnail_url = downloadBase + 'thumbnails/' + aircraftDirName + '_' + package['thumbnail']
|
||||
|
||||
package_node.append( make_xml_leaf('url', download_url) )
|
||||
package_node.append( make_xml_leaf('thumbnail', thumbnail_url) )
|
||||
package_node.append( make_xml_leaf('thumbnail-path', package['thumbnail']))
|
||||
|
||||
append_preview_nodes(package_node, package, downloadBase, aircraftDirName)
|
||||
append_tag_nodes(package_node, package)
|
||||
|
||||
return package_node
|
0
catalog/testData/Aircraft/f16/Previews/cockpit.png
Normal file
0
catalog/testData/Aircraft/f16/Previews/cockpit.png
Normal file
12
catalog/testData/Aircraft/f16/f16-common.xml
Normal file
12
catalog/testData/Aircraft/f16/f16-common.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList>
|
||||
<sim include="settings-common.xml">
|
||||
<author>Wilbur Wright</author>
|
||||
<tags>
|
||||
<tag>fighter</tag>
|
||||
<tag>1980s</tag>
|
||||
<tag>glass-cockpit</tag>
|
||||
</tags>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
11
catalog/testData/Aircraft/f16/f16-trainer-set.xml
Normal file
11
catalog/testData/Aircraft/f16/f16-trainer-set.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<name>f16-trainer</name>
|
||||
<description>F16 Trainer</description>
|
||||
<long-description>Twin-seat trainer version of the F16</long-description>
|
||||
|
||||
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
36
catalog/testData/Aircraft/f16/f16a-set.xml
Normal file
36
catalog/testData/Aircraft/f16/f16a-set.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<name>f16a</name>
|
||||
<description>F16-A</description>
|
||||
<long-description>The F16 is compact, light-weight multi-role fighter used around the world</long-description>
|
||||
|
||||
<primary-set type="bool">true</primary-set>
|
||||
|
||||
<rating>
|
||||
<FDM type="int">3</FDM>
|
||||
<systems type="int">1</systems>
|
||||
<cockpit type="int">2</cockpit>
|
||||
<model type="int">5</model>
|
||||
</rating>
|
||||
|
||||
<previews>
|
||||
<preview>
|
||||
<type>exterior</type>
|
||||
<splash type="bool">true</splash>
|
||||
<path>Previews/exterior-1.png</path>
|
||||
</preview>
|
||||
<preview>
|
||||
<type>exterior</type>
|
||||
<splash type="bool">true</splash>
|
||||
<path>Previews/exterior-f16a-2.png</path>
|
||||
</preview>
|
||||
<preview>
|
||||
<type>panel</type>
|
||||
<splash type="bool">false</splash>
|
||||
<path>Previews/cockpit.png</path>
|
||||
</preview>
|
||||
</previews>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
12
catalog/testData/Aircraft/f16/f16b-set.xml
Normal file
12
catalog/testData/Aircraft/f16/f16b-set.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<name>f16b</name>
|
||||
<description>F16-B</description>
|
||||
<long-description>The F16-B is an upgraded version of the F16A.</long-description>
|
||||
<variant-of>f16a</variant-of>
|
||||
|
||||
<author>James T Kirk</author>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
10
catalog/testData/Aircraft/f16/f16c-set.xml
Normal file
10
catalog/testData/Aircraft/f16/f16c-set.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<name>f16c</name>
|
||||
<description>F16-C</description>
|
||||
<long-description>The F16-C is an upgraded version of the F16A.</long-description>
|
||||
<variant-of>f16a</variant-of>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
12
catalog/testData/OtherDir/settings-common.xml
Normal file
12
catalog/testData/OtherDir/settings-common.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
|
||||
<!-- this file exists to test including + overlaying in the set XML -->
|
||||
|
||||
<PropertyList>
|
||||
<views>
|
||||
<view n="0">
|
||||
<foo>dsdddd</foo>
|
||||
</view>
|
||||
</views>
|
||||
|
||||
</PropertyList>
|
116
catalog/test_catalog.py
Executable file
116
catalog/test_catalog.py
Executable file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
import sgprops
|
||||
import os
|
||||
import catalog
|
||||
import lxml.etree as ET
|
||||
|
||||
class UpdateCatalogTests(unittest.TestCase):
|
||||
def test_scan_set(self):
|
||||
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"])
|
||||
self.assertEqual(info['id'], 'f16a')
|
||||
self.assertEqual(info['name'], 'F16-A')
|
||||
self.assertEqual(info['primary-set'], True)
|
||||
self.assertEqual(info['variant-of'], None)
|
||||
self.assertEqual(info['author'], 'Wilbur Wright')
|
||||
self.assertEqual(info['rating_FDM'], 3)
|
||||
self.assertEqual(info['rating_model'], 5)
|
||||
self.assertEqual(len(info['tags']), 3)
|
||||
|
||||
def test_scan_dir(self):
|
||||
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"])
|
||||
|
||||
self.assertEqual(pkg['id'], 'f16a')
|
||||
f16trainer = next(v for v in variants if v['id'] == 'f16-trainer')
|
||||
self.assertEqual(pkg['author'], 'Wilbur Wright')
|
||||
self.assertEqual(len(variants), 3)
|
||||
|
||||
# test variant relatonship between
|
||||
self.assertEqual(pkg['variant-of'], None)
|
||||
self.assertEqual(pkg['primary-set'], True)
|
||||
|
||||
self.assertEqual(f16trainer['variant-of'], None)
|
||||
self.assertEqual(f16trainer['primary-set'], False)
|
||||
|
||||
f16b = next(v for v in variants if v['id'] == 'f16b')
|
||||
self.assertEqual(f16b['variant-of'], 'f16a')
|
||||
self.assertEqual(f16b['primary-set'], False)
|
||||
self.assertEqual(f16b['author'], 'James T Kirk')
|
||||
|
||||
f16c = next(v for v in variants if v['id'] == 'f16c')
|
||||
self.assertEqual(f16c['variant-of'], 'f16a')
|
||||
self.assertEqual(f16c['primary-set'], False)
|
||||
|
||||
self.assertEqual(f16c['author'], 'Wilbur Wright')
|
||||
|
||||
|
||||
def test_extract_previews(self):
|
||||
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"])
|
||||
previews = info['previews']
|
||||
self.assertEqual(len(previews), 3)
|
||||
self.assertEqual(2, len([p for p in previews if p['type'] == 'exterior']))
|
||||
self.assertEqual(1, len([p for p in previews if p['type'] == 'panel']))
|
||||
self.assertEqual(1, len([p for p in previews if p['path'] == 'Previews/exterior-1.png']))
|
||||
|
||||
def test_extract_tags(self):
|
||||
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"])
|
||||
tags = info['tags']
|
||||
|
||||
def test_node_creation(self):
|
||||
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"])
|
||||
|
||||
catalog_node = ET.Element('PropertyList')
|
||||
catalog_root = ET.ElementTree(catalog_node)
|
||||
|
||||
pkgNode = catalog.make_aircraft_node('f16', pkg, variants, "http://foo.com/testOutput/")
|
||||
catalog_node.append(pkgNode)
|
||||
|
||||
# write out so we can parse using sgprops
|
||||
# yes we are round-tripping via the disk, if you can improve
|
||||
# then feel free..
|
||||
if not os.path.isdir("testOutput"):
|
||||
os.mkdir("testOutput")
|
||||
|
||||
cat_file = os.path.join("testOutput", 'catalog_fragment.xml')
|
||||
catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True, pretty_print=True)
|
||||
|
||||
parsed = sgprops.readProps(cat_file)
|
||||
parsedPkgNode = parsed.getChild("package")
|
||||
|
||||
self.assertEqual(parsedPkgNode.name, "package");
|
||||
|
||||
self.assertEqual(parsedPkgNode.getValue('id'), pkg['id']);
|
||||
self.assertEqual(parsedPkgNode.getValue('dir'), 'f16');
|
||||
self.assertEqual(parsedPkgNode.getValue('url'), 'http://foo.com/testOutput/f16.zip');
|
||||
self.assertEqual(parsedPkgNode.getValue('thumbnail'), 'http://foo.com/testOutput/thumbnails/f16_thumbnail.jpg');
|
||||
self.assertEqual(parsedPkgNode.getValue('thumbnail-path'), 'thumbnail.jpg');
|
||||
|
||||
self.assertEqual(parsedPkgNode.getValue('name'), pkg['name']);
|
||||
self.assertEqual(parsedPkgNode.getValue('description'), pkg['description']);
|
||||
self.assertEqual(parsedPkgNode.getValue('author'), "Wilbur Wright");
|
||||
|
||||
parsedVariants = parsedPkgNode.getChildren("variant")
|
||||
self.assertEqual(len(parsedVariants), 3)
|
||||
|
||||
f16ANode = parsedPkgNode
|
||||
self.assertEqual(f16ANode.getValue('name'), 'F16-A');
|
||||
|
||||
for index, pv in enumerate(parsedVariants):
|
||||
var = variants[index]
|
||||
self.assertEqual(pv.getValue('name'), var['name']);
|
||||
self.assertEqual(pv.getValue('description'), var['description']);
|
||||
|
||||
if (var['id'] == 'f16-trainer'):
|
||||
self.assertEqual(pv.getValue('variant-of'), '_primary_')
|
||||
self.assertEqual(pv.getValue('author'), "Wilbur Wright");
|
||||
elif (var['id'] == 'f16b'):
|
||||
self.assertEqual(pv.getValue('variant-of'), 'f16a')
|
||||
self.assertEqual(pv.getValue('description'), 'The F16-B is an upgraded version of the F16A.')
|
||||
self.assertEqual(pv.getValue('author'), "James T Kirk");
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -12,6 +12,7 @@ import time
|
||||
import sgprops
|
||||
import sys
|
||||
import catalogTags
|
||||
import catalog
|
||||
|
||||
CATALOG_VERSION = 4
|
||||
|
||||
@ -35,138 +36,6 @@ def get_xml_text(e):
|
||||
else:
|
||||
return ''
|
||||
|
||||
# create an xml node with text content
|
||||
def make_xml_leaf(name, text):
|
||||
leaf = ET.Element(name)
|
||||
if text != None:
|
||||
if isinstance(text, (int, long)):
|
||||
leaf.text = str(text)
|
||||
else:
|
||||
leaf.text = text
|
||||
else:
|
||||
leaf.text = ''
|
||||
return leaf
|
||||
|
||||
# return all available aircraft information from the set file as a
|
||||
# dict
|
||||
def scan_set_file(aircraft_dir, set_file):
|
||||
global includes
|
||||
|
||||
base_file = os.path.basename(set_file)
|
||||
base_id = base_file[:-8]
|
||||
set_path = os.path.join(aircraft_dir, set_file)
|
||||
|
||||
local_includes = includes
|
||||
local_includes.append(aircraft_dir)
|
||||
root_node = sgprops.readProps(set_path, includePaths = local_includes)
|
||||
|
||||
if not root_node.hasChild("sim"):
|
||||
return None
|
||||
|
||||
sim_node = root_node.getChild("sim")
|
||||
if sim_node == None:
|
||||
return None
|
||||
|
||||
variant = {}
|
||||
variant['name'] = sim_node.getValue("description", None)
|
||||
variant['status'] = sim_node.getValue("status", None)
|
||||
variant['author'] = sim_node.getValue("author", None)
|
||||
variant['description'] = sim_node.getValue("long-description", None)
|
||||
variant['id'] = base_id
|
||||
|
||||
# allow -set.xml files to declare themselves as primary.
|
||||
# we use this avoid needing a variant-of in every other -set.xml
|
||||
variant['primary-set'] = sim_node.getValue('primary-set', False)
|
||||
|
||||
# extract and record previews for each variant
|
||||
if sim_node.hasChild('previews'):
|
||||
print "has previews ..."
|
||||
variant['previews'] = extract_previews(sim_node.getChild('previews'), aircraft_dir)
|
||||
|
||||
if sim_node.hasChild('rating'):
|
||||
rating_node = sim_node.getChild("rating")
|
||||
variant['rating_FDM'] = rating_node.getValue("FDM", 0)
|
||||
variant['rating_systems'] = rating_node.getValue("systems", 0)
|
||||
variant['rating_cockpit'] = rating_node.getValue("cockpit", 0)
|
||||
variant['rating_model'] = rating_node.getValue("model", 0)
|
||||
|
||||
if sim_node.hasChild('tags'):
|
||||
variant['tags'] = extract_tags(sim_node.getChild('tags'), set_file)
|
||||
|
||||
if sim_node.hasChild('thumbnail'):
|
||||
variant['thumbnail'] = sim_node.getValue("thumbnail", None)
|
||||
|
||||
variant['variant-of'] = sim_node.getValue("variant-of", None)
|
||||
#print ' ', variant
|
||||
return variant
|
||||
|
||||
def extract_previews(previews_node, aircraft_dir):
|
||||
result = []
|
||||
for node in previews_node.getChildren("preview"):
|
||||
previewType = node.getValue("type", None)
|
||||
previewPath = node.getValue("path", None)
|
||||
|
||||
# check path exists in base-name-dir
|
||||
fullPath = os.path.join(aircraft_dir, previewPath)
|
||||
if not os.path.isfile(fullPath):
|
||||
print "Bad preview path, skipping:" + fullPath
|
||||
continue
|
||||
result.append({'type':previewType, 'path':previewPath})
|
||||
|
||||
return result
|
||||
|
||||
def extract_tags(tags_node, set_path):
|
||||
result = []
|
||||
for node in tags_node.getChildren("tag"):
|
||||
tag = node.value
|
||||
# check tag is in the allowed list
|
||||
if not catalogTags.isValidTag(tag):
|
||||
print "Unknown tag value:", tag, " in ", set_path
|
||||
result.append(tag)
|
||||
|
||||
return result
|
||||
|
||||
# scan all the -set.xml files in an aircraft directory. Returns a
|
||||
# package dict and a list of variants.
|
||||
def scan_aircraft_dir(aircraft_dir):
|
||||
setDicts = []
|
||||
primaryAircraft = []
|
||||
package = None
|
||||
|
||||
files = os.listdir(aircraft_dir)
|
||||
for file in sorted(files, key=lambda s: s.lower()):
|
||||
if file.endswith('-set.xml'):
|
||||
try:
|
||||
d = scan_set_file(aircraft_dir, file)
|
||||
if d == None:
|
||||
continue
|
||||
except:
|
||||
print "Skipping set file since couldn't be parsed:", os.path.join(aircraft_dir, file), sys.exc_info()[0]
|
||||
continue
|
||||
|
||||
setDicts.append(d)
|
||||
if d['primary-set']:
|
||||
primaryAircraft.append(d)
|
||||
elif d['variant-of'] == None:
|
||||
primaryAircraft.append(d)
|
||||
|
||||
if len(setDicts) == 0:
|
||||
return None
|
||||
|
||||
# use the first one
|
||||
if len(primaryAircraft) == 0:
|
||||
print "Aircraft has no primary aircraft at all:", aircraft_dir
|
||||
primaryAircraft = [setDicts[0]]
|
||||
|
||||
package = primaryAircraft[0]
|
||||
if not 'thumbnail' in package:
|
||||
package['thumbnail'] = "thumbnail.jpg"
|
||||
|
||||
# variants is just all the set dicts except the first one
|
||||
variants = setDicts
|
||||
variants.remove(package)
|
||||
return (package, variants)
|
||||
|
||||
# use svn commands to report the last change date within dir
|
||||
def last_change_date_svn(dir):
|
||||
command = [ 'svn', 'info', dir ]
|
||||
@ -215,18 +84,6 @@ def get_md5sum(file):
|
||||
f.close()
|
||||
return md5sum
|
||||
|
||||
def append_preview_nodes(node, variant, download_base, package_name):
|
||||
if not 'previews' in variant:
|
||||
return
|
||||
|
||||
for preview in variant['previews']:
|
||||
preview_node = ET.Element('preview')
|
||||
preview_url = download_base + 'previews/' + package_name + '_' + preview['path']
|
||||
preview_node.append( make_xml_leaf('type', preview['type']) )
|
||||
preview_node.append( make_xml_leaf('url', preview_url) )
|
||||
preview_node.append( make_xml_leaf('path', preview['path']) )
|
||||
node.append(preview_node)
|
||||
|
||||
def copy_previews_for_variant(variant, package_name, package_dir, previews_dir):
|
||||
if not 'previews' in variant:
|
||||
return
|
||||
@ -266,12 +123,74 @@ def copy_thumbnails_for_package(package, variants, package_name, package_dir, th
|
||||
for v in variants:
|
||||
copy_thumbnail_for_variant(v, package_name, package_dir, thumbnails_dir)
|
||||
|
||||
def append_tag_nodes(node, variant):
|
||||
if not 'tags' in variant:
|
||||
def process_aircraft_dir(name, repo_path):
|
||||
global includes
|
||||
global download_base
|
||||
global output_dir
|
||||
global valid_zips
|
||||
global previews_dir
|
||||
|
||||
aircraft_dir = os.path.join(repo_path, name)
|
||||
if not os.path.isdir(aircraft_dir):
|
||||
return
|
||||
|
||||
for tag in variant['tags']:
|
||||
node.append(make_xml_leaf('tag', tag))
|
||||
(package, variants) = catalog.scan_aircraft_dir(aircraft_dir, includes)
|
||||
if package == None:
|
||||
print "skipping:", name, "(no -set.xml files)"
|
||||
return
|
||||
|
||||
print "%s:" % name,
|
||||
|
||||
package_node = catalog.make_aircraft_node(name, package, variants, download_base)
|
||||
|
||||
download_url = download_base + name + '.zip'
|
||||
thumbnail_url = download_base + 'thumbnails/' + name + '_' + package['thumbnail']
|
||||
|
||||
# get cached md5sum if it exists
|
||||
md5sum = get_xml_text(md5sum_root.find(str('aircraft_' + name)))
|
||||
|
||||
# now do the packaging and rev number stuff
|
||||
dir_mtime = scan_dir_for_change_date_mtime(aircraft_dir)
|
||||
if repo_type == 'svn':
|
||||
rev = last_change_date_svn(aircraft_dir)
|
||||
else:
|
||||
d = datetime.datetime.utcfromtimestamp(dir_mtime)
|
||||
rev = d.strftime("%Y%m%d")
|
||||
package_node.append( catalog.make_xml_leaf('revision', rev) )
|
||||
#print "rev:", rev
|
||||
#print "dir mtime:", dir_mtime
|
||||
zipfile = os.path.join( output_dir, name + '.zip' )
|
||||
valid_zips.append(name + '.zip')
|
||||
if not os.path.exists(zipfile) \
|
||||
or dir_mtime > os.path.getmtime(zipfile) \
|
||||
or args.clean:
|
||||
# rebuild zip file
|
||||
print "updating:", zipfile
|
||||
make_aircraft_zip(repo_path, name, zipfile)
|
||||
md5sum = get_md5sum(zipfile)
|
||||
else:
|
||||
print "(no change)"
|
||||
if md5sum == "":
|
||||
md5sum = get_md5sum(zipfile)
|
||||
filesize = os.path.getsize(zipfile)
|
||||
package_node.append( catalog.make_xml_leaf('md5', md5sum) )
|
||||
package_node.append( catalog.make_xml_leaf('file-size-bytes', filesize) )
|
||||
|
||||
# handle md5sum cache
|
||||
node = md5sum_root.find('aircraft_' + name)
|
||||
if node != None:
|
||||
node.text = md5sum
|
||||
else:
|
||||
md5sum_root.append( catalog.make_xml_leaf('aircraft_' + name, md5sum) )
|
||||
|
||||
# handle thumbnails
|
||||
copy_thumbnails_for_package(package, variants, name, aircraft_dir, thumbnail_dir)
|
||||
|
||||
catalog_node.append(package_node)
|
||||
|
||||
# copy previews for the package and variants into the
|
||||
# output directory
|
||||
copy_previews_for_package(package, variants, name, aircraft_dir, previews_dir)
|
||||
|
||||
#def get_file_stats(file):
|
||||
# f = open(file, 'r')
|
||||
@ -305,6 +224,9 @@ else:
|
||||
scm_list = config_node.findall('scm')
|
||||
upload_node = config_node.find('upload')
|
||||
download_base = get_xml_text(config_node.find('download-url'))
|
||||
if not download_base.endswith('/'):
|
||||
download_base += '/'
|
||||
|
||||
output_dir = get_xml_text(config_node.find('local-output'))
|
||||
if output_dir == '':
|
||||
output_dir = os.path.join(args.dir, 'output')
|
||||
@ -378,112 +300,8 @@ for scm in scm_list:
|
||||
print "skipping:", name
|
||||
continue
|
||||
|
||||
aircraft_dir = os.path.join(repo_path, name)
|
||||
if os.path.isdir(aircraft_dir):
|
||||
print "%s:" % name,
|
||||
(package, variants) = scan_aircraft_dir(aircraft_dir)
|
||||
if package == None:
|
||||
print "skipping:", name, "(no -set.xml files)"
|
||||
continue
|
||||
#print "package:", package
|
||||
#print "variants:", variants
|
||||
package_node = ET.Element('package')
|
||||
package_node.append( make_xml_leaf('name', package['name']) )
|
||||
package_node.append( make_xml_leaf('status', package['status']) )
|
||||
package_node.append( make_xml_leaf('author', package['author']) )
|
||||
package_node.append( make_xml_leaf('description', package['description']) )
|
||||
if 'rating_FDM' in package or 'rating_systems' in package \
|
||||
or 'rating_cockpit' in package or 'rating_model' in package:
|
||||
rating_node = ET.Element('rating')
|
||||
package_node.append(rating_node)
|
||||
rating_node.append( make_xml_leaf('FDM',
|
||||
package['rating_FDM']) )
|
||||
rating_node.append( make_xml_leaf('systems',
|
||||
package['rating_systems']) )
|
||||
rating_node.append( make_xml_leaf('cockpit',
|
||||
package['rating_cockpit']) )
|
||||
rating_node.append( make_xml_leaf('model',
|
||||
package['rating_model']) )
|
||||
package_node.append( make_xml_leaf('id', package['id']) )
|
||||
for variant in variants:
|
||||
variant_node = ET.Element('variant')
|
||||
package_node.append(variant_node)
|
||||
variant_node.append( make_xml_leaf('id', variant['id']) )
|
||||
variant_node.append( make_xml_leaf('name', variant['name']) )
|
||||
if 'description' in variant:
|
||||
variant_node.append( make_xml_leaf('description', variant['description']) )
|
||||
|
||||
if 'author' in variant:
|
||||
variant_node.append( make_xml_leaf('author', variant['author']) )
|
||||
|
||||
if 'thumbnail' in variant:
|
||||
# note here we prefix with the package name, since the thumbnail path
|
||||
# is assumed to be unique within the package
|
||||
thumbUrl = download_base + "thumbnails/" + name + '_' + variant['thumbnail']
|
||||
variant_node.append(make_xml_leaf('thumbnail', thumbUrl))
|
||||
variant_node.append(make_xml_leaf('thumbnail-path', variant['thumbnail']))
|
||||
|
||||
append_preview_nodes(variant_node, variant, download_base, name)
|
||||
append_tag_nodes(variant_node, variant)
|
||||
|
||||
package_node.append( make_xml_leaf('dir', name) )
|
||||
if not download_base.endswith('/'):
|
||||
download_base += '/'
|
||||
download_url = download_base + name + '.zip'
|
||||
thumbnail_url = download_base + 'thumbnails/' + name + '_' + package['thumbnail']
|
||||
|
||||
package_node.append( make_xml_leaf('url', download_url) )
|
||||
package_node.append( make_xml_leaf('thumbnail', thumbnail_url) )
|
||||
package_node.append( make_xml_leaf('thumbnail-path', package['thumbnail']))
|
||||
|
||||
append_preview_nodes(package_node, package, download_base, name)
|
||||
append_tag_nodes(package_node, package)
|
||||
|
||||
# get cached md5sum if it exists
|
||||
md5sum = get_xml_text(md5sum_root.find(str('aircraft_' + name)))
|
||||
|
||||
# now do the packaging and rev number stuff
|
||||
dir_mtime = scan_dir_for_change_date_mtime(aircraft_dir)
|
||||
if repo_type == 'svn':
|
||||
rev = last_change_date_svn(aircraft_dir)
|
||||
else:
|
||||
d = datetime.datetime.utcfromtimestamp(dir_mtime)
|
||||
rev = d.strftime("%Y%m%d")
|
||||
package_node.append( make_xml_leaf('revision', rev) )
|
||||
#print "rev:", rev
|
||||
#print "dir mtime:", dir_mtime
|
||||
zipfile = os.path.join( output_dir, name + '.zip' )
|
||||
valid_zips.append(name + '.zip')
|
||||
if not os.path.exists(zipfile) \
|
||||
or dir_mtime > os.path.getmtime(zipfile) \
|
||||
or args.clean:
|
||||
# rebuild zip file
|
||||
print "updating:", zipfile
|
||||
make_aircraft_zip(repo_path, name, zipfile)
|
||||
md5sum = get_md5sum(zipfile)
|
||||
else:
|
||||
print "(no change)"
|
||||
if md5sum == "":
|
||||
md5sum = get_md5sum(zipfile)
|
||||
filesize = os.path.getsize(zipfile)
|
||||
package_node.append( make_xml_leaf('md5', md5sum) )
|
||||
package_node.append( make_xml_leaf('file-size-bytes', filesize) )
|
||||
|
||||
# handle md5sum cache
|
||||
node = md5sum_root.find('aircraft_' + name)
|
||||
if node != None:
|
||||
node.text = md5sum
|
||||
else:
|
||||
md5sum_root.append( make_xml_leaf('aircraft_' + name, md5sum) )
|
||||
|
||||
# handle thumbnails
|
||||
copy_thumbnails_for_package(package, variants, name, aircraft_dir, thumbnail_dir)
|
||||
|
||||
catalog_node.append(package_node)
|
||||
|
||||
# copy previews for the package and variants into the
|
||||
# output directory
|
||||
copy_previews_for_package(package, variants, name, aircraft_dir, previews_dir)
|
||||
# process each aircraft in turn
|
||||
process_aircraft_dir(name, repo_path)
|
||||
|
||||
# write out the master catalog file
|
||||
cat_file = os.path.join(output_dir, 'catalog.xml')
|
||||
|
Loading…
Reference in New Issue
Block a user