Compare commits
49 Commits
release/20
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d25cd78f | ||
|
|
55408ffda6 | ||
|
|
803e6ef418 | ||
|
|
0b831773af | ||
|
|
bc4bd61de6 | ||
|
|
38426b8a64 | ||
|
|
e9ebb418f3 | ||
|
|
f2cbb733a0 | ||
|
|
195f123c05 | ||
|
|
3408da4f40 | ||
|
|
ab34ede1ea | ||
|
|
dddf9dcb83 | ||
|
|
f6cbce7324 | ||
|
|
6034143788 | ||
|
|
7ad60c4471 | ||
|
|
4f5fd4bea6 | ||
|
|
2ab43e6c0a | ||
|
|
663eaaa65b | ||
|
|
e950c89c2f | ||
|
|
bcb4eb6064 | ||
|
|
c1a00bb944 | ||
|
|
480f8bbb68 | ||
|
|
f1e8e8b4a2 | ||
|
|
4f4a2c9cdd | ||
|
|
dd510b0286 | ||
|
|
018f0907c2 | ||
|
|
f2a27e592d | ||
|
|
89d526e740 | ||
|
|
68e2df9db6 | ||
|
|
87c11e7e2f | ||
|
|
7142621966 | ||
|
|
54d6196698 | ||
|
|
6b970f8e02 | ||
|
|
fb28f40b72 | ||
|
|
efd4f15d9d | ||
|
|
be74bb8017 | ||
|
|
3acff3caba | ||
|
|
c6eb59eb42 | ||
|
|
89948603de | ||
|
|
25a9835014 | ||
|
|
70eb74bc09 | ||
|
|
3e3b63181b | ||
|
|
91ea5ba877 | ||
|
|
b2754b573a | ||
|
|
6029b13828 | ||
|
|
6e8acf6fdc | ||
|
|
f16831a51d | ||
|
|
117fffef0b | ||
|
|
47570b3676 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,3 +21,4 @@ osgbuild
|
||||
CMakeCache.txt
|
||||
*.pyc
|
||||
build-*
|
||||
testOutput*
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -18,3 +18,7 @@
|
||||
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 = next
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
|
||||
#include "InstallConfig.iss"
|
||||
|
||||
#if GetEnv("VSINSTALLDIR") == ""
|
||||
#define VSInstallDir "C:\Program Files (x86)\Microsoft Visual Studio 14.0"
|
||||
#else
|
||||
#define VSInstallDir GetEnv("VSINSTALLDIR")
|
||||
#endif
|
||||
|
||||
#define VCInstallDir VSInstallDir + "\VC"
|
||||
#define InstallDir32 "X:\install\msvc140"
|
||||
#define OSGInstallDir InstallDir32 + "\OpenSceneGraph"
|
||||
#define OSGPluginsDir OSGInstallDir + "\bin\osgPlugins-" + OSGVersion
|
||||
@@ -69,7 +62,7 @@ ArchitecturesAllowed=x86 x64
|
||||
|
||||
; Sign tool must be defined in the Inno Setup GUI, to avoid
|
||||
; exposing the certificate password
|
||||
; SignTool=fg_code_sign1
|
||||
; SignTool=fg_code_sign1
|
||||
|
||||
[Tasks]
|
||||
; NOTE: The following entry contains English phrases ("Create a desktop icon" and "Additional icons"). You are free to translate them into another language if required.
|
||||
@@ -92,7 +85,6 @@ Source: "{#ThirdPartyDir}\3rdParty\bin\libintl-8.dll"; DestDir: "{app}\bin"; Che
|
||||
Source: "{#ThirdPartyDir}\3rdParty\bin\CrashRpt1403.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
|
||||
Source: "{#ThirdPartyDir}\3rdParty\bin\crashrpt_lang.ini"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
|
||||
Source: "{#ThirdPartyDir}\3rdParty\bin\CrashSender1403.exe"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
|
||||
Source: "{#VCInstallDir}\redist\x86\Microsoft.VC140.CRT\*.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
|
||||
|
||||
; 64 bits install
|
||||
Source: "{#InstallDir64}\bin\*.*"; DestDir: "{app}\bin"; Excludes: "{#ExcludedBinaries}"; Flags: ignoreversion recursesubdirs; Check: Is64BitInstallMode
|
||||
@@ -107,7 +99,6 @@ Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libintl-8.dll"; DestDir: "{app}\bin";
|
||||
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\CrashRpt1403.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
|
||||
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\crashrpt_lang.ini"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
|
||||
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
|
||||
|
||||
; Include the base package
|
||||
#if IncludeData == "TRUE"
|
||||
@@ -328,6 +319,66 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
UninstallCheckCleanPage: TNewNotebookPage;
|
||||
UninstallBackButton: TNewButton;
|
||||
UninstallNextButton: TNewButton;
|
||||
DoCleanCheckbox : TNewCheckBox;
|
||||
CleanHelp : TNewStaticText;
|
||||
|
||||
procedure InitializeUninstallProgressForm();
|
||||
begin
|
||||
UninstallProgressForm
|
||||
|
||||
UninstallCheckCleanPage := TNewNotebookPage.Create(UninstallProgressForm);
|
||||
UninstallCheckCleanPage.Notebook := UninstallProgressForm.InnerNotebook;
|
||||
UninstallCheckCleanPage.Parent := UninstallProgressForm.InnerNotebook;
|
||||
UninstallCheckCleanPage.Align := alClient
|
||||
|
||||
DoCleanCheckbox := TNewCheckBox.Create(UninstallProgressForm);
|
||||
DoCleanCheckbox.Parent := UninstallCheckCleanPage;
|
||||
DoCleanCheckbox.Caption := 'Remove all settings, downloaded scenery and aircraft';
|
||||
DoCleanCheckbox.Left := ScaleX(10);
|
||||
DoCleanCheckbox.Top := ScaleY(10);
|
||||
|
||||
DoCleanCheckbox.Width := UninstallProgressForm.InnerNotebook.Width - ScaleX(20)
|
||||
DoCleanCheckbox.Height := ScaleY(30)
|
||||
|
||||
CleanHelp := TNewStaticText.Create(UninstallProgressForm);
|
||||
CleanHelp.Parent := UninstallCheckCleanPage;
|
||||
CleanHelp.Top := DoCleanCheckbox.Top + DoCleanCheckbox.Height + ScaleY(10);
|
||||
CleanHelp.Left := DoCleanCheckbox.Left;
|
||||
CleanHelp.Width := DoCleanCheckbox.Width;
|
||||
CleanHelp.Height := CleanHelp.AdjustHeight();
|
||||
|
||||
CleanHelp.WordWrap := True;
|
||||
CleanHelp.Caption := 'FlightGear stores some settings in your user folder. In addition, ' +
|
||||
'scenery or aircraft data may have been downloaded to the download directory. ' +
|
||||
'To completely remove all these files, select this option.';
|
||||
|
||||
UninstallProgressForm.InnerNotebook.ActivePage := UninstallCheckCleanPage;
|
||||
|
||||
UninstallNextButton := TNewButton.Create(UninstallProgressForm);
|
||||
UninstallNextButton.Caption := 'Next';
|
||||
UninstallNextButton.Parent := UninstallProgressForm;
|
||||
UninstallNextButton.Left :=
|
||||
UninstallProgressForm.CancelButton.Left -
|
||||
UninstallProgressForm.CancelButton.Width -
|
||||
ScaleX(10);
|
||||
UninstallNextButton.Top := UninstallProgressForm.CancelButton.Top;
|
||||
UninstallNextButton.Width := UninstallProgressForm.CancelButton.Width;
|
||||
UninstallNextButton.Height := UninstallProgressForm.CancelButton.Height;
|
||||
UninstallNextButton.ModalResult := mrOk;
|
||||
|
||||
UninstallProgressForm.CancelButton.Enabled := True;
|
||||
UninstallProgressForm.CancelButton.ModalResult := mrCancel;
|
||||
|
||||
if UninstallProgressForm.ShowModal = mrCancel then Abort;
|
||||
|
||||
UninstallProgressForm.InnerNotebook.ActivePage := UninstallProgressForm.InstallingPage;
|
||||
end;
|
||||
|
||||
|
||||
procedure CurStepChanged(CurStep: TSetupStep);
|
||||
var
|
||||
Version: TWindowsVersion;
|
||||
@@ -353,7 +404,18 @@ begin
|
||||
end;
|
||||
|
||||
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
|
||||
var ResultCode: Integer;
|
||||
begin
|
||||
if CurUninstallStep = usUninstall then
|
||||
begin
|
||||
if DoCleanCheckbox.Checked = True then
|
||||
begin
|
||||
Log('Running clean uninstall');
|
||||
Exec(ExpandConstant('{app}\bin\fgfs.exe'), '--uninstall', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
Log('clean uninstall completed');
|
||||
end;
|
||||
end;
|
||||
|
||||
if CurUninstallStep = usPostUninstall then
|
||||
begin
|
||||
RemoveFirewallException('FlightGear', ExpandConstant('{app}') + '\bin\fgfs.exe');
|
||||
|
||||
@@ -7,6 +7,10 @@ fi
|
||||
|
||||
VERSION=`cat flightgear/version`
|
||||
|
||||
#####################################################################################
|
||||
# ensure fgrcc can run when linked against libSimGearCore, for example
|
||||
export LD_LIBRARY_PATH=$WORKSPACE/dist/lib64:$WORKSPACE/dist/lib:$LD_LIBRARY_PATH
|
||||
|
||||
#####################################################################################
|
||||
# remove old and create fresh build directories
|
||||
cd $WORKSPACE
|
||||
@@ -14,7 +18,6 @@ mkdir -p sgBuild
|
||||
mkdir -p fgBuild
|
||||
mkdir -p output
|
||||
rm -rf output/*
|
||||
rm -rf dist/*
|
||||
|
||||
#####################################################################################
|
||||
echo "Starting on SimGear"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
IF NOT DEFINED WORKSPACE SET WORKSPACE=%~dp0
|
||||
IF NOT DEFINED IS_NIGHTLY_BUILD SET IS_NIGHTLY_BUILD=1
|
||||
|
||||
IF %IS_NIGHTLY_BUILD% EQU 1 (
|
||||
SET FGBUILDTYPE=Nightly
|
||||
@@ -23,6 +24,7 @@ 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
|
||||
@@ -33,6 +35,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%
|
||||
cmake --build . --config RelWithDebInfo --target INSTALL
|
||||
@@ -47,6 +50,7 @@ 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
|
||||
@@ -57,14 +61,16 @@ cmake ..\flightgear -G "Visual Studio 14 Win64" ^
|
||||
-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%
|
||||
cmake --build . --config RelWithDebInfo --target INSTALL
|
||||
|
||||
cd ..
|
||||
|
||||
REM Qt5 deployment
|
||||
%QT5SDK32%\bin\windeployqt --release --list target %WORKSPACE%/install/msvc140/bin/fgfs.exe
|
||||
%QT5SDK64%\bin\windeployqt --release --list target %WORKSPACE%/install/msvc140-64/bin/fgfs.exe
|
||||
SET QMLDIR=%WORKSPACE%/flightgear/src/GUI/qml
|
||||
%QT5SDK32%\bin\windeployqt --release --list target --qmldir %QMLDIR% %WORKSPACE%/install/msvc140/bin/fgfs.exe
|
||||
%QT5SDK64%\bin\windeployqt --release --list target --qmldir %QMLDIR% %WORKSPACE%/install/msvc140-64/bin/fgfs.exe
|
||||
|
||||
REM build setup
|
||||
ECHO Packaging root is %WORKSPACE%
|
||||
|
||||
@@ -35,11 +35,25 @@ def scan_set_file(aircraft_dir, set_file, includes):
|
||||
if sim_node == None:
|
||||
return None
|
||||
|
||||
# allow -set.xml files to specifcially exclude themselves from
|
||||
# the creation process, by setting <exclude-from-catalog>true</>
|
||||
if (sim_node.getValue("exclude-from-catalog", False) == True):
|
||||
return None
|
||||
|
||||
variant = {}
|
||||
variant['name'] = sim_node.getValue("description", None)
|
||||
name = sim_node.getValue("description", None)
|
||||
if (name == None or len(name) == 0):
|
||||
print "Set file " + set_file + " is missing a <description>, skipping"
|
||||
return None
|
||||
|
||||
variant['name'] = name
|
||||
variant['status'] = sim_node.getValue("status", None)
|
||||
variant['author'] = sim_node.getValue("author", None)
|
||||
variant['description'] = sim_node.getValue("long-description", 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.
|
||||
@@ -64,6 +78,10 @@ def scan_set_file(aircraft_dir, set_file, includes):
|
||||
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
|
||||
|
||||
@@ -103,6 +121,7 @@ def scan_aircraft_dir(aircraft_dir, includes):
|
||||
files = os.listdir(aircraft_dir)
|
||||
for file in sorted(files, key=lambda s: s.lower()):
|
||||
if file.endswith('-set.xml'):
|
||||
# print 'trying:', file
|
||||
try:
|
||||
d = scan_set_file(aircraft_dir, file, includes)
|
||||
if d == None:
|
||||
@@ -118,8 +137,9 @@ def scan_aircraft_dir(aircraft_dir, includes):
|
||||
elif d['variant-of'] == None:
|
||||
primaryAircraft.append(d)
|
||||
|
||||
# print setDicts
|
||||
if len(setDicts) == 0:
|
||||
return None
|
||||
return None, None
|
||||
|
||||
# use the first one
|
||||
if len(primaryAircraft) == 0:
|
||||
@@ -128,7 +148,8 @@ def scan_aircraft_dir(aircraft_dir, includes):
|
||||
|
||||
package = primaryAircraft[0]
|
||||
if not 'thumbnail' in package:
|
||||
package['thumbnail'] = "thumbnail.jpg"
|
||||
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
|
||||
@@ -172,8 +193,16 @@ def make_aircraft_node(aircraftDirName, package, variants, downloadBase):
|
||||
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 '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')
|
||||
@@ -217,11 +246,12 @@ def make_aircraft_node(aircraftDirName, package, variants, downloadBase):
|
||||
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']))
|
||||
|
||||
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)
|
||||
|
||||
@@ -58,9 +58,11 @@ manufacturerTags = [
|
||||
"messerschmitt",
|
||||
"mikoyan-gurevich",
|
||||
"mitsubishi",
|
||||
"north-american",
|
||||
"northrop",
|
||||
"pilatus",
|
||||
"piper",
|
||||
"republic",
|
||||
"robin",
|
||||
"saab",
|
||||
"short",
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
<version n="1">3.5.*</version>
|
||||
<version n="2">3.6.*</version>
|
||||
<version n="3">3.7.*</version>
|
||||
<version n="4">2016.1.*</version>
|
||||
<version n="5">2016.*.*</version>
|
||||
<version n="6">2017.*.*</version>
|
||||
<id>org.flightgear.fgaddon</id>
|
||||
<license>GPL</license>
|
||||
<url>http://mirrors.ibiblio.org/flightgear/ftp/Aircraft/catalog.xml</url>
|
||||
<name>FlightGear Aircraft Distribution From fgaddon</name>
|
||||
<name>FlightGear aircraft distribution from fgaddon</name>
|
||||
<description>This hangar provides aircraft officially supported and maintained by the FlightGear project, under a free-software license.</description>
|
||||
<de>
|
||||
<description>Auf Deutsch</description>
|
||||
|
||||
@@ -133,6 +133,8 @@ class Node(object):
|
||||
n.set('type', "bool")
|
||||
except UnicodeEncodeError:
|
||||
print "Encoding error with", self._value, type(self._value)
|
||||
except:
|
||||
print "Some other exceptiong in sgprops._createXMLElement()"
|
||||
|
||||
# index in parent
|
||||
if (self.index != 0):
|
||||
|
||||
8
catalog/testData/Aircraft/c150/c150-set.xml
Normal file
8
catalog/testData/Aircraft/c150/c150-set.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList>
|
||||
<sim>
|
||||
<name>c150</name>
|
||||
<description>Cessna 150</description>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
||||
@@ -7,6 +7,7 @@
|
||||
<tag>1980s</tag>
|
||||
<tag>glass-cockpit</tag>
|
||||
</tags>
|
||||
<minimum-fg-version>2017.4</minimum-fg-version>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
||||
|
||||
11
catalog/testData/Aircraft/f16/f16-excluded-set.xml
Normal file
11
catalog/testData/Aircraft/f16/f16-excluded-set.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<exclude-from-catalog type="bool">true</exclude-from-catalog>
|
||||
<name>f16-excluded</name>
|
||||
<description>Fine</description>
|
||||
<long-description>Blah blah blah</long-description>
|
||||
<variant-of>f16a</variant-of>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
||||
11
catalog/testData/Aircraft/f16/f16broken-set.xml
Normal file
11
catalog/testData/Aircraft/f16/f16broken-set.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<PropertyList include="f16-common.xml">
|
||||
<sim>
|
||||
<name>f16broken</name>
|
||||
<!-- <description></description> -->
|
||||
<description></description>
|
||||
<long-description>Blah blah blah</long-description>
|
||||
<variant-of>f16a</variant-of>
|
||||
</sim>
|
||||
|
||||
</PropertyList>
|
||||
0
catalog/testData/Aircraft/f16/thumbnail.jpg
Normal file
0
catalog/testData/Aircraft/f16/thumbnail.jpg
Normal 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>
|
||||
|
||||
@@ -17,6 +17,7 @@ class UpdateCatalogTests(unittest.TestCase):
|
||||
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"])
|
||||
@@ -25,6 +26,7 @@ class UpdateCatalogTests(unittest.TestCase):
|
||||
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)
|
||||
@@ -90,6 +92,8 @@ class UpdateCatalogTests(unittest.TestCase):
|
||||
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)
|
||||
|
||||
@@ -109,8 +113,37 @@ class UpdateCatalogTests(unittest.TestCase):
|
||||
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()
|
||||
|
||||
@@ -144,7 +144,10 @@ def process_aircraft_dir(name, repo_path):
|
||||
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']
|
||||
if 'thumbnail' in package:
|
||||
# this is never even used, but breaks the script by assuming
|
||||
# all aircraft packages have thumbnails defined?
|
||||
thumbnail_url = download_base + 'thumbnails/' + name + '_' + package['thumbnail']
|
||||
|
||||
# get cached md5sum if it exists
|
||||
md5sum = get_xml_text(md5sum_root.find(str('aircraft_' + name)))
|
||||
@@ -301,6 +304,7 @@ for scm in scm_list:
|
||||
continue
|
||||
|
||||
# process each aircraft in turn
|
||||
# print name, repo_path
|
||||
process_aircraft_dir(name, repo_path)
|
||||
|
||||
# write out the master catalog file
|
||||
|
||||
@@ -26,6 +26,7 @@ VERSION="$(echo "$script_blob_id" | sed 's@\$Id: *\([0-9a-f]\+\) *@\1@')"
|
||||
# Then remove the trailing '$'
|
||||
VERSION="${VERSION%\$}"
|
||||
|
||||
PROGNAME=$(basename "$0")
|
||||
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)"
|
||||
|
||||
#######################################################
|
||||
@@ -54,6 +55,8 @@ BUILD_TYPE="RelWithDebInfo"
|
||||
SG_CMAKEARGS=""
|
||||
FG_CMAKEARGS=""
|
||||
|
||||
declare -a UNMATCHED_OPTIONAL_PKG_ALTERNATIVES
|
||||
|
||||
while getopts "shc:p:a:d:r:j:O:ib:" OPTION; do
|
||||
case $OPTION in
|
||||
s) STABLE="STABLE" ;;
|
||||
@@ -161,31 +164,74 @@ function _make(){
|
||||
fi
|
||||
}
|
||||
|
||||
# Find an available, non-virtual package matching one of the given regexps.
|
||||
# Add 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(){
|
||||
function _mandatory_pkg_alternative(){
|
||||
local pkg
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "No match found for the package alternative, aborting."
|
||||
echo "Empty package alternative: this is a bug in the script, aborting." \
|
||||
| tee -a "$LOGFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Considering a package alternative:" "$@" | tee -a "$LOGFILE"
|
||||
pkg=$(_find_package_alternative "$@")
|
||||
|
||||
if [[ -n "$pkg" ]]; then
|
||||
echo "Package alternative matched for $pkg" | tee -a "$LOGFILE"
|
||||
PKG="$PKG $pkg"
|
||||
else
|
||||
echo "No match found for the package alternative, aborting." \
|
||||
| tee -a "$LOGFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# If available, add a non-virtual package matching one of the given regexps.
|
||||
#
|
||||
# Returning 0 or 1 on success to indicate whether a match was found could be
|
||||
# done, but would need to be specifically handled at the calling site,
|
||||
# since the script is run under 'set -e' regime.
|
||||
function _optional_pkg_alternative(){
|
||||
local pkg
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Empty optional package alternative: this is a bug in the script," \
|
||||
"aborting." | tee -a "$LOGFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Considering an optional package alternative:" "$@" | tee -a "$LOGFILE"
|
||||
pkg=$(_find_package_alternative "$@")
|
||||
|
||||
if [[ -n "$pkg" ]]; then
|
||||
echo "Optional package alternative matched for $pkg" | tee -a "$LOGFILE"
|
||||
PKG="$PKG $pkg"
|
||||
else
|
||||
echo "No match found for the optional package alternative, continuing" \
|
||||
"anyway." | tee -a "$LOGFILE"
|
||||
# "$*" so that we only add one element to the array in this line
|
||||
UNMATCHED_OPTIONAL_PKG_ALTERNATIVES+=("$*")
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# This function requires the 'dctrl-tools' package
|
||||
function _find_package_alternative(){
|
||||
local pkg
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
return 0 # Nothing could be found
|
||||
fi
|
||||
|
||||
# This finds non-virtual packages only (on purpose)
|
||||
pkg="$(apt-cache dumpavail | \
|
||||
grep-dctrl -e -sPackage -FPackage \
|
||||
@@ -193,13 +239,12 @@ function _package_alternative_inner(){
|
||||
sed -ne '1s/^Package:[[:space:]]*//gp')"
|
||||
|
||||
if [[ -n "$pkg" ]]; then
|
||||
echo "Package alternative matched for $pkg"
|
||||
PKG="$PKG $pkg"
|
||||
echo "$pkg"
|
||||
return 0
|
||||
else
|
||||
# Try with the next regexp
|
||||
shift
|
||||
_package_alternative_inner "$@"
|
||||
_find_package_alternative "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -267,8 +312,8 @@ if [[ "$DOWNLOAD_PACKAGES" = "y" ]] && [[ "$APT_GET_UPDATE" = "y" ]]; then
|
||||
fi
|
||||
|
||||
# Ensure 'dctrl-tools' is installed
|
||||
if [[ "$(dpkg-query --showformat='${db:Status-Status}\n' --show dctrl-tools \
|
||||
2>/dev/null)" != "installed" ]]; then
|
||||
if [[ "$(dpkg-query --showformat='${Status}\n' --show dctrl-tools \
|
||||
2>/dev/null | awk '{print $3}')" != "installed" ]]; then
|
||||
if [[ "$DOWNLOAD_PACKAGES" = "y" ]]; then
|
||||
_aptInstall dctrl-tools
|
||||
else
|
||||
@@ -288,11 +333,16 @@ PKG="$PKG libcgal-dev libgdal-dev libtiff5-dev"
|
||||
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'
|
||||
_mandatory_pkg_alternative libopenscenegraph-3.4-dev libopenscenegraph-dev \
|
||||
'libopenscenegraph-[0-9]+\.[0-9]+-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
|
||||
_mandatory_pkg_alternative libpng-dev libpng12-dev libpng16-dev
|
||||
# The following packages are needed for the built-in launcher
|
||||
_optional_pkg_alternative qtbase5-private-dev
|
||||
_optional_pkg_alternative qtdeclarative5-private-dev
|
||||
_optional_pkg_alternative qml-module-qtquick2
|
||||
_optional_pkg_alternative qml-module-qtquick-window2
|
||||
# FGPanel
|
||||
PKG="$PKG fluid libbz2-dev libfltk1.3-dev libxi-dev libxmu-dev"
|
||||
# FGAdmin
|
||||
@@ -863,6 +913,24 @@ if [[ "$(declare -p WHATTOBUILD)" =~ '['([0-9]+)']="TERRAGEARGUI"' ]]; then
|
||||
echo "./TerraGUI \$@" >> run_terrageargui.sh
|
||||
fi
|
||||
|
||||
# Print optional package alternatives that didn't match (this helps with
|
||||
# troubleshooting)
|
||||
if [[ ${#UNMATCHED_OPTIONAL_PKG_ALTERNATIVES[@]} -gt 0 ]]; then
|
||||
echo | tee -a "$LOGFILE"
|
||||
printf "The following optional package alternative(s) didn't match:\n\n" \
|
||||
| tee -a "$LOGFILE"
|
||||
|
||||
for alt in "${UNMATCHED_OPTIONAL_PKG_ALTERNATIVES[@]}"; do
|
||||
printf " %s\n" "$alt" | tee -a "$LOGFILE"
|
||||
done
|
||||
|
||||
printf "\nThis could explain missing optional features in FlightGear or \
|
||||
other software\ninstalled by $PROGNAME.\n" | tee -a "$LOGFILE"
|
||||
else
|
||||
printf "All optional package alternatives have found a matching package.\n" \
|
||||
| tee -a "$LOGFILE"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "download_and_compile.sh has finished to work"
|
||||
|
||||
|
||||
2
fgdata
2
fgdata
Submodule fgdata updated: c8b090fa4e...b1f197434c
Submodule flightgear updated: 989ebf73a6...7e9549c1bc
1
getstart
Submodule
1
getstart
Submodule
Submodule getstart added at 943c000f6d
@@ -40,6 +40,7 @@ puts "Is-release? : ##{$isRelease}"
|
||||
$prefixDir=Dir.pwd + "/dist"
|
||||
dmgDir=Dir.pwd + "/image"
|
||||
srcDir=Dir.pwd + "/flightgear"
|
||||
qmlDir=srcDir + "/src/GUI/qml"
|
||||
|
||||
puts "Erasing previous image dir"
|
||||
`rm -rf #{dmgDir}`
|
||||
@@ -48,8 +49,10 @@ bundle=dmgDir + "/FlightGear.app"
|
||||
|
||||
# run macdeployt before we rename the bundle, otherwise it
|
||||
# can't find the bundle executable
|
||||
# also note if adding options here, the bundle path has to be
|
||||
# the first argument to macdeployqt
|
||||
puts "Running macdeployqt on the bundle to copy Qt libraries"
|
||||
`macdeployqt #{$prefixDir}/fgfs.app`
|
||||
`macdeployqt #{$prefixDir}/fgfs.app -qmldir=#{qmlDir}`
|
||||
|
||||
puts "Moving & renaming app bundle"
|
||||
`mkdir -p #{dmgDir}`
|
||||
|
||||
126
python3-flightgear/README-l10n.txt
Normal file
126
python3-flightgear/README-l10n.txt
Normal file
@@ -0,0 +1,126 @@
|
||||
-*- coding: utf-8 -*-
|
||||
|
||||
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[1].
|
||||
|
||||
|
||||
Creating XLIFF files from existing FlightGear legacy XML translation 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 for the following
|
||||
# commands to work. POSIX shell does that, Bash too apparently, but not Zsh
|
||||
# (by default). In Zsh, you can use $=languages or ${=languages} to ensure
|
||||
# the expansion uses word splitting.
|
||||
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
|
||||
|
||||
Updating XLIFF files to reflect changes in the default translation
|
||||
------------------------------------------------------------------
|
||||
|
||||
When master strings[2] have changed (in a large sense, i.e.: strings added,
|
||||
modified or removed, or categories added or removed[3]):
|
||||
|
||||
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
|
||||
merge-new-master $languages
|
||||
|
||||
Updating XLIFF files to mark or remove obsolete translated strings
|
||||
------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
|
||||
Merging contents from an XLIFF file into another one
|
||||
----------------------------------------------------
|
||||
|
||||
Suppose a translator has been working on a particular translation file, and
|
||||
meanwhile the official XLIFF file for this translation has been updated in
|
||||
FGData (new translatable strings added, obsolete strings marked or removed,
|
||||
etc.). In such a case, 'fg-merge-xliff-into-xliff' can be used to merge the
|
||||
translator's work into the project file. Essentially, this means that for all
|
||||
strings that have the same source text, plural status, number of plural forms
|
||||
and of course target language, the target texts, “approved” status and
|
||||
translator comments will be taken from the first file passed in the following
|
||||
command:
|
||||
|
||||
fg-merge-xliff-into-xliff TRANSLATOR_FILE PROJECT_FILE
|
||||
|
||||
Used like this, PROJECT_FILE will be updated with data from TRANSLATOR_FILE.
|
||||
If you don't want to modify PROJECT_FILE, use the -o (--output) option. If '-'
|
||||
is passed as argument to this option, then the result is written to the
|
||||
standard output.
|
||||
|
||||
Creating skeleton XLIFF files for new translations
|
||||
--------------------------------------------------
|
||||
|
||||
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)
|
||||
|
||||
Getting more information on the scripts
|
||||
---------------------------------------
|
||||
|
||||
fg-convert-translation-files, fg-update-translation-files,
|
||||
fg-merge-xliff-into-xliff and fg-new-translations all support the --help
|
||||
option for more detailed information.
|
||||
|
||||
|
||||
Footnotes
|
||||
---------
|
||||
|
||||
[1] Except for the fg-merge-xliff-into-xliff script, which doesn't have any
|
||||
of these requirements.
|
||||
|
||||
[2] Strings in the default translation.
|
||||
|
||||
[3] 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!)
|
||||
181
python3-flightgear/fg-convert-translation-files
Executable file
181
python3-flightgear/fg-convert-translation-files
Executable file
@@ -0,0 +1,181 @@
|
||||
#! /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
|
||||
|
||||
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()
|
||||
123
python3-flightgear/fg-merge-xliff-into-xliff
Executable file
123
python3-flightgear/fg-merge-xliff-into-xliff
Executable file
@@ -0,0 +1,123 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# fg-merge-xliff-into-xliff --- Merge translations from one XLIFF file into
|
||||
# another one
|
||||
# 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 locale
|
||||
import os
|
||||
import sys
|
||||
|
||||
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 ...] SOURCE INTO
|
||||
Merge strings from a FlightGear XLIFF localization file into another one.""",
|
||||
description="""\
|
||||
This program merges a FlightGear XLIFF localization file into another one.
|
||||
This means that every translatable string that:
|
||||
|
||||
(1) exists in both SOURCE and INTO;
|
||||
|
||||
(2) has the same target language, source text, plural status and number of
|
||||
plural forms in SOURCE and in INTO;
|
||||
|
||||
is updated from SOURCE, i.e.: the target texts, 'approved' status and
|
||||
translator comments are copied from SOURCE.
|
||||
|
||||
The result is written to INTO unless the -o (--output) option is given.
|
||||
|
||||
Note that this program is different from fg-update-translation-files's
|
||||
'merge-new-master' command, which is for updating an XLIFF file according to
|
||||
the default translation ("master").
|
||||
|
||||
Expected use case: suppose that a translator is working on a translation
|
||||
file, and meanwhile the official XLIFF file for this translation is updated
|
||||
in the project repository (new translatable strings added, obsolete strings
|
||||
marked or removed, etc.). This program can then be used to merge the
|
||||
translator work into the project file for all strings for which it makes
|
||||
sense (source text unchanged, same plural status, etc.).""",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
# I want --help but not -h (it might be useful for something else)
|
||||
add_help=False)
|
||||
|
||||
parser.add_argument("source", metavar="SOURCE",
|
||||
help="""\
|
||||
input XLIFF file; read updated translated strings
|
||||
from this file""")
|
||||
parser.add_argument("into", metavar="INTO",
|
||||
help="""\
|
||||
XLIFF file to compare to SOURCE in order to decide
|
||||
which translated strings to update; unless the -o
|
||||
option is used, updated strings are written to this
|
||||
file""")
|
||||
parser.add_argument("-o", "--output",
|
||||
help="""\
|
||||
write the XLIFF merged output to OUTPUT instead of
|
||||
INTO. When this option is used, INTO is read but not
|
||||
modified. If OUTPUT is '-', write the XLIFF merged
|
||||
output to the standard output.""")
|
||||
parser.add_argument("--help", action="help",
|
||||
help="display this message and exit")
|
||||
|
||||
return parser.parse_args(namespace=params)
|
||||
|
||||
|
||||
def mergeXliffIntoXliff(source, into, output):
|
||||
formatHandler = fg_i18n.XliffFormatHandler()
|
||||
|
||||
srcTransl = formatHandler.readTranslation(source)
|
||||
transl = formatHandler.readTranslation(into)
|
||||
# Merge 'srcTransl' into 'transl'
|
||||
transl.mergeNonMasterTransl(srcTransl, logger=logger)
|
||||
|
||||
# File path, or '-' for the standard output
|
||||
outputFile = into if output is None else output
|
||||
formatHandler.writeTranslation(transl, outputFile)
|
||||
|
||||
|
||||
def main():
|
||||
global params
|
||||
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
params = processCommandLine()
|
||||
|
||||
mergeXliffIntoXliff(params.source, params.into, params.output)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__": main()
|
||||
120
python3-flightgear/fg-new-translations
Executable file
120
python3-flightgear/fg-new-translations
Executable file
@@ -0,0 +1,120 @@
|
||||
#! /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
|
||||
|
||||
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()
|
||||
179
python3-flightgear/fg-update-translation-files
Executable file
179
python3-flightgear/fg-update-translation-files
Executable file
@@ -0,0 +1,179 @@
|
||||
#! /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
|
||||
|
||||
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()
|
||||
0
python3-flightgear/flightgear/__init__.py
Normal file
0
python3-flightgear/flightgear/__init__.py
Normal file
0
python3-flightgear/flightgear/meta/__init__.py
Normal file
0
python3-flightgear/flightgear/meta/__init__.py
Normal file
58
python3-flightgear/flightgear/meta/exceptions.py
Normal file
58
python3-flightgear/flightgear/meta/exceptions.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# -*- 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"
|
||||
1925
python3-flightgear/flightgear/meta/i18n.py
Normal file
1925
python3-flightgear/flightgear/meta/i18n.py
Normal file
File diff suppressed because it is too large
Load Diff
95
python3-flightgear/flightgear/meta/logging.py
Normal file
95
python3-flightgear/flightgear/meta/logging.py
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- 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
|
||||
81
python3-flightgear/flightgear/meta/misc.py
Normal file
81
python3-flightgear/flightgear/meta/misc.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# -*- 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)
|
||||
172
python3-flightgear/rebuild-fgdata-embedded-resources
Executable file
172
python3-flightgear/rebuild-fgdata-embedded-resources
Executable file
@@ -0,0 +1,172 @@
|
||||
#! /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()
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
THIS_RELEASE="2017.2"
|
||||
NEXT_RELEASE="2017.3"
|
||||
SUBMODULES="simgear flightgear fgdata"
|
||||
THIS_RELEASE="2018.1"
|
||||
NEXT_RELEASE="2018.2"
|
||||
SUBMODULES="simgear flightgear fgdata getstart"
|
||||
|
||||
#:<< '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,4 +42,3 @@ 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}"
|
||||
|
||||
|
||||
2
simgear
2
simgear
Submodule simgear updated: 9840302931...8e29cae309
Reference in New Issue
Block a user