Compare commits

..

7 Commits

Author SHA1 Message Date
Automatic Release Builder
1949900359 new version: 2017.1.3 2017-04-04 08:59:05 +02:00
Automatic Release Builder
d3d16d122b new version: 2017.1.2 2017-03-01 20:41:09 +01:00
Automatic Release Builder
16dd404983 Update submodule heads for release/2017.1 2017-02-22 18:08:22 +01:00
Automatic Release Builder
c4f6efe18f There is also no fgpanel icon 2017-02-21 15:23:55 +01:00
Automatic Release Builder
c4af97e4f7 Disable fgpanel for windows due to missing glew dependency 2017-02-21 15:21:58 +01:00
Automatic Release Builder
7431c6253f desperate attempt to get fgdata cloned 2017-02-21 11:28:53 +01:00
Automatic Release Builder
f98d36ab3a set correct release-branch for submodules 2017-02-20 18:52:19 +01:00
44 changed files with 325 additions and 3691 deletions

23
.gitattributes vendored
View File

@@ -1,23 +0,0 @@
# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
.gitattributes text export-ignore
.gitignore text export-ignore
*.py text
*.txt text
*.rst text
*.xml text
*.desktop text
*.svg text
*.jpg binary
*.png binary
*.gif binary
*.bat text eol=crlf
AUTHORS text
COPYING text
COPYING.* text
README.* text
Makefile text
ChangeLog text
ChangeLog.* text
/download_and_compile.sh text ident

1
.gitignore vendored
View File

@@ -21,4 +21,3 @@ osgbuild
CMakeCache.txt
*.pyc
build-*
testOutput*

10
.gitmodules vendored
View File

@@ -1,11 +1,11 @@
[submodule "simgear"]
path = simgear
url = https://git.code.sf.net/p/flightgear/simgear
branch = release/2017.3
branch = release/2017.1
[submodule "flightgear"]
path = flightgear
url = https://git.code.sf.net/p/flightgear/flightgear
branch = release/2017.3
branch = release/2017.1
[submodule "fgrun"]
path = fgrun
url = https://git.code.sf.net/p/flightgear/fgrun
@@ -13,12 +13,8 @@
[submodule "fgdata"]
path = fgdata
url = git://git.code.sf.net/p/flightgear/fgdata
branch = release/2017.3
branch = release/2017.1
[submodule "windows-3rd-party"]
path = windows-3rd-party
url = https://git.code.sf.net/p/flightgear/windows-3rd-party
branch = master
[submodule "getstart"]
path = getstart
url = https://git.code.sf.net/p/flightgear/getstart
branch = release/2017.3

View File

@@ -109,6 +109,12 @@ Source: "{#ThirdPartyDir}\3rdParty.x64\bin\crashrpt_lang.ini"; DestDir: "{app}\b
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\CrashSender1403.exe"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#VCInstallDir}\redist\x64\Microsoft.VC140.CRT\*.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
; 32/64 bits install
;NOTE: FGPanel has no 64 bits equivalent, so we are using the 32 bits binary for 32&64 bits OS
;Torsten 2017-02-21: currently no FGPanel due to missing glew dependency
;Source: "{#InstallDir32}\bin\fgpanel.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
; Include the base package
#if IncludeData == "TRUE"
Source: "X:\fgdata\*.*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist
@@ -205,7 +211,7 @@ Name: "{group}\Flightgear Wiki"; Filename: "http://wiki.flightgear.org"
Name: "{group}\Tools\Uninstall FlightGear"; Filename: "{uninstallexe}"
Name: "{group}\Tools\fgjs"; Filename: "cmd"; Parameters: "/k fgjs.exe ""--fg-root={app}\data"""; WorkingDir: "{app}\bin"
Name: "{group}\Tools\yasim"; Filename: "cmd"; Parameters: "/k ""{app}\bin\yasim.exe"" -h"; WorkingDir: "{app}\bin"
Name: "{group}\Tools\fgpanel"; Filename: "cmd"; Parameters: "/k ""{app}\bin\fgpanel.exe"" -h"; WorkingDir: "{app}\bin"
;Name: "{group}\Tools\fgpanel"; Filename: "cmd"; Parameters: "/k ""{app}\bin\fgpanel.exe"" -h"; WorkingDir: "{app}\bin"
Name: "{group}\Tools\FGCom"; Filename: "{app}\bin\fgcom.exe"; WorkingDir: "{app}\bin"
Name: "{group}\Tools\FGCom-testing"; Filename: "{app}\bin\fgcom.exe"; Parameters: "--frequency=910"; WorkingDir: "{app}\bin"
Name: "{group}\Tools\Explore Documentation Folder"; Filename: "{app}\data\Docs"

View File

@@ -14,6 +14,7 @@ mkdir -p sgBuild
mkdir -p fgBuild
mkdir -p output
rm -rf output/*
rm -rf dist/*
#####################################################################################
echo "Starting on SimGear"
@@ -37,7 +38,7 @@ cp simgear-*.tar.bz2 ../output/.
#####################################################################################
echo "Starting on FlightGear"
cd ../fgBuild
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DSIMGEAR_SHARED:BOOL="ON" -DFG_BUILD_TYPE=Release ../flightgear
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DSIMGEAR_SHARED:BOOL="ON" ../flightgear
# compile
make
@@ -59,3 +60,4 @@ echo "Assembling base package"
cd $WORKSPACE
tar cjf output/FlightGear-$VERSION-data.tar.bz2 fgdata/

View File

@@ -1,12 +1,6 @@
IF NOT DEFINED WORKSPACE SET WORKSPACE=%~dp0
IF %IS_NIGHTLY_BUILD% EQU 1 (
SET FGBUILDTYPE=Nightly
) ELSE (
SET FGBUILDTYPE=Release
)
REM following are for testing the script locally
REM SET PATH=%PATH%;%ProgramFiles%\CMake\bin;%ProgramFiles(x86)%\"Inno Setup 5"\
REM SET QT5SDK32=C:\Qt\5.6\msvc2015
@@ -23,7 +17,6 @@ cd build-sg32
cmake ..\simgear -G "Visual Studio 14" ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DCMAKE_PREFIX_PATH:PATH=%OSG32% ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140
cmake --build . --config RelWithDebInfo --target INSTALL
@@ -34,9 +27,7 @@ cmake ..\flightgear -G "Visual Studio 14" ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140 ^
-DCMAKE_PREFIX_PATH:PATH=%WORKSPACE%/install/msvc140/OpenSceneGraph ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DCMAKE_PREFIX_PATH=%QT5SDK32%;%OSG32% ^
-DFG_BUILD_TYPE=%FGBUILDTYPE%
-DCMAKE_PREFIX_PATH=%QT5SDK32%;%OSG32%
cmake --build . --config RelWithDebInfo --target INSTALL
cd ..
@@ -49,7 +40,6 @@ cd build-sg64
cmake ..\SimGear -G "Visual Studio 14 Win64" ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DCMAKE_PREFIX_PATH:PATH=%OSG64% ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64
cmake --build . --config RelWithDebInfo --target INSTALL
@@ -59,9 +49,7 @@ cmake ..\flightgear -G "Visual Studio 14 Win64" ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64 ^
-DCMAKE_PREFIX_PATH=%QT5SDK64%;%OSG64% ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DFG_BUILD_TYPE=%FGBUILDTYPE%
-DCMAKE_PREFIX_PATH=%QT5SDK64%;%OSG64%
cmake --build . --config RelWithDebInfo --target INSTALL
cd ..
@@ -79,10 +67,9 @@ subst X: %WORKSPACE%.
REM ensure output dir is clean since we upload the entirety of it
rmdir /S /Q output
SET CRASHFIX_UPLOAD_URL=http://crashes.flightgear.org/index.php/debugInfo/uploadExternal
SET FGFS_PDB=src\Main\RelWithDebInfo\fgfs.pdb
ECHO Uploading PDB files to %CRASHFIX_UPLOAD_URL%
upload -v -u %CRASHFIX_UPLOAD_URL% FlightGear %WORKSPACE%\build-fg32\%FGFS_PDB% %WORKSPACE%\build-fg64\%FGFS_PDB%
REM archiving PDB files
copy %WORKSPACE%\build-fg32\src\Main\RelWithDebInfo\fgfs.pdb %WORKSPACE%\Output\fgfs-x86-%BUILD_NUMBER%.pdb
copy %WORKSPACE%\build-fg64\src\Main\RelWithDebInfo\fgfs.pdb %WORKSPACE%\Output\fgfs-x64-%BUILD_NUMBER%.pdb
REM indirect way to get command output into an environment variable
set PATH=%OSG32%\bin;%PATH%

View File

@@ -1,247 +0,0 @@
#!/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)
if sim_node.hasChild('author'):
variant['author'] = sim_node.getValue("author", None)
if sim_node.hasChild('long-description'):
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)
if sim_node.hasChild('minimum-fg-version'):
variant['minimum-fg-version'] = sim_node.getValue('minimum-fg-version', 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:
if (os.path.exists(os.path.join(aircraft_dir, "thumbnail.jpg"))):
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']) )
if 'author' in package:
package_node.append( make_xml_leaf('author', package['author']) )
if 'description' in package:
package_node.append( make_xml_leaf('description', package['description']) )
if 'minimum-fg-version' in package:
package_node.append( make_xml_leaf('minimum-fg-version', package['minimum-fg-version']) )
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'
package_node.append( make_xml_leaf('url', download_url) )
if 'thumbnail' in package:
thumbnail_url = downloadBase + 'thumbnails/' + aircraftDirName + '_' + package['thumbnail']
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

View File

@@ -1,164 +1,80 @@
aircraftTypeTags = [
"aerobatic",
"airship",
"balloon",
"bizjet",
"bomber",
"cargo",
"carrier",
"fighter",
"ga",
"glider",
"groundvehicle",
"helicopter",
"racer",
"spaceship",
"tanker",
"trainer",
"transport",
"ultralight",
"reconnaissance",
"seacraft",
"crop-duster",
"bush-plane"
"ga", "fighter", "helicopter", "glider", "spaceship", "bomber", "groundvehicle",
"tanker", "cargo", "transport", "bizjet", "trainer", "airship", "balloon"
]
manufacturerTags = [
"airbus",
"antonov",
"atr",
"avro",
"bell",
"bleriot",
"boeing",
"bombardier",
"caudron",
"cessna",
"consolidated",
"dassault",
"diamond",
"dornier",
"douglas",
"embraer",
"eurocopter",
"fairchild",
"fairey",
"focke-wulf",
"fokker",
"general-dynamics",
"gotha",
"grumman",
"handley-page",
"hawker",
"heinkel",
"ilyushin",
"junkers",
"lockheed",
"mc-donnell-douglas",
"messerschmitt",
"mikoyan-gurevich",
"mitsubishi",
"north-american",
"northrop",
"pilatus",
"piper",
"republic",
"robin",
"saab",
"short",
"sopwith",
"spad",
"sukhoi",
"supermarine",
"tupolev",
"vickers",
"vought",
"yakovlev"
"boeing", "cessna", "diamond", "douglas", "bell", "piper",
"airbus", "vickers", "lockheed", "fokker",
"embraer", "bombardier", "pilatus", "robin",
"eurocopter"
]
eraTags = [
"1910s",
"early-pioneers",
"ww1",
"1920s",
"1930s",
"1940s",
"golden-age",
"ww2",
"coldwar", "vietnam",
"1950s",
"1960s",
"1970s",
"1980s",
"1990s",
"2000s",
"2010s",
"coldwar",
"early-pioneers",
"golden-age",
"gulfwar1",
"gulfwar2",
"vietnam",
"ww1",
"ww2"
"gulfwar2"
]
featureTags = [
"aerobatic",
"airship",
"amphibious",
"biplane",
"canard",
"castering-wheel",
"delta",
"etops",
"experimental",
"fictional",
"fixed-gear",
"floats",
"glass-cockpit",
"high-wing",
"h-tail",
"hud",
"ifr",
"prototype",
"refuel",
"retractable-gear",
"fixed-gear",
"tail-dragger",
"seaplane",
"skis",
"vtol",
"stol",
"experimental",
"prototype",
"fictional",
"biplane",
"triplane",
"supersonic",
"t-tail",
"tail-dragger",
"tricycle",
"tail-hook",
"triplane",
"v-tail",
"high-wing",
"cannard",
"tail-hook",
"refuel",
"delta",
"variable-geometry",
"vtol",
"wing-fold"
"glass-cockpit",
"hud",
"etops",
"floats",
"amphibious",
"airship",
"aerobatic"
]
propulsionTags = [
"afterburner",
"piston", "radial",
"diesel",
"electric",
"jet",
"propeller",
"piston",
"radial",
"rocket",
"single-engine",
"variable-pitch",
"supercharged",
"turboprop",
"jet", "afterburner", "rocket",
"electric",
"twin-engine",
"variable-pitch",
"fixed-pitch"
"single-engine"
]
simFeatureTags = [
"dual-controls",
"rembrandt",
"tow",
"wildfire"
"dual-controls",
"rembrandt"
]
tags = aircraftTypeTags + manufacturerTags + eraTags + simFeatureTags + propulsionTags + featureTags
def isValidTag(maybeTag):
return maybeTag in tags

View File

@@ -185,13 +185,12 @@ class PropsHandler(handler.ContentHandler):
if 'include' in attrs.keys():
self.handleInclude(attrs['include'])
return
currentState = self._stateStack[-1]
if 'n' in attrs.keys():
try:
index = int(attrs['n'])
except:
print "Invalid index at line:", self._locator.getLineNumber(), "of", self._path
raise IndexError("Invalid index at line:", self._locator.getLineNumber(), "of", self._path)
currentState.recordExplicitIndex(name, index)

View File

@@ -1,8 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<PropertyList>
<sim>
<name>c150</name>
<description>Cessna 150</description>
</sim>
</PropertyList>

View File

@@ -1,13 +0,0 @@
<?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>
<minimum-fg-version>2017.4</minimum-fg-version>
</sim>
</PropertyList>

View File

@@ -1,11 +0,0 @@
<?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>

View File

@@ -1,36 +0,0 @@
<?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>

View File

@@ -1,12 +0,0 @@
<?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>

View File

@@ -1,10 +0,0 @@
<?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>

View File

@@ -1,12 +0,0 @@
<?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>

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<sim>
<!-- found in the F-15 XML -->
<uhf n="[0]">
<frequencies>
<selected-mhz type="int">225000</selected-mhz>
</frequencies>
</uhf>
</sim>
</PropertyList>
<uhf n="[0]">
<frequencies>
<selected-mhz type="int">225000</selected-mhz>
</frequencies>
</uhf>
</sim>
</PropertyList>

View File

@@ -1,149 +0,0 @@
#!/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)
self.assertEqual(info['minimum-fg-version'], '2017.4')
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)
self.assertEqual(pkg['minimum-fg-version'], '2017.4')
# 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");
self.assertEqual(parsedPkgNode.getValue('minimum-fg-version'), "2017.4");
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");
def test_minimalAircraft(self):
# test an aircraft with a deliberately spartan -set.xml file with
# most interesting data missing
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/c150", ["testData/OtherDir"])
catalog_node = ET.Element('PropertyList')
catalog_root = ET.ElementTree(catalog_node)
pkgNode = catalog.make_aircraft_node('c150', pkg, variants, "http://foo.com/testOutput/")
catalog_node.append(pkgNode)
if not os.path.isdir("testOutput2"):
os.mkdir("testOutput2")
cat_file = os.path.join("testOutput2", '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.getValue('id'), pkg['id'])
self.assertEqual(parsedPkgNode.getValue('dir'), 'c150')
self.assertEqual(parsedPkgNode.getValue('url'), 'http://foo.com/testOutput/c150.zip')
self.assertFalse(parsedPkgNode.hasChild('thumbnail'))
self.assertFalse(parsedPkgNode.hasChild('thumbnail-path'));
self.assertEqual(parsedPkgNode.getValue('name'), pkg['name']);
self.assertFalse(parsedPkgNode.hasChild('description'));
self.assertFalse(parsedPkgNode.hasChild('author'));
self.assertFalse(parsedPkgNode.hasChild('minimum-fg-version'));
self.assertFalse(parsedPkgNode.hasChild('variant'));
if __name__ == '__main__':
unittest.main()

View File

@@ -11,8 +11,6 @@ import subprocess
import time
import sgprops
import sys
import catalogTags
import catalog
CATALOG_VERSION = 4
@@ -36,6 +34,127 @@ 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)
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
# 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):
# old way of finding the master aircraft: it's the only one whose
# variant-of is empty. All the others have an actual value
# newer alternative is to specify one -set.xml as the primary. All the
# others are therefore variants.
setDicts = []
found_master = False
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']:
found_master = True
package = d
# didn't find a dict identified explicitly as the primary, look for one
# with an undefined variant-of
if not found_master:
for d in setDicts:
if d['variant-of'] == '':
found_master = True
package = d
break
if not found_master:
if len(setDicts) > 1:
print "Warning, no explicit primary set.xml in " + aircraft_dir
# use the first one
package = setDicts[0]
# variants is just all the set dicts except the master
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 ]
@@ -84,6 +203,18 @@ 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
@@ -103,95 +234,6 @@ def copy_previews_for_package(package, variants, package_name, package_dir, prev
for v in variants:
copy_previews_for_variant(v, package_name, package_dir, previews_dir)
def copy_thumbnail_for_variant(variant, package_name, package_dir, thumbnails_dir):
if not 'thumbnail' in variant:
return
thumb_src = os.path.join(package_dir, variant['thumbnail'])
thumb_dst = os.path.join(thumbnails_dir, package_name + '_' + variant['thumbnail'])
dir = os.path.dirname(thumb_dst)
if not os.path.isdir(dir):
os.makedirs(dir)
if os.path.exists(thumb_src):
shutil.copy2(thumb_src, thumb_dst)
def copy_thumbnails_for_package(package, variants, package_name, package_dir, thumbnails_dir):
copy_thumbnail_for_variant(package, package_name, package_dir, thumbnails_dir)
# and now each variant in turn
for v in variants:
copy_thumbnail_for_variant(v, package_name, package_dir, thumbnails_dir)
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
(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')
# md5 = hashlib.md5(f.read()).hexdigest()
@@ -224,9 +266,6 @@ 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')
@@ -300,8 +339,106 @@ for scm in scm_list:
print "skipping:", name
continue
# process each aircraft in turn
process_aircraft_dir(name, repo_path)
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']) )
append_preview_nodes(variant_node, variant, download_base, name)
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 + '_thumbnail.jpg'
package_node.append( make_xml_leaf('url', download_url) )
package_node.append( make_xml_leaf('thumbnail', thumbnail_url) )
append_preview_nodes(package_node, package, download_base, name)
# todo: url (download), thumbnail (download url)
# 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
thumbnail_src = os.path.join(aircraft_dir, 'thumbnail.jpg')
thumbnail_dst = os.path.join(thumbnail_dir, name + '_thumbnail.jpg')
if os.path.exists(thumbnail_src):
shutil.copy2(thumbnail_src, thumbnail_dst)
catalog_node.append(package_node)
package_node.append( make_xml_leaf('thumbnail-path', 'thumbnail.jpg') )
# copy previews for the package and variants into the
# output directory
copy_previews_for_package(package, variants, name, aircraft_dir, previews_dir)
# write out the master catalog file
cat_file = os.path.join(output_dir, 'catalog.xml')

View File

@@ -17,15 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
script_blob_id='$Id$'
# Slightly tricky substitution to avoid our regexp being wildly replaced with
# the blob name (id) when the script is checked out:
#
# First extract the hexadecimal blob object name followed by a '$'
VERSION="$(echo "$script_blob_id" | sed 's@\$Id: *\([0-9a-f]\+\) *@\1@')"
# Then remove the trailing '$'
VERSION="${VERSION%\$}"
VERSION="2.34"
FGVERSION="release/$(git ls-remote --heads https://git.code.sf.net/p/flightgear/flightgear|grep '\/release\/'|cut -f4 -d'/'|sort -t . -k 1,1n -k2,2n -k3,3n|tail -1)"
#######################################################
@@ -108,16 +100,6 @@ function _logSep(){
echo "***********************************" >> $LOGFILE
}
function _aptUpdate(){
echo "Asking password for 'apt-get update'..."
sudo apt-get update
}
function _aptInstall(){
echo "Asking password for 'apt-get install $*'..."
sudo apt-get install "$@"
}
function _gitUpdate(){
if [ "$DOWNLOAD" != "y" ]; then
return
@@ -161,48 +143,6 @@ function _make(){
fi
}
# Find an available, non-virtual package matching one of the given regexps.
#
# Each positional parameter is interpreted as a POSIX extended regular
# expression. These parameters are examined from left to right, and the first
# available matching package is added to the global PKG variable. If no match
# is found, the script aborts.
function _package_alternative(){
if [[ $# -lt 1 ]]; then
echo "Empty package alternative: this is a bug in the script, aborting."
exit 1
fi
echo "Considering a package alternative:" "$@"
_package_alternative_inner "$@"
}
# This function requires the 'dctrl-tools' package
function _package_alternative_inner(){
local pkg
if [[ $# -lt 1 ]]; then
echo "No match found for the package alternative, aborting."
exit 1
fi
# This finds non-virtual packages only (on purpose)
pkg="$(apt-cache dumpavail | \
grep-dctrl -e -sPackage -FPackage \
"^[[:space:]]*($1)[[:space:]]*\$" - | \
sed -ne '1s/^Package:[[:space:]]*//gp')"
if [[ -n "$pkg" ]]; then
echo "Package alternative matched for $pkg"
PKG="$PKG $pkg"
return 0
else
# Try with the next regexp
shift
_package_alternative_inner "$@"
fi
}
#######################################################
# set script to stop if an error occours
set -e
@@ -261,23 +201,6 @@ _logSep
#######################################################
#######################################################
if [[ "$DOWNLOAD_PACKAGES" = "y" ]] && [[ "$APT_GET_UPDATE" = "y" ]]; then
_aptUpdate
fi
# Ensure 'dctrl-tools' is installed
if [[ "$(dpkg-query --showformat='${db:Status-Status}\n' --show dctrl-tools \
2>/dev/null)" != "installed" ]]; then
if [[ "$DOWNLOAD_PACKAGES" = "y" ]]; then
_aptInstall dctrl-tools
else
echo -n "The 'dctrl-tools' package is needed, but DOWNLOAD_PACKAGES is "
echo -e "not set to 'y'.\nAborting."
exit 1
fi
fi
# Minimum
PKG="build-essential cmake git"
# cmake
@@ -287,12 +210,9 @@ PKG="$PKG libcgal-dev libgdal-dev libtiff5-dev"
# TGGUI/OpenRTI
PKG="$PKG libqt4-dev"
# SG/FG
PKG="$PKG zlib1g-dev freeglut3-dev libboost-dev"
_package_alternative libopenscenegraph-3.4-dev libopenscenegraph-dev \
'libopenscenegraph-[0-9]+\.[0-9]+-dev'
PKG="$PKG zlib1g-dev freeglut3-dev libboost-dev libopenscenegraph-dev"
# FG
PKG="$PKG libopenal-dev libudev-dev qt5-default qtdeclarative5-dev libdbus-1-dev libplib-dev"
_package_alternative libpng-dev libpng12-dev libpng16-dev
PKG="$PKG libopenal-dev libudev-dev qt5-default libdbus-1-dev libpng12-dev libplib-dev"
# FGPanel
PKG="$PKG fluid libbz2-dev libfltk1.3-dev libxi-dev libxmu-dev"
# FGAdmin
@@ -304,8 +224,12 @@ PKG="$PKG python-tk"
# FGx (FGx is not compatible with Qt5, however we have installed Qt5 by default)
#PKG="$PKG libqt5xmlpatterns5-dev libqt5webkit5-dev"
if [[ "$DOWNLOAD_PACKAGES" = "y" ]]; then
_aptInstall $PKG
if [ "$DOWNLOAD_PACKAGES" = "y" ]; then
echo "Asking password for apt-get operations..."
if [ "$APT_GET_UPDATE" = "y" ]; then
sudo apt-get update
fi
sudo apt-get install $PKG
fi
#######################################################
@@ -455,8 +379,8 @@ if [[ "$(declare -p WHATTOBUILD)" =~ '['([0-9]+)']="OSG"' ]]; then
echo "****************************************" | tee -a $LOGFILE
cd "$CBD"/openscenegraph
_gitDownload https://github.com/openscenegraph/osg.git
_gitUpdate OpenSceneGraph-3.4
_gitUpdate OpenSceneGraph-3.2
if [ "$RECONFIGURE" = "y" ]; then
cd "$CBD"
mkdir -p build/openscenegraph

2
fgdata

Submodule fgdata updated: 5b4983c716...9dc91304b4

Submodule getstart deleted from a75fedfc67

View File

@@ -21,7 +21,7 @@ echo "Build path is: $PATH"
###############################################################################
echo "Starting on SimGear"
pushd sgBuild
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DCMAKE_BUILD_TYPE=RelWithDebInfo ../simgear
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DENABLE_CURL:BOOL="ON" -DCMAKE_BUILD_TYPE=RelWithDebInfo ../simgear
# compile
make
@@ -39,14 +39,7 @@ popd
################################################################################
echo "Starting on FlightGear"
pushd fgBuild
if [ $FG_IS_RELEASE == '1' ]; then
FGBUILDTYPE=Release
else
FGBUILDTYPE=Nightly
fi
cmake -DFG_BUILD_TYPE=$FGBUILDTYPE -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DCMAKE_BUILD_TYPE=RelWithDebInfo ../flightgear
cmake -DFG_NIGHTLY=1 -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DCMAKE_BUILD_TYPE=RelWithDebInfo ../flightgear
make

View File

@@ -1,83 +0,0 @@
Quick start for the localization (l10n) scripts
===============================================
The following assumes that all of these are in present in
$FG_ROOT/Translations:
- the default translation (default/*.xml);
- the legacy FlightGear XML localization files (<language_code>/*.xml);
- except for 'fg-convert-translation-files' which creates them, existing
XLIFF 1.2 files (<language_code>/FlightGear-nonQt.xlf).
Note: the legacy FlightGear XML localization files are only needed by
'fg-convert-translation-files' when migrating to the XLIFF format. The
other scripts only need the default translation and obviously, for
'fg-update-translation-files', the current XLIFF files.
To get the initial XLIFF files (generated from the default translation in
$FG_ROOT/Translations/default as well as the legacy FlightGear XML
localization files in $FG_ROOT/Translations/<language_code>):
languages="de en_US es fr it nl pl pt zh_CN"
# Your shell must expand $languages as several words. POSIX shell does that,
# but not zsh for instance. Otherwise, don't use a shell variable.
fg-convert-translation-files --transl-dir="$FG_ROOT/Translations" $languages
# Add strings found in the default translation but missing in the legacy FG
# XML l10n files
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
merge-new-master $languages
When master strings[1] have changed (in a large sense, i.e.: strings added,
modified or removed, or categories added or removed[2]):
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
merge-new-master $languages
To remove unused translated strings (not to be done too often in my opinion):
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
remove-unused $languages
(you may replace 'remove-unused' with 'mark-unused' to just mark the strings
as not-to-be-translated, however 'merge-new-master' presented above already
does that)
To create skeleton translations for new languages (e.g., for fr_BE, en_AU and
ca):
1) Check (add if necessary) that flightgear/meta/i18n.py knows the plural
forms used in the new languages. This is done by editing PLURAL_FORMS
towards the top of this i18n.py file (very easy). If the existing entry
for, e.g., "zh" is sufficient for zh_TW or zh_HK, just let "zh" handle
them: it will be tried as fallback if there is no perfect match on
language and territory.
2) Run a command such as:
fg-new-translations --transl-dir="$FG_ROOT/Translations" fr_BE en_AU ca
(if you do this for only one language at a time, you can use the -o
option to precisely control where the output goes, otherwise
fg-new-translations chooses an appropriate place based on the value
specified for --transl-dir)
fg-convert-translation-files, fg-update-translation-files and
fg-new-translations all support the --help option for more detailed
information.
Footnotes
---------
[1] Strings in the default translation.
[2] Only empty categories are removed by this command. An obsolete category
can be made empty by manual editing (easy, just locate the right
<group>) or this way:
fg-update-translation-files --transl-dir=... mark-unused
fg-update-translation-files --transl-dir=... remove-unused
(note that this will remove *all* strings marked as unused in the first
step, not only those in some particular category!)

View File

@@ -1,186 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# fg-convert-translation-files --- Convert FlightGear's translation files
# Copyright (C) 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
import collections
import locale
import os
import sys
try:
import xml.etree.ElementTree as et
except ImportError:
import elementtree.ElementTree as et
import flightgear.meta.logging
import flightgear.meta.i18n as fg_i18n
PROGNAME = os.path.basename(sys.argv[0])
# Only messages with severity >= info will be printed to the terminal (it's
# possible to also log all messages to a file regardless of their level, see
# the Logger class). Of course, there is also the standard logging module...
logger = flightgear.meta.logging.Logger(
progname=PROGNAME,
logLevel=flightgear.meta.logging.LogLevel.info,
defaultOutputStream=sys.stderr)
debug = logger.debug
info = logger.info
notice = logger.notice
warning = logger.warning
error = logger.error
critical = logger.critical
# We could use Translation.__str__(): not as readable (for now) but more
# accurate on metadata
def printPlainText(l10nResPoolMgr, translations):
"""Print output suitable for a quick review (by the programmer)."""
firstLang = True
for langCode, (transl, nbWhitespacePbs) in translations.items():
# 'transl' is a Translation instance
if firstLang:
firstLang = False
else:
print()
print("-" * 78 + "\n" + langCode + "\n" + "-" * 78)
print("\nNumber of leading and/or trailing whitespace problems: {}"
.format(nbWhitespacePbs))
for cat in transl:
print("\nCategory: {cat}\n{underline}".format(
cat=cat, underline="~"*(len("Category: ") + len(cat))))
t = transl[cat]
for tid, translUnit in sorted(t.items()):
# - Using '{master!r}' and '{transl!r}' prints stuff such as
# \xa0 for nobreak spaces, which can lead to the erroneous
# conclusion that there was an encoding problem.
# - Only printing the first target text here (no plural forms)
print("\n{id}\n '{sourceText}'\n '{targetText}'"
.format(id=tid.id(), sourceText=translUnit.sourceText,
targetText=translUnit.targetTexts[0]))
def writeXliff(l10nResPoolMgr, translations):
formatHandler = fg_i18n.XliffFormatHandler()
for langCode, translData in translations.items():
translation = translData.transl # Translation instance
if params.output_dir is None:
# Use default locations for the written xliff files
l10nResPoolMgr.writeTranslation(formatHandler, translation)
else:
basename = "{}-{}.{}".format(
formatHandler.defaultFileStem(langCode),
langCode,
formatHandler.standardExtension)
filePath = os.path.join(params.output_dir, basename)
formatHandler.writeTranslation(translation, filePath)
def processCommandLine():
params = argparse.Namespace()
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...] LANGUAGE_CODE...
Convert FlightGear's old XML translation files into other formats.""",
description="""\
Most notably, XLIFF format can be chosen for output. The script performs
a few automated checks on the input files too.""",
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
parser.add_argument("-t", "--transl-dir",
help="""\
directory containing all translation subdirs (such as
{default!r}, 'en_GB', 'fr_FR', 'de', 'it'...). This
"option" MUST be specified.""".format(
default=fg_i18n.DEFAULT_LANG_DIR))
parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="+",
help="""\
codes of languages to read translations for (don't
specify {default!r} this way, it is special and not a
language code)"""
.format(default=fg_i18n.DEFAULT_LANG_DIR))
parser.add_argument("-o", "--output-dir",
help="""\
output directory for written XLIFF files
(default: for each output file, use a suitable location
under TRANSL_DIR)""")
parser.add_argument("-f", "--output-format", default="xliff",
choices=("xliff", "text"), help="""\
format to use for the output files""")
parser.add_argument("--help", action="help",
help="display this message and exit")
params = parser.parse_args(namespace=params)
if params.transl_dir is None:
error("--transl-dir must be given, aborting")
sys.exit(1)
return params
def main():
global params
locale.setlocale(locale.LC_ALL, '')
params = processCommandLine()
l10nResPoolMgr = fg_i18n.L10NResourcePoolManager(params.transl_dir, logger)
# English version of all translatable strings
masterTransl, nbWhitespaceProblemsInMaster = \
l10nResPoolMgr.readFgMasterTranslation()
translations = collections.OrderedDict()
# Sort elements of 'translations' according to language code (= the keys)
for langCode in sorted(params.lang_code):
translationData = l10nResPoolMgr.readFgTranslation(masterTransl,
langCode)
translations[translationData.transl.targetLanguage] = translationData
if params.output_format == "xliff":
writeFunc = writeXliff # write to files
elif params.output_format == "text":
writeFunc = printPlainText # print to stdout
else:
assert False, \
"Unexpected output format: '{}'".format(params.output_format)
writeFunc(l10nResPoolMgr, translations)
nbWhitespaceProblemsInTransl = sum(
(translData.nbWhitespacePbs for translData in translations.values() ))
info("total number of leading and/or trailing whitespace problems: {}"
.format(nbWhitespaceProblemsInMaster + nbWhitespaceProblemsInTransl))
sys.exit(0)
if __name__ == "__main__": main()

View File

@@ -1,125 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# fg-new-translations --- Create new translations for FlightGear
# Copyright (C) 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
import collections
import locale
import os
import sys
try:
import xml.etree.ElementTree as et
except ImportError:
import elementtree.ElementTree as et
import flightgear.meta.logging
import flightgear.meta.i18n as fg_i18n
PROGNAME = os.path.basename(sys.argv[0])
# Only messages with severity >= info will be printed to the terminal (it's
# possible to also log all messages to a file regardless of their level, see
# the Logger class). Of course, there is also the standard logging module...
logger = flightgear.meta.logging.Logger(
progname=PROGNAME,
logLevel=flightgear.meta.logging.LogLevel.info,
defaultOutputStream=sys.stderr)
def processCommandLine():
params = argparse.Namespace()
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...] LANGUAGE_CODE...
Write the skeleton of XLIFF translation files.""",
description="""\
This program writes XLIFF translation files with the strings to translate
for the specified languages (target strings are empty). This is what you need
to start a translation for a new language.""",
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
parser.add_argument("-t", "--transl-dir",
help="""\
directory containing all translation subdirs (such as
{default!r}, 'en_GB', 'fr_FR', 'de', 'it'...). This
"option" MUST be specified.""".format(
default=fg_i18n.DEFAULT_LANG_DIR))
parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="+",
help="""\
codes of languages to create translations for (e.g., fr,
fr_BE, en_GB, it, es_ES...)""")
parser.add_argument("-o", "--output-file",
help="""\
where to write the output to (use '-' for standard
output); if not specified, a suitable file under
TRANSL_DIR will be chosen for each LANGUAGE_CODE.
Note: this option can only be given when exactly one
LANGUAGE_CODE has been specified on the command
line (it doesn't make sense otherwise).""")
parser.add_argument("--output-format", default="xliff",
choices=fg_i18n.FORMAT_HANDLERS_NAMES,
help="format to use for the output files")
parser.add_argument("--help", action="help",
help="display this message and exit")
params = parser.parse_args(namespace=params)
if params.transl_dir is None:
logger.error("--transl-dir must be given, aborting")
sys.exit(1)
if params.output_file is not None and len(params.lang_code) > 1:
logger.error("--output-file can only be given when exactly one "
"LANGUAGE_CODE has been specified on the command line "
"(it doesn't make sense otherwise)")
sys.exit(1)
return params
def main():
global params
locale.setlocale(locale.LC_ALL, '')
params = processCommandLine()
l10nResPoolMgr = fg_i18n.L10NResourcePoolManager(params.transl_dir, logger)
xliffFormatHandler = fg_i18n.FORMAT_HANDLERS_MAP[params.output_format]()
if params.output_file is not None:
assert len(params.lang_code) == 1, params.lang_code
# Output to one file or to stdout
l10nResPoolMgr.writeSkeletonTranslation(
xliffFormatHandler, params.lang_code[0],
filePath=params.output_file)
else:
# Output to several files
for langCode in params.lang_code:
l10nResPoolMgr.writeSkeletonTranslation(xliffFormatHandler,
langCode)
sys.exit(0)
if __name__ == "__main__": main()

View File

@@ -1,184 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# fg-update-translation-files --- Merge new default translation,
# remove obsolete strings from a translation
# Copyright (C) 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
import enum
import locale
import os
import sys
try:
import xml.etree.ElementTree as et
except ImportError:
import elementtree.ElementTree as et
import flightgear.meta.logging
import flightgear.meta.i18n as fg_i18n
PROGNAME = os.path.basename(sys.argv[0])
# Only messages with severity >= info will be printed to the terminal (it's
# possible to also log all messages to a file regardless of their level, see
# the Logger class). Of course, there is also the standard logging module...
logger = flightgear.meta.logging.Logger(
progname=PROGNAME,
logLevel=flightgear.meta.logging.LogLevel.info,
defaultOutputStream=sys.stderr)
def processCommandLine():
params = argparse.Namespace()
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...] ACTION LANGUAGE_CODE...
Update FlightGear XLIFF localization files.""",
description="""\
This program performs the following operations (actions) on FlightGear XLIFF
translation files (*.xlf):
- [merge-new-master]
Read the default translation[1], add new translated strings it contains to
the XLIFF localization files corresponding to the specified language(s),
mark the translated strings in said files that need review (modified in
the default translation) as well as those that are not used anymore
(disappeared in the default translation, or marked in a way that says they
don't need to be translated);
- [mark-unused]
Read the default translation and mark translated strings (in the XLIFF
localization files corresponding to the specified language(s)) that are
not used anymore;
- [remove-unused]
In the XLIFF localization files corresponding to the specified
language(s), remove all translated strings that are marked as unused.
A translated string that is marked as unused is still present in the XLIFF
localization file; it is just presented in a way that tells translators they
don't need to worry about it. On the other hand, when a translated string is
removed, translators don't see it anymore and the translation is lost, except
if rescued by external means such as backups or version control systems (Git,
Subversion, etc.)
Note that the 'remove-unused' action does *not* imply 'mark-unused'. It only
removes translation units that are already marked as unused (i.e., with
translate="no"). Thus, it makes sense to do 'mark-unused' followed by
'remove-unused' if you really want to get rid of old translations (you need to
invoke the program twice, or make a small change for this). Leaving unused
translated strings marked as such in XLIFF files shouldn't harm much in
general on the short or mid-term: they only take some space.
[1] FlightGear XML files in $FG_ROOT/Translations/default containing strings
used for the default locale (English).""",
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
parser.add_argument("-t", "--transl-dir",
help="""\
directory containing all translation subdirs (such as
{default!r}, 'en_GB', 'fr_FR', 'de', 'it'...). This
"option" MUST be specified.""".format(
default=fg_i18n.DEFAULT_LANG_DIR))
parser.add_argument("action", metavar="ACTION",
choices=("merge-new-master",
"mark-unused",
"remove-unused"),
help="""\
what to do: merge a new default (= master)
translation, or mark unused translation units, or
remove those already marked as unused from the XLIFF
files corresponding to each given LANGUAGE_CODE (i.e.,
those that are not in the default translation)""")
parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="+",
help="""\
codes of languages to operate on (e.g., fr, en_GB, it,
es_ES...)""")
parser.add_argument("--help", action="help",
help="display this message and exit")
params = parser.parse_args(namespace=params)
if params.transl_dir is None:
logger.error("--transl-dir must be given, aborting")
sys.exit(1)
return params
class MarkOrRemoveUnusedAction(enum.Enum):
mark, remove = range(2)
def markOrRemoveUnused(l10nResPoolMgr, action):
formatHandler = fg_i18n.XliffFormatHandler()
masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl
for langCode in params.lang_code:
xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode)
transl = formatHandler.readTranslation(xliffPath)
if action == MarkOrRemoveUnusedAction.mark:
transl.markObsoleteOrVanished(masterTransl, logger=logger)
elif action == MarkOrRemoveUnusedAction.remove:
transl.removeObsoleteOrVanished(logger=logger)
else:
assert False, "unexpected action: {!r}".format(action)
l10nResPoolMgr.writeTranslation(formatHandler, transl,
filePath=xliffPath)
def mergeNewMaster(l10nResPoolMgr):
formatHandler = fg_i18n.XliffFormatHandler()
masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl
for langCode in params.lang_code:
xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode)
transl = formatHandler.readTranslation(xliffPath)
transl.mergeMasterTranslation(masterTransl, logger=logger)
l10nResPoolMgr.writeTranslation(formatHandler, transl,
filePath=xliffPath)
def main():
global params
locale.setlocale(locale.LC_ALL, '')
params = processCommandLine()
l10nResPoolMgr = fg_i18n.L10NResourcePoolManager(params.transl_dir, logger)
if params.action == "mark-unused":
markOrRemoveUnused(l10nResPoolMgr, MarkOrRemoveUnusedAction.mark)
elif params.action == "remove-unused":
markOrRemoveUnused(l10nResPoolMgr, MarkOrRemoveUnusedAction.remove)
elif params.action == "merge-new-master":
mergeNewMaster(l10nResPoolMgr)
else:
assert False, "Bug: unexpected action: {!r}".format(params.action)
sys.exit(0)
if __name__ == "__main__": main()

View File

@@ -1,58 +0,0 @@
# -*- coding: utf-8 -*-
# exceptions.py --- Simple, general-purpose subclass of Exception
#
# Copyright (C) 2015, 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""Simple, general-purpose Exception subclass."""
class FGPyException(Exception):
def __init__(self, message=None, *, mayCapitalizeMsg=True):
"""Initialize an FGPyException instance.
Except in cases where 'message' starts with a proper noun or
something like that, its first character should be given in
lower case. Automated treatments of this exception may print the
message with its first character changed to upper case, unless
'mayCapitalizeMsg' is False. In other words, if the case of the
first character of 'message' must not be changed under any
circumstances, set 'mayCapitalizeMsg' to False.
"""
self.message = message
self.mayCapitalizeMsg = mayCapitalizeMsg
def __str__(self):
return self.completeMessage()
def __repr__(self):
return "{}.{}({!r})".format(__name__, type(self).__name__, self.message)
# Typically overridden by subclasses with a custom constructor
def detail(self):
return self.message
def completeMessage(self):
if self.message:
return "{shortDesc}: {detail}".format(
shortDesc=self.ExceptionShortDescription,
detail=self.detail())
else:
return self.ExceptionShortDescription
ExceptionShortDescription = "FlightGear Python generic exception"

File diff suppressed because it is too large Load Diff

View File

@@ -1,95 +0,0 @@
# -*- coding: utf-8 -*-
# logging.py --- Simple logging infrastructure (mostly taken from FFGo)
# Copyright (C) 2015, 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import sys
from . import misc
class LogLevel(misc.OrderedEnum):
debug, info, notice, warning, error, critical = range(6)
# List containing the above log levels as strings in increasing priority order
allLogLevels = [member.name for member in LogLevel]
allLogLevels.sort(key=lambda n: LogLevel[n].value)
def _logFuncFactory(level):
def logFunc(self, *args, **kwargs):
self.log(LogLevel[level], True, *args, **kwargs)
def logFunc_noPrefix(self, *args, **kwargs):
self.log(LogLevel[level], False, *args, **kwargs)
return (logFunc, logFunc_noPrefix)
class Logger:
def __init__(self, progname=None, logLevel=LogLevel.notice,
defaultOutputStream=sys.stdout, logFile=None):
self.progname = progname
self.logLevel = logLevel
self.defaultOutputStream = defaultOutputStream
self.logFile = logFile
def setLogFile(self, *args, **kwargs):
self.logFile = open(*args, **kwargs)
def log(self, level, printLogLevel, *args, **kwargs):
if printLogLevel and level >= LogLevel.warning and args:
args = [level.name.upper() + ": " + args[0]] + list(args[1:])
if level >= self.logLevel:
if (self.progname is not None) and args:
tArgs = [self.progname + ": " + args[0]] + list(args[1:])
else:
tArgs = args
kwargs["file"] = self.defaultOutputStream
print(*tArgs, **kwargs)
if self.logFile is not None:
kwargs["file"] = self.logFile
print(*args, **kwargs)
# Don't overload log() with too many tests or too much indirection for
# little use
def logToFile(self, *args, **kwargs):
kwargs["file"] = self.logFile
print(*args, **kwargs)
# NP functions are “no prefix” variants which never prepend the log level
# (otherwise, it is only prepended for warning and higher levels).
debug, debugNP = _logFuncFactory("debug")
info, infoNP = _logFuncFactory("info")
notice, noticeNP = _logFuncFactory("notice")
warning, warningNP = _logFuncFactory("warning")
error, errorNP = _logFuncFactory("error")
critical, criticalNP = _logFuncFactory("critical")
class DummyLogger(Logger):
def setLogFile(self, *args, **kwargs):
pass
def log(self, *args, **kwargs):
pass
def logToFile(self, *args, **kwargs):
pass

View File

@@ -1,81 +0,0 @@
# -*- coding: utf-8 -*-
# misc.py --- Miscellaneous classes and/or functions
# Copyright (C) 2015-2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import enum
# Based on an example from the 'enum' documentation
class OrderedEnum(enum.Enum):
"""Base class for enumerations whose members can be ordered.
Contrary to enum.IntEnum, this class maintains normal enum.Enum
invariants, such as members not being comparable to members of other
enumerations (nor of any other class, actually).
"""
def __ge__(self, other):
if self.__class__ is other.__class__:
return self.value >= other.value
return NotImplemented
def __gt__(self, other):
if self.__class__ is other.__class__:
return self.value > other.value
return NotImplemented
def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
return NotImplemented
def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented
def __eq__(self, other):
if self.__class__ is other.__class__:
return self.value == other.value
return NotImplemented
def __ne__(self, other):
if self.__class__ is other.__class__:
return self.value != other.value
return NotImplemented
# Taken from <http://effbot.org/zone/element-lib.htm#prettyprint> and modified
# by Florent Rougon
def indentXmlTree(elem, level=0, basicOffset=2, lastChild=False):
def indentation(level):
return "\n" + level*basicOffset*" "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = indentation(level+1)
for e in elem[:-1]:
indentXmlTree(e, level+1, basicOffset, False)
if len(elem):
indentXmlTree(elem[-1], level+1, basicOffset, True)
if level and (not elem.tail or not elem.tail.strip()):
if lastChild:
elem.tail = indentation(level-1)
else:
elem.tail = indentation(level)

View File

@@ -1,172 +0,0 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# rebuild-fgdata-embedded-resources -- Rebuild FGData-resources.[ch]xx
# Copyright (C) 2017 Florent Rougon
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# Only standard modules so that distributors can easily run this script, in
# case they want to recreate FGData-resources.[ch]xx from source.
import argparse
import json
import locale
import logging
import os
import subprocess
import sys
PROGNAME = os.path.basename(sys.argv[0])
CONFIG_FILE = os.path.join(os.path.expanduser('~'),
".fgmeta",
PROGNAME + ".json")
# chLevel: console handler level
def setupLogging(level=logging.NOTSET, chLevel=None):
global logger
if chLevel is None:
chLevel = level
logger = logging.getLogger(__name__)
# Effective level for all child loggers with NOTSET level
logger.setLevel(level)
# Create console handler and set its level
ch = logging.StreamHandler() # Uses sys.stderr by default
ch.setLevel(chLevel) # NOTSET, DEBUG, INFO, WARNING, ERROR, CRITICAL
# Logger name with :%(name)s... many other things available, including
# %(levelname)s
formatter = logging.Formatter("{}: %(message)s".format(PROGNAME))
# Add formatter to ch
ch.setFormatter(formatter)
# Add ch to logger
logger.addHandler(ch)
# Modifies 'params' in-place
def loadCfgFileSection(params, jsonTree, title, items):
# NB: !!! each item is subject to os.path.expanduser() !!!
try:
section = jsonTree[title]
except KeyError:
pass
else:
for name in items:
try:
path = section[name]
except KeyError:
pass
else:
setattr(params, name.lower(), os.path.expanduser(path))
# Modifies 'params' in-place
def loadConfigFile(params):
if not os.path.isfile(CONFIG_FILE):
return
# The log level is set too late for this one -> commented out
# logger.info("Loading config file {}...".format(CONFIG_FILE))
with open(CONFIG_FILE, "r", encoding="utf-8") as cfgFile:
tree = json.load(cfgFile)
loadCfgFileSection(params, tree, "repositories", ("FlightGear", "FGData"))
loadCfgFileSection(params, tree, "executables", ("fgrcc",))
def processCommandLine(params):
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...]
Rebuild FGData embedded resources for FlightGear.""",
description="""\
Use fgrcc with FGData-resources.xml and the corresponding files in FGData to
(re)create the FGData-resources.[ch]xx files used in the FlightGear build. The
existing files in the FlightGear repository are always overwritten
(FGData-resources.[ch]xx in <FlightGear-repo>/src/EmbeddedResources).
This is a dumb script that simply calls fgrcc with appropriate parameters. In
order to save some typing, you may want to use a configuration file like this
(~/.fgmeta/%(prog)s.json):
{"repositories": {"FlightGear": "~/flightgear/src/flightgear",
"FGData": "~/flightgear/src/fgdata"},
"executables": {"fgrcc":
"~/flightgear/src/build-fg/src/EmbeddedResources/fgrcc"
}
}""",
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
parser.add_argument('--flightgear', action='store', help="""\
Path to the FlightGear repository""")
parser.add_argument('--fgdata', action='store', help="""\
Path to the FGData repository""")
parser.add_argument('--fgrcc', action='store', help="""\
Path to the fgrcc executable""")
parser.add_argument('--log-level', action='store',
choices=("debug", "info", "warning", "error",
"critical"),
default=None, help="""Set the log level""")
parser.add_argument('--help', action="help",
help="display this message and exit")
parser.parse_args(namespace=params)
# Don't use the 'default' argparse mechanism for this, in order to allow
# the config file to set the log level in a meaningful way if we want (not
# implemented at the time of this writing).
if params.log_level is not None:
logger.setLevel(getattr(sys.modules["logging"],
params.log_level.upper()))
def main():
locale.setlocale(locale.LC_ALL, '')
setupLogging(level=logging.INFO) # may be overridden by options
params = argparse.Namespace()
loadConfigFile(params) # could set the log level
processCommandLine(params)
if (params.flightgear is None or params.fgdata is None or
params.fgrcc is None):
logger.error(
"--flightgear, --fgdata and --fgrcc must all be specified (they "
"may be set in the config file; use --help for more info)")
sys.exit(1)
resDir = os.path.join(params.flightgear, "src", "EmbeddedResources")
inputXMLFile = os.path.join(resDir, "FGData-resources.xml")
cxxFile = os.path.join(resDir, "FGData-resources.cxx")
hxxFile = os.path.join(resDir, "FGData-resources.hxx")
args = [params.fgrcc,
"--root={}".format(params.fgdata),
"--output-cpp-file={}".format(cxxFile),
"--init-func-name=initFGDataEmbeddedResources",
"--output-header-file={}".format(hxxFile),
"--output-header-identifier=_FG_FGDATA_EMBEDDED_RESOURCES",
inputXMLFile]
# encoding="utf-8" requires Python >= 3.6 -> will add it later
# (it's not really needed, as we don't process the output)
subprocess.run(args, check=True)
sys.exit(0)
if __name__ == "__main__": main()

View File

@@ -12,7 +12,7 @@
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with FlightGear If not, see <http://www.gnu.org/licenses/>.
#along with Foobar. If not, see <http://www.gnu.org/licenses/>.
if [ -z "$1" -o -z "$2" ]; then
echo "usage: thismajor.thisminor nextmajor.nextminor path"
@@ -65,6 +65,8 @@ createBranch() {
while [ $# -gt 0 ]; do
echo "Processing $1"
pushd $1 > /dev/null
git config user.name "Automatic Release Builder"
git config user.email "build@flightgear.org"
createBranch
popd > /dev/null
shift

View File

@@ -1,8 +1,8 @@
#!/bin/bash
THIS_RELEASE="2017.3"
NEXT_RELEASE="2017.4"
SUBMODULES="simgear flightgear fgdata getstart"
THIS_RELEASE="2017.1"
NEXT_RELEASE="2017.2"
SUBMODULES="simgear flightgear fgdata"
#:<< 'COMMENT_END'
git checkout next
@@ -28,7 +28,7 @@ read something
for f in $SUBMODULES .; do
pushd "$f"
echo "Pushing $f"
git checkout release/${THIS_RELEASE} && git push origin release/${THIS_RELEASE} && git push origin version/${THIS_RELEASE}.1 && git push origin version/${NEXT_RELEASE}.0 && git checkout next && git push
git checkout release/${THIS_RELEASE} && git push origin release/${THIS_RELEASE} && git push origin version/${THIS_RELEASE}.1 && git push origin version/${NEXT_RELEASE}.0 && git checkout next && git push
popd
done
@@ -42,3 +42,4 @@ done
svn copy svn+ssh://svn.code.sf.net/p/flightgear/fgaddon/trunk \
svn+ssh://svn.code.sf.net/p/flightgear/fgaddon/branches/release-${THIS_RELEASE} \
-m "branching for release ${THIS_RELEASE}"

Submodule simgear updated: 629e68428f...2b4e5a71df

View File

@@ -1 +1 @@
2017.3.1
2017.1.3