Compare commits

...

148 Commits

Author SHA1 Message Date
4899cbc634 更新 'build_appimage.sh' 2022-12-21 21:11:44 +08:00
Florent Rougon
d8a16058bf download_and_compile.sh: remove some unnecessary quoting
Only in a few "crowded" places where this improves readability. Note
that in these cases, the quote removal does *not* prevent the parameter
values from containing spaces, tabs or newlines.
2022-12-15 23:10:13 +01:00
Florent Rougon
5e6276bd30 download_and_compile.sh: improve the --help output
Reorder options (most basic and important options first; related options
together; experimental or deprecated options last). Explain a bit more
in some cases. Use the https protocol in the URL of the FlightGear wiki.
2022-12-15 22:27:01 +01:00
Florent Rougon
fe33acae74 download_and_compile.sh: add option --override-repo
This option allows one to override the repository from which a given
component is to be cloned (it doesn't do anything when the repository
for a component is simply updated).

Example that downloads OSG 3.4.2 from James' repository (it has
FlightGear-specific patches applied):

  download_and_compile.sh -j$(nproc) -s --cleanup \
    --override-repo OSG=GitHub:github.com/zakalawe/osg.git \
    --component-branch OSG=fgfs-342-1 SIMGEAR FGFS DATA OSG
2022-12-15 22:18:12 +01:00
Florent Rougon
aa17379ae0 download_and_compile.sh: simplify the definition of _usage() 2022-12-15 22:17:42 +01:00
Florent Rougon
5e71ae60fe download_and_compile.sh: minor change to the --help output
Amend wording to avoid confusion (some people interpret "latest release"
as meaning "development branch"; use "latest stable release" to avoid
this confusion).
2022-12-05 18:23:07 +01:00
Florent Rougon
7469b39cad download_and_compile.sh: changes to the generated scripts
The first goal of this commit was to ensure that the LD_LIBRARY_PATH
setting performed in some of the generated scripts uses absolute paths,
otherwise if a process (such as ctest) changes the current directory
before starting an executable that needs our LD_LIBRARY_PATH setting, we
can have problems (thanks to Patrick Callahan for the report).

Some refactoring of the automated script generation plus a few other
fixes concerning these scripts were done along the way (use here
documents for better readability; don't use 'echo' with options as this
is non-portable; etc.).
2022-11-30 22:13:25 +01:00
Florent Rougon
1e65f0e144 download_and_compile.sh: little optimization 2022-11-25 09:56:14 +01:00
Florent Rougon
14e27756b1 download_and_compile.sh: new generated wrapper script named 'run'
This new script is created by download_and_compile.sh in the same way as
run_fgfs.sh and friends. It changes the current directory to $d/install,
where $d is the directory containing the 'run' script. Then it sets
LD_LIBRARY_PATH in the same way as run_fgfs.sh. Finally, it runs the
command formed of all arguments passed to it.

This can be used for instance to run SimGear tests with the proper
LD_LIBRARY_PATH setting: assuming SimGear has been built by
download_and_compile.sh and you are in the directory from which
download_and_compile.sh was run, you can do:

  cd build/simgear
  ../../run ctest --output-on-failure
2022-11-25 09:03:50 +01:00
Florent Rougon
11949b1e8e download_and_compile.sh: add core file support to run_fgfs_debug.sh
Usage of run_fgfs_debug.sh is slightly changed: you now need to put a
'--' argument before all arguments that you want to pass to fgfs. For
instance:

  ./run_fgfs_debug.sh -- --aircraft=ufo --airport=PMDY

There is also a new option: -c, alias --core-file. This option allows
one to start gdb from an existing fgfs core dump, with appropriate
LD_LIBRARY_PATH setting and --directory options; in this case, don't
specify any fgfs argument (the fgfs arguments used when the core file
was produced have been recorded therein). Example:

  ./run_fgfs_debug.sh -c /path/to/core

All this is documented with './run_fgfs_debug.sh --help'.
2022-11-25 00:38:21 +01:00
Florent Rougon
0ee880c5dc download_and_compile.sh: install libqt5quick5 if available
This should solve a bug where some launcher icons aren't displayed
properly. So far, we had an optional dependency on qml-module-qtquick2,
which depends on libqt5quick5 or libqt5quick5-gles, however only the
former ensures a proper display in the built-in launcher (when
libqt5quick5-gles is installed instead of libqt5quick5, users see black
squares instead of the icons on the left).
2022-10-23 10:08:13 +02:00
Stuart Buchanan
50fd23d72c Include more railway features, don't add tunnels
From mespieler.

8333805787116b9d5cbc91b67f2a6b9bac4922b1
2022-09-25 18:32:25 +01:00
James Hogan
8966dcd737
Windows: Install openxr_loader.dll
Add openxr_loader.dll to the list of 3rd party DLLs that need
installing. The OpenXR loader is now included in windows-3rd-party,
allowing VR support to be enabled, which requires this file.
2022-08-19 23:42:28 +01:00
Stuart Buchanan
382747c2d1 WS30: Improved gencoastlines
Use Overpass API more effectively in 1x1 degree blocks,
using same technique as genroads.py
2022-05-28 20:42:43 +01:00
Automatic Release Builder
5b12f55c3f Add libevent to packaging list 2022-04-20 10:26:52 +01:00
Automatic Release Builder
d043edf9c5 macOS: update for correct libEvent version 2022-04-19 13:48:56 +01:00
Automatic Release Builder
969c2f9788 Add helper script to fix macOS libEvent packaging 2022-03-08 15:14:17 +00:00
Automatic Release Builder
c346526e1b Windows installer: don't copy compiler runtime 2022-02-08 10:30:27 +00:00
Florent Rougon
7bcff8eaf4 i18n.py: declare plural forms for the Turkish language
I'm not quite sure, but it seems to me that Qt Linguist treats the
Turkish language as having one "universal form". We need plural forms
for Turkish since FGData commit c0bb8d8a8d64e1 in branch
'release/2020.3' added a 'tr' translation.
2022-02-03 15:30:46 +01:00
Fahim Imaduddin Dalvi
4730d57d40 WS30: Updated Dockerfile with python scripts
The Dockerfile has been updated to include Python, ws30 line data
generation scripts and their dependencies.
2022-01-22 17:18:23 +03:00
Fahim Imaduddin Dalvi
f672e8451b WS30: Added python dependency requirements file for scripts 2022-01-22 16:25:06 +03:00
Automatic Release Builder
65f2c2e041 Tweak macOS OpenAL packaging 2022-01-07 11:12:56 +00:00
Automatic Release Builder
b1dd31e255 Mac: include OpenAL-soft in the bundle 2022-01-06 14:19:11 +00:00
Automatic Release Builder
9fa81a6ab8 Tweak Mac Jenkins script to optionally use OpenAL-soft 2022-01-06 14:15:51 +00:00
Julian Smith
52c0efedb7 download_and_compile.sh: also install ffmpeg libraries for video encoding support. 2021-12-27 10:31:47 +00:00
Stuart Buchanan
d7abbaa10f WS30: Improved road generation 2021-12-05 20:38:19 +00:00
Fahim Imaduddin Dalvi
f46f25dbaf Updated Dockerfile for more efficient builds.
We now use multi-stage builds so that the build-time dependencies and
code are not included in the final image. Also updated the README with
information about Docker hub, and added a LICENSE file.
2021-11-17 21:39:38 +03:00
Fahim Imaduddin Dalvi
54e68e949f Added Dockerfile for VPB terrain generator
Added a Dockerfile that can be used to build a docker/podman image with
the required environment for VPB terrain generator. A sample generation
script is also included.
2021-11-15 20:23:44 +03:00
Brendan Black
1be19e5f12 Account for differences between test vm & build vm
my test vm has some extra *.so library symlinks so some patchelf commands were failing on the jenkins build vm - this changes the patchelf command to catch all the possible copied libraries
2021-09-25 09:02:16 +02:00
Brendan Black
f135bd8f61 build_appimage.sh: run patchelf on libharfbuzz
run patchelf on libharfbuzz as manjaro needs it now (rolling distros...)
2021-09-24 08:50:40 +01:00
Brendan Black
e36c646caf fix for https://sourceforge.net/p/flightgear/codetickets/2651/
libfreetype 2.11 breaks compatibility with older harfbuzz that we are including to enable backwards compatibility with Ubuntu 16.04 based dists, so we now need to include libfontconfig & libpng15

In future for next we might  not bother with harfbuzz,fontconfig etc as we are compiling OSG with vendor neutral dispatch (libGLvnd) that the older Mesa in 16.04 doesn't support
2021-09-10 11:19:13 +01:00
Automatic Release Builder
61abd3e89e Add serializer plugins to Windows installer
This should enable WS30 support in nightly builds.
2021-09-02 13:41:19 +01:00
Jonas K
232699cb31 Add positional option "--exec-app=" to AppImage launch script
This option allows execution of any application stored in "/usr/bin" of the AppImage.
It has to be used as the first argument handed to the launch script.

Squashed commits:
- Add additional parameter checks and verify executability
- Print help when no value is passed to --exec-app
- Add all packaged executables as "additional executable" arguments to call of linuxdeployqt
  + Required dependencies of other applications will be deployed and library paths updated.
  * Update help text
  * Use find instead of ls to make file name handling robust (special chars, newlines, spaces)
- Modify find command to filter for executable files instead of using find's "-executable" option
  Previously find failed to filter for executable files only when the AppImage was executed.
  When the was AppImage mounted, "ls -al" showed that the file "usr/bin/qt.conf" was not executable.
  However, when executing "find usr/bin/ -type f -executable" the file "usr/bin/qt.conf" still showed up.
  Executing the same find command on the not-mounted source appdir did not show the file.
  The change from "-executable" to logic ands/ors of "-user", "-group" and "-perm" fixes this behaviour.
  Additionally this commit does no longer add "fgfs" to the additional executables since it is the main executable and processed anyways.
- Update find command to properly check permissions
  Read permission and executability are required.
- Minor improvements for basename calls
  * Quotes around basename argument
  - Useless "basename" call
- Fix potential security flaw when matching application name input
  The matching of "/" was erroneous and allowed execution of binaries outside the AppImage's /usr/bin directory.
2021-08-31 11:04:41 +01:00
Florent Rougon
b42f543b93 i18n.py: print the problematic 'trans-unit' id when aborting
It's much easier to locate an error in a .XLF file when one has the id
of the 'trans-unit' element that causes the problem.
2021-08-04 00:07:55 +02:00
Automatic Release Builder
acd34fda78 Linuxdeployqt: Use -qmldir to define plugins
This should copy less stuff, and hopefully fix the reported error 
loading QtQuick Controls-2
2021-06-09 10:50:28 +01:00
Automatic Release Builder
7e26d650bc AppImage: default to launch, fix osgDB plugin loading
When no arguments are pased to the AppImage, start with
the launcher for a pleasant experience.

Adjust the RPath on our copied osgDB plugins, so that dependencies
are found at the bundled lib dir.
2021-06-07 16:54:16 +01:00
Automatic Release Builder
79ee40e885 Fix Ubuntu 16 / Mint 18 support: copy HarfBuzz
Need to include HarfBuzz in the image, which comes from /lib64 on our
build machine

Thanks to Brendan Black for tracking this down

Ticket-Id: https://sourceforge.net/p/flightgear/codetickets/2590/
2021-06-04 10:04:59 +01:00
James Turner
3bf94f7b61 AppImage: use stable 7 version of LinuxDeployQt 2021-05-24 15:46:43 +01:00
James Turner
32cb401c79 Windows: add osgdb_osgterrain loader to installer
Needed for WS3 testing
2021-05-21 09:17:28 +01:00
James Turner
4db42544d2 Fix for 64-bit only Windows build
Remove reference to OSG32 which is now empty
2021-05-20 14:00:09 +01:00
James Turner
9eafe4e274 AppImage: more tweaks to Linux build
Use RelWithDebInfo, switch to ninja, and fix the OSG-36 lib path
2021-05-20 09:31:45 +01:00
James Turner
178cdbe216 AppImage: switch to OSG 3.6.5 2021-05-19 10:16:01 +01:00
Automatic Release Builder
04587d3a39 Remove more files from the base package 2021-05-19 10:13:45 +01:00
Florent Rougon
aaf52f0628 download_and_compile.sh: accept qtchooser as an alternative to qt5-default
This should be more user-friendly, as qt5-default isn't part of recent
Debian/Ubuntu distros.

List discussion: https://sourceforge.net/p/flightgear/mailman/message/37281536/
2021-05-13 14:29:49 +02:00
Stuart Buchanan
bd01aad8e6 WS30 - Scenery features from OSM 2021-05-03 15:59:30 +01:00
Automatic Release Builder
8be5b2fc52 Update post-upload to support more file suffixes 2021-03-22 11:06:24 +00:00
Automatic Release Builder
6eae0403c1 Add this script so it doesn’t get lost 2021-03-22 11:04:05 +00:00
Automatic Release Builder
3d47c15feb Fix LibLZMA path 2021-03-18 15:50:00 +00:00
Florent Rougon
26c859fcbd git-date.py: minor changes
- Special-case Windows for the default config file location (this should
  allow the program to run even if HOME is unset).

- Improve the help text, in particular by reordering some of the
  options.
2021-03-11 21:01:37 +01:00
Florent Rougon
538e89be54 git-date.py: fix test for "no repository was specified"
Also perform miscellaneous minor formatting fixes.
2021-03-10 20:44:13 +01:00
Florent Rougon
b68dc80cb6 git-date.py: minor fix to the help text 2021-03-10 20:14:06 +01:00
Florent Rougon
d817865575 git-date.py: clarify the usage help text 2021-03-10 17:47:06 +01:00
Florent Rougon
d0f4f363d2 Add script git-date.py in directory 'dev-utils'
This script allows one to easily find commits in several Git
repositories around a given date (in any date format accepted by Git).
The repositories may be given labels for easier identification and can
be defined via a configuration file and/or the command-line arguments.

Option --checkout tells git-date.py to automatically perform a
'git checkout' in each of the repositories at the commits that were
found. Options --show-commits and --show-commits-option instruct it to
run 'git show' for each commit found with the options of your choice
(all options can also be set via a configuration file).

This script can be useful to find when a given regression happened in
FlightGear---or any project that makes use of several Git repositories.
For more details, run 'git-date.py --help'.
2021-03-10 17:12:47 +01:00
Automatic Release Builder
53a0c9cc2e Don't wipe all of output/, only data TXZs
Otherwise we wipe source tarballs created by the build script.
2021-02-17 11:04:57 +00:00
Automatic Release Builder
27475c599f Alternate syntax for older Git on Jenkins 2021-02-17 10:35:25 +00:00
Automatic Release Builder
b8bc8301f9 Fix Windows installer to add libLZMA.dll 2021-02-12 22:29:09 +00:00
Automatic Release Builder
411823a24d Add script to create base package and update TXZ 2021-02-12 22:28:52 +00:00
Slawek Mikula
799633854b - build_release_windows.bat - fix for creating InstallConfig.iss file 2021-02-11 21:24:05 +00:00
Slawek Mikula
2b0b734160 - #2524 - fix of FlightGear-files.iss include (after defines) 2021-02-11 15:22:46 +00:00
Slawek Mikula
1b2b8da12f - setupimg.bmp - new last page screen 2021-02-10 14:32:23 +00:00
Slawek Mikula
4e1d247ce3 - info-before-en.txt, info-before-pl.txt - EN/PL information before installation - unstable
- FlightGear-files.iss - removed commented-out files
- FlightGear.iss - add InfoBeforeFile for EN/PL languages
2021-02-10 14:32:23 +00:00
Slawek Mikula
136ef74759 - #2524 - removed unused script (don't know where it comes from :)) 2021-02-10 14:32:23 +00:00
Slawek Mikula
bfe6b6b925 - #2524 - ported changes from release installer to next branch (
split section of ISS installer, additional translated string,
files from flightgear source, removed antivirus message)
2021-02-10 14:32:23 +00:00
Slawek Mikula
7deb727a90 - #2244 - german translations 2021-02-10 14:32:23 +00:00
Slawek Mikula
68f0c9ee74 - #2244 - added spanish & dutch translations 2021-02-10 14:32:23 +00:00
Slawek Mikula
01a6208fa7 - #2244 - added some info about uninstall procedure inside fgfs.exe
(cherry picked from commit af8e8ffb800f8ac02f43bfeb517721f6c2038e80)
2021-02-10 14:25:07 +00:00
Slawek Mikula
fd93c81fbb - #2244 - i18n for windows installer
- build_release_windows.bat - add code to parse FGVersion and provide FGVersionGroup (major.minor) text
 - FlightGear.iss - extend docs, use FGHarnessDir to exclude direct drive mapping, use FGVersionGroup for installer marking, add i18n (en/pl) with custom messages, use %USERPROFILE instead of {userdocs} for additional folders

(cherry picked from commit 5da03d6ae9412afd53452c4e04fb33ca2fe36249)
2021-02-10 14:24:53 +00:00
Automatic Release Builder
4ad749a481 Update catalog compatability versions
Ensure the stable 2020 is only used for the LTS, and
trunk is used for 2020.4 / next
2021-01-24 15:34:20 +00:00
James Turner
0cf47573fb Add LibLZMA to installers
- Windows .ISS script
- AppImage .so copy list
- manual copy on macOS DMG building
2021-01-10 12:02:40 +00:00
Florent Rougon
79642b4d29 download_and_compile.sh: add dependency liblzma-dev for SIMGEAR 2021-01-09 18:53:58 +01:00
Automatic Release Builder
273927d40a Stable 2020 catalog: remove 2020.4 support 2020-12-14 14:30:41 +00:00
Automatic Release Builder
979d8f051e macOS: include osgTerrain in packaging 2020-11-29 16:11:12 +00:00
Automatic Release Builder
c24e3c2aac Fix typo in Windows build .bat 2020-11-21 16:03:31 +00:00
Florent Rougon
fa9550e5e7 download_and_compile.sh: don't install OSG or plib packages if these are built
If the OSG component has been specified, don't attempt to install a
libopenscenegraph...-dev package from the distro. Ditto for the
libplib-dev package when the PLIB component has been specified.
2020-11-16 21:24:07 +01:00
Automatic Release Builder
b11dab8c30 Windows: remove compositor from build script 2020-11-16 18:36:31 +00:00
Florent Rougon
4a82d5e8bc download_and_compile.sh: qml-module-qtquick-controls2 for everything but --old-lts
Require qml-module-qtquick-controls2 when building 'next', or using -s,
or --lts.
2020-11-16 15:06:09 +01:00
legoboyvdlp R
444e8c0338 Add osgTerrain to the Windows install 2020-11-15 09:33:58 +00:00
Florent Rougon
c6dde7ecc5 download_and_compile.sh: make --lts use release/2020.3 and add --old-lts
For SimGear, FlightGear and FGData (i.e., the SIMGEAR, FGFS and DATA
components in download_and_compile.sh-speak), option --lts now means
release/2020.3 and the new option --old-lts means release/2018.3.
2020-11-14 19:08:15 +01:00
Brendan Black
4b45f4224e cp libfreebl* crypto libs so ubuntu 20.10 works 2020-10-28 15:11:57 +00:00
Automatic Release Builder
eea397ed85 Make set-version.sh handle new naming
Now we renamed simgear-version and flightgear-version, this
script needed to get smarter.
2020-10-26 10:09:44 +00:00
Automatic Release Builder
b8a7bf3104 Catalogs: add 2018 -> 2020 migration information 2020-10-25 18:08:44 +00:00
James Turner
00d4c6ec93 Re-enable Ibiblio in update-catalogs.sh 2020-10-22 12:59:24 +00:00
Automatic Release Builder
6435bcbf4f FGAddon trunk catalog: update version options
Mark the trunk catalog as compatible with 2020.4, and remove older
versions from the compat list.
2020-10-22 13:56:38 +01:00
Florent Rougon
c731caa23d download_and_compile.sh: rename --sg-cmake-args to --sg-cmake-arg and --fg-cmake-args to --fg-cmake-arg
This is more logical this way, since every use of such an option
specifies exactly *one* additional argument to pass to CMake.
2020-10-20 10:29:41 +02:00
Florent Rougon
2618144e24 download_and_compile.sh: add support for --sg-cmake-args and --fg-cmake-args
Each of these options may be passed multiple times. The advantage over
the previous interface (environment variables SG_CMAKEARGS and
FG_CMAKEARGS) is that the new interface allows one to pass arguments
containing spaces to CMake, for instance:

  --sg-cmake-args='-DCMAKE_CXX_FLAGS=-Wno-deprecated-declarations -Wall'

(the single quotes here would be interpreted by the user's shell, and
removed before download_and_compile.sh can see them). Setting the
environment variables SG_CMAKEARGS and FG_CMAKEARGS should still work as
before but is now deprecated.

The implementation uses Bash arrays named SG_CMAKE_ARGS and
FG_CMAKE_ARGS, but in order to avoid confusing users about the
deprecated variable names, the log file continues to print
'SG_CMAKEARGS=...' and 'FG_CMAKEARGS=...' (note the different use of
underscores in the names).
2020-10-20 01:39:27 +02:00
Automatic Release Builder
90f951a899 Update VS version for nightly Windows builds
Disable 32-bit builds for the moment.
2020-10-15 12:22:11 +01:00
Automatic Release Builder
ebaa83c483 Update version information 2020-10-13 22:46:05 +01:00
Stuart Buchanan
c2223d4deb Better stats for aircraft_updates.py and set exec 2020-10-13 19:17:34 +01:00
Stuart Buchanan
0472d9483c fgaddon utilities
aircraft_updates.py - list updated aircraft in fgaddon between two date
points.  Useful for release notes.

find_md5file.py - identify identical files based on md5sum.  Useful
for finding license infringement.
2020-10-11 20:21:51 +01:00
James Turner
b86121be85 Add catalog update script
Ensure this doesn't get lost, it's nothing magic but helps
to document+capture what the server is doing, in case
someone needs to replicate it.
2020-09-21 10:16:09 +00:00
James Turner
c5032d816b Fix output path for 2020 stable catalog 2020-09-21 08:33:55 +00:00
Automatic Release Builder
8d558e636a Fix paths for SVN branch 2020-09-19 21:43:42 +01:00
Automatic Release Builder
ebcf07ddaa Ignore catalog md5 sums data 2020-09-19 21:42:46 +01:00
Automatic Release Builder
d6cf56a465 Add 2020 FGaddon catalog 2020-09-19 21:36:21 +01:00
Automatic Release Builder
7d75f46d2c Build_appImage tweaks 2020-09-18 10:46:03 +01:00
Automatic Release Builder
1a76b92300 Fix build_appimage permissions 2020-09-16 13:14:00 +01:00
Florent Rougon
56ae978017 download_and_compile.sh: allow '_', '-' and '.' in usernames
With this commit, option --git-clone-site-params accepts '_', '-' and
'.' in usernames. Thanks to Keith Paterson for the report.
2020-09-02 11:06:05 +02:00
James Turner
bbf956b518 Downloads scripts 2020-08-24 06:43:00 -04:00
Florent Rougon
e78b239597 download_and_compile.sh: require qml-module-qtquick-controls2 when building next 2020-07-14 12:32:27 +02:00
Julian Smith
754b347d7c Cope with renamed version => flightgear-version file. 2020-07-04 09:02:27 +01:00
Florent Rougon
cf95fc3530 download_and_compile.sh: more reliable test in _gitDownload()
Before this change, using OSG with download_and_compile.sh several times
in the same directory would fail because the upstream repo for OSG has
none of README, README.txt and README.rst at top-level (it has a
README.md). Testing for the .git dir is definitely more reliable.
2020-07-03 14:21:05 +02:00
Florent Rougon
25d9d717b5 download_and_compile.sh: no component and only --cleanup -> only do cleanup
If --cleanup is used and no component has been specified on the command
line, run the cleanup routine but don't process any component: no
download, no compilation, no installation. Previously(*), this used to
process the default set of components: SIMGEAR FGFS and DATA.

Therefore, if all you want to do is to remove compiled and installed
files, you can now run:

  download_and_compile.sh --cleanup

(*) During less than 24 hours, as --cleanup was added yesterday.
2020-06-30 15:11:02 +02:00
Florent Rougon
aa563cb5cb download_and_compile.sh: refactoring
Move several chunks of code to their own function. This will make the
code easier to follow when largish chunks are executed only under
certain conditions.

Minor changes unrelated to the refactoring:
  - make _logSep print a larger separator (78 chars);
  - write the SELECTED_SUITE at the top of the log file.
2020-06-30 15:11:02 +02:00
Automatic Release Builder
43082ed65b Add AppImage creation script by Brendan Black
Not fully tested yet but want to get this on Jenkins to see how it
goes.
2020-06-30 11:31:44 +01:00
Florent Rougon
9f710a8c84 download_and_compile.sh: add safety net in _cleanup()
Make sure $INSTALL_DIR is really a harmless 'install' directory before
calling 'rm -rf' on it.
2020-06-29 16:07:09 +02:00
Florent Rougon
3099633675 download_and_compile.sh: fix the order of operations in _gitUpdate()
_gitUpdate() used to call 'git pull' then 'git checkout'. If the latter
command really did a branch switch, this could leave the local branch
behind its remote counterpart (that was hopefully fetched by the
'git pull'). From now on, we do:

  git fetch origin
  git checkout --force "$branch"
  git pull --rebase

(the --force option was already there before in the form of -f). This
way, we can be sure that the local branch we check out is up-to-date
when the function returns.

Also replace short options by long ones for better readability of the
code, and use Bash's [[ ... ]] conditional construct instead of [ ... ]
for more efficiency---I think.

Note: 'git stash save' is documented as deprecated in favor of
      'git stash push', however the latter appears to have been
      introduced in 2017, therefore I believe it is too early to use it
      in download_and_compile.sh.
2020-06-29 15:23:53 +02:00
Florent Rougon
21c13c0886 download_and_compile.sh: add option --cleanup
This option recursively deletes build and install directories, but
preserves FGData if present (FGData is in
<base_dir>/install/flightgear/fgdata, hence the need to take special
care of it).

There is currently no way to trigger this cleanup routine whithout
pretending to act on at least one component, since "no components
specified" implies "SIMGEAR FGFS DATA". That said, using -pn -dn -rn -cn
with one of the components you already have should be close enough to
"only do the cleanup".
2020-06-29 14:23:18 +02:00
Florent Rougon
0972e57a5b download_and_compile.sh: use the set_ld_library_path variable
This improves readability a little bit. set_ld_library_path was defined
but unused since commit a5e4c47f. Note that this variable must be set
*after* the OpenBSD-specific code block because its definition relies on
the value of 'paths', which is modified in said block.
2020-06-23 19:22:45 +02:00
Florent Rougon
3bce994ea8 download_and_compile.sh: prompt when building 'next' and logfile not already present
This ensures that users building 'next' have seen the message that warns
about possible instability and are aware of the other options (--lts for
the latest Long Term Support release, -s for the latest release).

The default answer is to continue. If --non-interactive has been given,
the prompt is skipped and download_and_compile.sh proceeds as usual.

This commit also adds _yes_no_prompt() which makes more sense than
_yes_no_quit_prompt() here, since the 'no' answer implies that the user
wants to quit.
2020-06-23 11:10:25 +02:00
Florent Rougon
fdf98d0ef3 download_and_compile.sh: consistent indentation for long options in _usage() 2020-06-22 20:38:47 +02:00
Florent Rougon
041dc98c9c download_and_compile.sh: don't hardcode the address of the FG repo
When doing the 'git ls-remote' request to find the latest FG release,
d&c was using a hardcoded address for the FG repo. Use
${REPO_ADDRESS[FGFS]} instead.
2020-06-22 20:05:26 +02:00
Florent Rougon
1f3f4ea353 download_and_compile.sh: only print COMPONENT_BRANCH[foo]=bar for built components
Only those components present in WHATTOBUILD are really interesting when
printing and logging COMPONENT_BRANCH[foo]=bar. Inter-component deps are
taken into account before doing that, since they may add components to
WHATTOBUILD.
2020-06-22 19:13:58 +02:00
Florent Rougon
c4c8f0a099 download_and_compile.sh: add options --lts and --component-branch
Option --lts builds the latest LTS release of components SIMGEAR, FGFS
and DATA. The presence of option -s or --lts affects the version or
branch checked out for each component; however, passing none of these
options doesn't imply that development versions will be used for
everything---this selects development versions for FlightGear and
possibly closely-related software, but for the rest, we aim at something
reasonably usable, as in "current release".

For each component, the default version selected depending on whether
-s, --lts or none of these was given, can be overridden using
'--component-branch COMPONENT=BRANCH' (without the quotes). For
instance:

  download_and_compile.sh --lts \
    --component-branch OSG=OpenSceneGraph-3.6 SIMGEAR FGFS DATA OSG

will build the latest LTS release of FlightGear against the
OpenSceneGraph-3.6 branch of OpenSceneGraph. Option --component-branch
may be used several times and always overrides the defaults determined
by the presence or absence of -s or -lts. Thus, the relative order of
-s, --lts and --component-branch options does not matter.

This commit also adds text to the standard output and log file that
tells users:
  - which "suite" they have selected (default=next, -s or --lts) and
    what this implies;
  - which branch will be checked out for each component (i.e., after
    the overrides from all --component-branch options passed have been
    applied).

It is nonsensical to provide both -s and --lts in the same invocation,
but the last one wins.
2020-06-22 18:26:39 +02:00
Automatic Release Builder
28de5426f2 Localized catalogs: fix name/description bug 2020-06-22 10:02:40 +01:00
Florent Rougon
e105274de4 Update catalog/README.md (and fix a typo) 2020-06-22 00:41:05 +02:00
Florent Rougon
8028ce2888 Python: move test modules and data to python3-flightgear/flightgear/meta/tests/
- Move test_catalog.py, test_sgprops.py and catalog/testData/ to
  python3-flightgear/flightgear/meta/tests/.
- Copy catalog/fgaddon-catalog/ to the same place (it is needed by
  test_catalog.py).
- Adapt test_catalog.py and test_sgprops.py accordingly.
- Remove the executable bits from test_catalog.py and test_sgprops.py:
  this is because test_catalog.py can't be run directly anymore; well,
  it can but 3 tests would fail in this setup. No time to investigate
  why (sorry), but this commit adds a README.txt in
  python3-flightgear/flightgear/meta/tests/README.txt that explains how
  to run the tests in a way that works (basically, run
  'python3 -m unittest' from the python3-flightgear directory).

For a bit more context, see
<https://sourceforge.net/p/flightgear/mailman/message/37042247/>.
2020-06-22 00:30:51 +02:00
Automatic Release Builder
cef19a8b13 Catalog I18N support
Read I18N satrings form aircraft data and add to the catalog
2020-06-21 19:25:18 +01:00
Florent Rougon
3a36bdd474 i18n: move the scripts to the top-level 'i18n' directory
Also add a README.md to python3-flightgear explaining how to use the
PYTHONPATH environment variable or a .pth file in order to run the
Python scripts in FGMeta, and pointing to the top-level directories
'catalog' and 'i18n'.
2020-06-19 18:26:43 +02:00
Florent Rougon
b86452cf08 fg-copy-weather-scenarios-to-default-locale: adjust the sgprops import 2020-06-19 18:15:30 +02:00
Florent Rougon
1c2d17d869 Reorganize catalog modules
- Move the support modules inside python3-flightgear/flightgear/ and
  remove their shebang, if any.
- Accordingly adapt the import statements.
- Change shebangs from e.g. '#! /usr/bin/python' to
  '#! /usr/bin/env python3'.
- Small changes to make Python 3 happy with all scripts.

catalog/check_aircraft.py should be run under Python 3 from now on.
2020-06-19 18:15:25 +02:00
Florent Rougon
d259ec0b76 i18n Python scripts: improve fg-copy-weather-scenarios-to-default-locale
- Use the new flightgear.meta.strutils.simplify() function.
- Automatically add a comment to the generated file to indicate that it
  was automatically generated and shouldn't be manually modified, etc.
- Improve error handling: abort with a clear error message if any of the
  'id', 'name' and 'desc' children of a 'scenario' element is
  problematic (empty or missing, for instance).
- Rename make_xml_leaf() to makeXmlLeaf() + other minor renaming.
2020-06-18 14:23:03 +02:00
Florent Rougon
52e84741d0 i18n Python scripts: add module flightgear.meta.strutils
For now, the module only contains the simplify() function, which will be
used by fg-copy-weather-scenarios-to-default-locale.
2020-06-18 14:22:57 +02:00
Automatic Release Builder
c2a241c357 Review feedback from Florent 2020-06-18 10:16:06 +01:00
Florent Rougon
120d02e5fb i18n Python scripts: rename BasicL10NResourceManager._readFgResourceFile()
Class method BasicL10NResourceManager._readFgResourceFile() was not
meant to be private; remove the leading underscore.
2020-06-18 01:06:37 +02:00
Florent Rougon
14eb302022 i18n Python scripts: fix a typo in TranslationUnit._stringsKey()
I believe the problematic code could only be reached when reading buggy
versions (i.e., with duplicate ids) of the legacy FlightGear XML
non-master l10n files, which is why we haven't tripped on it so far.
2020-06-18 00:56:37 +02:00
Automatic Release Builder
d502afa171 Add weather-scenarios to i18n list 2020-06-17 17:08:50 +01:00
Automatic Release Builder
14b3950d44 Script to create default translation for weather 2020-06-17 17:03:25 +01:00
Florent Rougon
eabc8534b0 i18n Python scripts: define the list of basic categories at the top
Introduce a BASIC_CATEGORIES variable at the top of
python3-flightgear/flightgear/meta/i18n.py that lists all categories
handled by BasicL10NResourceManager. Since currently all of our
translation files can be handled this way (the XML master files all have
a flat structure), we only need to say BASIC_CATEGORIES = CATEGORIES.

With this change, adding a new basic category such as
'weather-scenarios' only requires one to add it to CATEGORIES.
2020-06-17 13:12:31 +02:00
Automatic Release Builder
a80917705d Update trunk FGaddon catalog metadata
Ensure next is usable for trunk FGaddon.
2020-06-16 12:54:11 +01:00
Automatic Release Builder
e92948a44e track submodule changes for release 2020-06-15 12:33:58 +01:00
Automatic Release Builder
fd2b26a975 new version: 2020.3.0 2020-06-15 12:33:58 +01:00
Automatic Release Builder
40b6272570 new version: 2020.2.1 2020-06-15 12:33:58 +01:00
Automatic Release Builder
a82e6f7f6b Adjust for new LTS release 2020-06-15 12:33:20 +01:00
legoboyvdlp R
e34d02edbc Windows install: re-add js_demo.exe
The former is an advanced configuration tool for users' joysticks.
2020-05-25 09:26:12 +01:00
Florent Rougon
3810a31230 download_and_compile.sh: improve user-interaction
Since the prompt is repeated by _yes_no_quit_prompt() every time an
invalid answer is given, a short sentence is better than the empty
string.
2020-05-24 16:31:26 +02:00
Florent Rougon
00710497b0 download_and_compile.sh: add missing quoting
This is needed because $answer will be empty in case the default $2 is
empty and the user hits Enter at the prompt.
2020-05-24 11:39:27 +02:00
Florent Rougon
420034d5b5 download_and_compile.sh: make initial cloning of FGData easy and secure
Because cloning FGData from SourceForge using https does not work (this
has been the case for *years*) whereas normal updates of an existing
clone do work, and so does cloning the repository from its official
GitLab mirror using https, this commits implements a special case in
_gitDownload():

  If the assembled clone URL is
  <https://git.code.sf.net/p/flightgear/fgdata>, then ask the user if he
  agrees to automatically clone FGData from GitLab and arrange the
  repository setup to fetch subsequent updates from SourceForge. This
  should be fine because <https://gitlab.com/flightgear/fgdata> is an
  official mirror of FGData. The default answer is thus to do so. It is
  automatically chosen when download_and_compile.sh is called with
  --non-interactive (new option).

This implies that the initial use of download_and_compile.sh is again as
easy as subsequent ones.

This commits also adds the utility function _yes_no_quit_prompt() to
repeatedly ask a question ($1) until a valid answer has been provided.
The function automatically uses the default answer ($2) if
--non-interactive has been passed to download_and_compile.sh. See the
“discussion” at
<https://sourceforge.net/p/flightgear/mailman/message/37017469/>.
2020-05-24 11:14:36 +02:00
Florent Rougon
b3893f7bda i18n Python scripts: allow autodetection of translation files
- Add class method availableTranslations() to AbstractFormatHandler in
  i18n.py.

- Use it in fg-update-translation-files to allow autodetection of the
  available translations when no LANGUAGE_CODE is passed to
  fg-update-translation-files.

This should address James' wish at
<https://sourceforge.net/p/flightgear/mailman/message/37003967/>.
2020-05-08 10:33:35 +02:00
James Turner
4e28b88c22 Windows: fixes for compositor builds 2020-05-03 19:02:26 +01:00
Florent Rougon
fa0dcb5d4d download_and_compile.sh: add libssl-dev as mandatory dep for CMake
Unless SSL support is turned off, libssl-dev is needed to build CMake.
Thanks to Jeff Davis for the report.
2020-05-01 17:39:46 +02:00
James Turner
819074136a Re-enable ‘full-fat’ nightlies for macOS
May need to tweak the bundle IDs for notarization, let’s see.
2020-05-01 12:00:59 +01:00
James Turner
03ac46120c Windows: remove erroneous space breaking build
This was causing to pick the second prefix path as the source dir,
which doesn’t work so well.
2020-05-01 08:46:49 +01:00
James Turner
cc76052038 Trunk FGAddon hangar: support 2020.* versions 2020-04-29 14:58:14 +01:00
legoboyvdlp R
3f38a3cf18 Add support for compositor to windows builds 2020-04-29 08:37:50 +01:00
James Turner
1c7dcaf5d5 macOS: package libSentry 2020-04-29 08:32:15 +01:00
James Turner
dbdfc52a00 Adjust release script 2020-04-27 09:31:38 +01:00
James Turner
d4489091e2 track submodule changes for release 2020-04-27 09:30:09 +01:00
James Turner
6fa2edf9d5 new version: 2020.2.0 2020-04-27 09:30:08 +01:00
102 changed files with 4493 additions and 733 deletions

3
.gitignore vendored
View File

@ -22,3 +22,6 @@ CMakeCache.txt
*.pyc *.pyc
build-* build-*
testOutput* testOutput*
md5sum.xml
staging

50
FlightGear-files.iss Normal file
View File

@ -0,0 +1,50 @@
[Files]
; 64 bits install
Source: "{#InstallDir64}\bin\*.*"; DestDir: "{app}\bin"; Excludes: "{#ExcludedBinaries}"; Flags: ignoreversion recursesubdirs; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\zlib.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\OpenAL32.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libpng.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libcurl.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libintl-8.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\sentry.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\crashpad_handler.exe"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\dbus-1-3.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\event_core.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\liblzma.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\openxr_loader.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
; Include the base package
#if IncludeData == "TRUE"
Source: "{#FgHarnessPath}\fgdata\*.*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist
#endif
; 64 bits install
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osg.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgDB.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgGA.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgParticle.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgText.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgUtil.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgViewer.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgSim.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgFX.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgTerrain.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\ot{#OTSoNumber}-OpenThreads.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_ac.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_osga.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_3ds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_mdl.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_jpeg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_rgb.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_png.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_dds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_txf.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_tiff.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_freetype.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_osgterrain.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_serializers_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_serializers_osgterrain.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode

39
FlightGear-i18n.iss Normal file
View File

@ -0,0 +1,39 @@
[Messages]
ConfirmUninstall=Are you sure you want to completely remove %1 {#FGVersion} and all of its components?
pl.ConfirmUninstall=Czy na pewno chcesz całkowicie usunąć %1 {#FGVersion} i wszystkie jego komponenty?
es.ConfirmUninstall=¿ Estás seguro de que quieres borrar completamente %1 {#FGVersion} y todos sus componentes ?
nl.ConfirmUninstall=Weet u zeker dat u %1 {#FGVersion} en alle bijbehorende onderdelen wilt verwijderen?
de.ConfirmUninstall=Bist Du sicher, dass Du %1 {#FGVersion} und alle Komponenten entfernen willst?
[CustomMessages]
CreateDesktopIcon=Create a &desktop icon
CreateDesktopIconGroup=Additional icons:
RemoveAllSettings=Remove all settings, downloaded scenery and aircraft
RemoveAllSettingsDescription=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.
FirewallFgException=Allows FlightGear to send and receive data over the multiplayer network and to get METARs.
FirewallFgcomException=Allows FGCom to establish a connection to FlightGear and the VoIP server for voice ATC communication.
pl.CreateDesktopIcon=Utwórz ikony na pulpicie
pl.CreateDesktopIconGroup=Dodatkowe ikony:
pl.RemoveAllSettings=Usuń wszystkie ustawienia, pobraną scenerię i samoloty
pl.RemoveAllSettingsDescription=FlightGear zapisuje niektóre ustawienia w katalogach użytkownika. Dodatkowo, sceneria lub dane statków powietrznych mogą być pobierane do katalogu pobrań. Aby całkowicie usunąć te ustawienia, wybierz tą opcję.
pl.FirewallFgException=Pozwala aplikacji FlightGear na wysyłanie i pobieranie danych przez sieć multiplayer oraz aby pobrać dane pogodowe METAR.
pl.FirewallFgcomException=Pozwala aplikacji FGCom na ustanowienie połączenia do aplikacji FlightGear i do serwerów VoIP dla komunikacji głosowej z ATC (kontrolerem lotów).
es.CreateDesktopIcon=Crear icono en el escritorio
es.RemoveAllSettings=Borrar todos los ajustes, escenarios y aviones descargados
es.RemoveAllSettingsDescription=FlightGear almacena algunos ajustes en tu carpeta de usuario. Adicionalmente, los datos de escenarios y aviones pueden haber sido descargados en el directorio de descargas. Para borrar completamente todos esos archivos, selecciona esta opción.
es.FirewallFgException=Permite a FlightGear mandar y recibir datos a la red multijugador y obtener METAR.
es.FirewallFgcomException=Permite a FGCom establecer una conexión con FlightGear y el servidor VoIP para comunicaciones de voz con el ATC.
nl.CreateDesktopIcon=Maak een snelkoppeling op het &bureaublad
nl.RemoveAllSettings=Verwijder alle instellingen en gedownloade data
nl.RemoveAllSettingsDescription=FlightGear bewaart een aantal instellingen in uw gebruikersmap. Mogelijk is er ook data in de downloadmap opgeslagen. Selecteer deze optie om die bestanden definitief te verwijderen.
nl.FirewallFgException=Sta FlightGear toe om data te verzenden en ontvangen via het multiplayernetwerk en om live weergegevens te downloaden.
nl.FirewallFgcomException=Sta FGCom toe om verbinding met FlightGear en de VoIP server te maken voor op stem gebaseerde ATC-communicatie.
de.CreateDesktopIcon=Ein Desktop-Icon anlegen
de.RemoveAllSettings=Alle Einstellungen und heruntergeladene Daten löschen
de.RemoveAllSettingsDescription=FlightGear speichert seine Einstellungen in deinem User-Verzeichnis. Zusätzlich heruntergeladene Flugzeuge und Szenerie-Daten können sich im Download-Verzeichnis befinden. Wähle diese Option, um alle Daten zu löschen.
de.FirewallFgException=Erlaubt FlightGear die Verbindung zum Multiplayer-Netzwerk und den Download von METAR-Daten.
de.FirewallFgcomException=Erlaubt FGCom die Verbindung zu FlightGear- und VoIP-Servern für den ATC-Sprechfunk.

210
FlightGear.iss Executable file → Normal file
View File

@ -1,4 +1,4 @@
; Script generated by the Inno Setup Script Wizard. ; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; ;
; This script creates an installable FlightGear package for Win32 using the ; This script creates an installable FlightGear package for Win32 using the
@ -7,7 +7,9 @@
; ;
; http://www.jrsoftware.org/isinfo.php ; http://www.jrsoftware.org/isinfo.php
; ;
; Note: the files must appear in the X: drive. ; Note: Files root path is defined in the FgHarnessPath (in InstallConfig.iss)
;
; For example if You want to use X: drive as a root path
; You can do this with the command below: ; You can do this with the command below:
; ;
; subst X: path_to_files ; subst X: path_to_files
@ -17,185 +19,95 @@
; C:\> subst X: F:\Path\to\FlightGear\root ; C:\> subst X: F:\Path\to\FlightGear\root
; C:\> subst X: F:\ ; C:\> subst X: F:\
; ;
; TRANSLATION NOTE:
; - external i18n files HAVE to be UTF-8 with BOM encoded. Otherwise the installer can
; not detect correct file encoding
;
; InstallConfig.iss example content:
;
; #define FGHarnessPath "x:"
; #define FGVersion "2020.4.1"
; #define FGVersionGroup "2020.4"
; #define OSGVersion "3.0.0"
; #define OSGSoNumber "2"
; #define OTSoNumber "3"
; #define FGDetails "-nightly"
; #define IncludeData "FALSE"
;
; Uninstall procedure with --uninstall flag:
; executed by fgfs.exe (fg_init.cxx):
; - removes all under the FG_HOME directory
; - removes all from Download dir/Terrasync
; - removes all from Download dir/Aircraft
#include "InstallConfig.iss" #include "InstallConfig.iss"
#include "FlightGear-i18n.iss"
#define InstallDir32 "X:\install\msvc140" #define FGSourcePath FgHarnessPath + "\flightgear"
#define OSGInstallDir InstallDir32 + "\OpenSceneGraph" #define InstallDir64 FgHarnessPath + "\install\msvc140-64"
#define OSGPluginsDir OSGInstallDir + "\bin\osgPlugins-" + OSGVersion
#define InstallDir64 "X:\install\msvc140-64"
#define OSG64InstallDir InstallDir64 + "\OpenSceneGraph" #define OSG64InstallDir InstallDir64 + "\OpenSceneGraph"
#define OSG64PluginsDir OSG64InstallDir + "\bin\osgPlugins-" + OSGVersion #define OSG64PluginsDir OSG64InstallDir + "\bin\osgPlugins-" + OSGVersion
#define ThirdPartyDir FgHarnessPath + "\windows-3rd-party\msvc140"
#define ThirdPartyDir "X:\windows-3rd-party\msvc140"
; we copy everything in install/<arch>/bin except these, which aren't ; we copy everything in install/<arch>/bin except these, which aren't
; useful to the end-user to ship ; useful to the end-user to ship
#define ExcludedBinaries "*smooth.exe,metar.exe,js_demo.exe" #define ExcludedBinaries "*smooth.exe,metar.exe"
#include "FlightGear-files.iss"
[Setup] [Setup]
AppId=FlightGear AppId=FlightGear_{#FGVersionGroup}
AppName=FlightGear AppName=FlightGear
AppPublisher=The FlightGear Team AppPublisher=The FlightGear Team
OutputBaseFilename=FlightGear-{#FGVersion}{#FGDetails} OutputBaseFilename=FlightGear-{#FGVersion}{#FGDetails}
AppVerName=FlightGear v{#FGVersion} AppVerName=FlightGear v{#FGVersion}
AppVersion={#FGVersion}
AppPublisherURL=http://www.flightgear.org AppPublisherURL=http://www.flightgear.org
AppSupportURL=http://www.flightgear.org AppSupportURL=http://www.flightgear.org
AppUpdatesURL=http://www.flightgear.org AppUpdatesURL=http://www.flightgear.org
DefaultDirName={pf}\FlightGear {#FGVersion} DefaultDirName={pf}\FlightGear {#FGVersionGroup}
UsePreviousAppDir=no UsePreviousAppDir=no
DefaultGroupName=FlightGear {#FGVersion} DefaultGroupName=FlightGear {#FGVersionGroup}
UsePreviousGroup=no UsePreviousGroup=no
LicenseFile=X:\flightgear\COPYING LicenseFile={#FGSourcePath}\COPYING
Uninstallable=yes Uninstallable=yes
SetupIconFile=X:\flightgear\package\flightgear.ico SetupIconFile={#FgHarnessPath}\windows\flightgear.ico
VersionInfoVersion={#FGVersion}.0 VersionInfoVersion={#FGVersion}.0
InfoBeforeFile=X:\flightgear\package\windows\infobefore.txt WizardImageFile={#FgHarnessPath}\windows\setupimg.bmp
WizardImageFile=X:\flightgear\package\windows\setupimg.bmp
WizardImageStretch=No WizardImageStretch=No
WizardSmallImageFile=X:\flightgear\package\windows\setupsmall.bmp WizardSmallImageFile={#FgHarnessPath}\windows\setupsmall.bmp
VersionInfoCompany=The FlightGear Team VersionInfoCompany=The FlightGear Team
UninstallDisplayIcon={app}\bin\fgfs.exe UninstallDisplayIcon={app}\bin\fgfs.exe
ArchitecturesInstallIn64BitMode=x64 ArchitecturesInstallIn64BitMode=x64
ArchitecturesAllowed=x86 x64 ArchitecturesAllowed=x64
; Sign tool must be defined in the Inno Setup GUI, to avoid ; Sign tool must be defined in the Inno Setup GUI, to avoid
; exposing the certificate password ; exposing the certificate password
; SignTool=fg_code_sign1 ; SignTool=fg_code_sign1
[Tasks] [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. Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:CreateDesktopIconGroup}"
Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:"
[Files] [Languages]
; NOTE: run subst X: F:\ (or whatever path the expanded tree resides at) Name: "en"; MessagesFile: "compiler:Default.isl"; InfoBeforeFile: "{#FgHarnessPath}\windows\info-before-en.txt"
;Source: "X:\*.txt"; DestDir: "{app}"; Flags: ignoreversion Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl"; InfoBeforeFile: "{#FgHarnessPath}\windows\info-before-pl.txt"
; 32 bits install Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl";
Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl";
Source: "{#InstallDir32}\bin\*.*"; DestDir: "{app}\bin"; Excludes: "{#ExcludedBinaries}"; Flags: ignoreversion recursesubdirs; Check: not Is64BitInstallMode Name: "de"; MessagesFile: "compiler:Languages\German.isl";
;locale only exists for fgrun - which has been disabled
;Source: "{#InstallDir32}\share\locale\*"; DestDir: "{app}\bin\locale"; Flags: ignoreversion recursesubdirs; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\zlib.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\OpenAL32.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\libpng.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\libcurl.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\libintl-8.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\sentry.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\crashpad_handler.exe"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\dbus-1-3.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty\bin\event_core.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
; 64 bits install
Source: "{#InstallDir64}\bin\*.*"; DestDir: "{app}\bin"; Excludes: "{#ExcludedBinaries}"; Flags: ignoreversion recursesubdirs; Check: Is64BitInstallMode
;locale only exists for fgrun - which has been disabled
;Source: "{#InstallDir64}\share\locale\*"; DestDir: "{app}\bin\locale"; Flags: ignoreversion recursesubdirs; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\zlib.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\OpenAL32.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libpng.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libcurl.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\libintl-8.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\sentry.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\crashpad_handler.exe"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\dbus-1-3.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#ThirdPartyDir}\3rdParty.x64\bin\event_core.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
; Include the base package
#if IncludeData == "TRUE"
Source: "X:\fgdata\*.*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist
#endif
; 32 bits install
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osg.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgDB.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgGA.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgParticle.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgText.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgUtil.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgViewer.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgSim.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\osg{#OSGSoNumber}-osgFX.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGInstallDir}\bin\ot{#OTSoNumber}-OpenThreads.dll"; DestDir: "{app}\bin"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_ac.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_osga.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_3ds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_mdl.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_jpeg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_rgb.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_png.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_dds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_txf.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_tiff.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
Source: "{#OSGPluginsDir}\osgdb_freetype.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osganimation.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgfx.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgmanipulator.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgparticle.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgshadow.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgsim.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgterrain.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgtext.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_serializers_osgvolume.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_deprecated_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
;Source: "{#OSGPluginsDir}\osgdb_deprecated_osgparticle.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Check: not Is64BitInstallMode
; 64 bits install
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osg.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgDB.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgGA.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgParticle.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgText.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgUtil.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgViewer.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgSim.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\osg{#OSGSoNumber}-osgFX.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64InstallDir}\bin\ot{#OTSoNumber}-OpenThreads.dll"; DestDir: "{app}\bin"; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_ac.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_osga.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_3ds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_mdl.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_jpeg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_rgb.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_png.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_dds.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_txf.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_tiff.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
Source: "{#OSG64PluginsDir}\osgdb_freetype.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osganimation.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgfx.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgmanipulator.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgparticle.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgshadow.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgsim.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgterrain.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgtext.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_serializers_osgvolume.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_deprecated_osg.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
;Source: "{#OSG64PluginsDir}\osgdb_deprecated_osgparticle.dll"; DestDir: "{app}\bin\osgPlugins-{#OSGVersion}"; Flags: skipifsourcedoesntexist; Check: Is64BitInstallMode
[Dirs] [Dirs]
; Make the user installable scenery directory ; Make the user installable scenery directory
Name: "{userdocs}\FlightGear\Aircraft"; Permissions: everyone-modify; Check: not DirExists(ExpandConstant('{userdocs}\FlightGear\Aircraft')) Name: "{%USERPROFILE}\FlightGear\Downloads"; Permissions: creatorowner-modify; Check: not DirExists(ExpandConstant('{%USERPROFILE}\FlightGear\Downloads'))
Name: "{userdocs}\FlightGear\TerraSync"; Permissions: everyone-modify; Check: not DirExists(ExpandConstant('{userdocs}\FlightGear\TerraSync')) Name: "{%USERPROFILE}\FlightGear\Custom Aircraft"; Permissions: creatorowner-modify; Check: not DirExists(ExpandConstant('{%USERPROFILE}\FlightGear\Custom Aircraft'))
Name: "{userdocs}\FlightGear\Custom Scenery"; Permissions: everyone-modify; Check: not DirExists(ExpandConstant('{userdocs}\FlightGear\Custom Scenery')) Name: "{%USERPROFILE}\FlightGear\Custom Scenery"; Permissions: creatorowner-modify; Check: not DirExists(ExpandConstant('{%USERPROFILE}\FlightGear\Custom Scenery'))
[Icons] [Icons]
Name: "{userdesktop}\FlightGear {#FGVersion}"; Filename: "{app}\bin\fgfs.exe"; Parameters: "--launcher"; WorkingDir: "{app}\bin"; Tasks: desktopicon; Name: "{userdesktop}\FlightGear {#FGVersionGroup}"; Filename: "{app}\bin\fgfs.exe"; Parameters: "--launcher"; WorkingDir: "{app}\bin"; Tasks: desktopicon;
Name: "{group}\FlightGear"; Filename: "{app}\bin\fgfs.exe"; Parameters: "--launcher"; WorkingDir: "{app}\bin"; Name: "{group}\FlightGear {#FGVersionGroup}"; Filename: "{app}\bin\fgfs.exe"; Parameters: "--launcher"; WorkingDir: "{app}\bin";
Name: "{group}\FlightGear Manual"; Filename: "{app}\data\Docs\getstart.pdf" Name: "{group}\FlightGear Manual"; Filename: "{app}\data\Docs\getstart.pdf"
Name: "{group}\FlightGear Documentation"; Filename: "{app}\data\Docs\index.html" Name: "{group}\FlightGear Documentation"; Filename: "{app}\data\Docs\index.html"
Name: "{group}\Flightgear Wiki"; Filename: "http://wiki.flightgear.org" Name: "{group}\Flightgear Wiki"; Filename: "http://wiki.flightgear.org"
Name: "{group}\Tools\Uninstall FlightGear"; Filename: "{uninstallexe}" Name: "{group}\Tools\Uninstall FlightGear {#FGVersion}"; Filename: "{uninstallexe}"
Name: "{group}\Tools\fgjs"; Filename: "cmd"; Parameters: "/k fgjs.exe ""--fg-root={app}\data"""; WorkingDir: "{app}\bin" 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\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"
@ -330,8 +242,6 @@ var
procedure InitializeUninstallProgressForm(); procedure InitializeUninstallProgressForm();
begin begin
UninstallProgressForm
UninstallCheckCleanPage := TNewNotebookPage.Create(UninstallProgressForm); UninstallCheckCleanPage := TNewNotebookPage.Create(UninstallProgressForm);
UninstallCheckCleanPage.Notebook := UninstallProgressForm.InnerNotebook; UninstallCheckCleanPage.Notebook := UninstallProgressForm.InnerNotebook;
UninstallCheckCleanPage.Parent := UninstallProgressForm.InnerNotebook; UninstallCheckCleanPage.Parent := UninstallProgressForm.InnerNotebook;
@ -339,7 +249,7 @@ begin
DoCleanCheckbox := TNewCheckBox.Create(UninstallProgressForm); DoCleanCheckbox := TNewCheckBox.Create(UninstallProgressForm);
DoCleanCheckbox.Parent := UninstallCheckCleanPage; DoCleanCheckbox.Parent := UninstallCheckCleanPage;
DoCleanCheckbox.Caption := 'Remove all settings, downloaded scenery and aircraft'; DoCleanCheckbox.Caption := ExpandConstant('{cm:RemoveAllSettings}');
DoCleanCheckbox.Left := ScaleX(10); DoCleanCheckbox.Left := ScaleX(10);
DoCleanCheckbox.Top := ScaleY(10); DoCleanCheckbox.Top := ScaleY(10);
@ -354,9 +264,7 @@ begin
CleanHelp.Height := CleanHelp.AdjustHeight(); CleanHelp.Height := CleanHelp.AdjustHeight();
CleanHelp.WordWrap := True; CleanHelp.WordWrap := True;
CleanHelp.Caption := 'FlightGear stores some settings in your user folder. In addition, ' + CleanHelp.Caption := ExpandConstant('{cm:RemoveAllSettingsDescription}');
'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; UninstallProgressForm.InnerNotebook.ActivePage := UninstallCheckCleanPage;
@ -391,10 +299,10 @@ begin
if (Version.Major >= 6) then if (Version.Major >= 6) then
begin begin
{ IN and OUT rules must be specified separately, otherwise the firewall will create only the IN rule } { IN and OUT rules must be specified separately, otherwise the firewall will create only the IN rule }
AddAdvancedFirewallException('FlightGear', 'Allows FlightGear to send and receive data over the multiplayer network and to get METARs.', ExpandConstant('{app}') + '\bin\fgfs.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_IN); AddAdvancedFirewallException('FlightGear', ExpandConstant('{cm:FirewallFgException}'), ExpandConstant('{app}') + '\bin\fgfs.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_IN);
AddAdvancedFirewallException('FlightGear', 'Allows FlightGear to send and receive data over the multiplayer network and to get METARs.', ExpandConstant('{app}') + '\bin\fgfs.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_OUT); AddAdvancedFirewallException('FlightGear', ExpandConstant('{cm:FirewallFgException}'), ExpandConstant('{app}') + '\bin\fgfs.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_OUT);
AddAdvancedFirewallException('FlightGear FGCom', 'Allows FGCom to establish a connection to FlightGear and the VoIP server for voice ATC communication.', ExpandConstant('{app}') + '\bin\fgcom.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_IN); AddAdvancedFirewallException('FlightGear FGCom', ExpandConstant('{cm:FirewallFgcomException}'), ExpandConstant('{app}') + '\bin\fgcom.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_IN);
AddAdvancedFirewallException('FlightGear FGCom', 'Allows FGCom to establish a connection to FlightGear and the VoIP server for voice ATC communication.', ExpandConstant('{app}') + '\bin\fgcom.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_OUT); AddAdvancedFirewallException('FlightGear FGCom', ExpandConstant('{cm:FirewallFgcomException}'), ExpandConstant('{app}') + '\bin\fgcom.exe', NET_FW_IP_PROTOCOL_ALL, '', '', NET_FW_RULE_DIR_OUT);
end end
else if (Version.Major = 5) and (((Version.Minor = 1) and (Version.ServicePackMajor >= 2)) or ((Version.Minor = 2) and (Version.ServicePackMajor >= 1))) then else if (Version.Major = 5) and (((Version.Minor = 1) and (Version.ServicePackMajor >= 2)) or ((Version.Minor = 2) and (Version.ServicePackMajor >= 1))) then
begin begin

167
build_appimage.sh Executable file
View File

@ -0,0 +1,167 @@
#!/bin/bash
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# builds Appimage on Centos 7 using linuxdeployqt from continuous build
# expects to work in $WORKSPACE, uses the contents of dist/{bin,share,lib64} copied into an appdir
# missing qt plugins are copied in manually, as are osgPlugins
# libcurl in SIMGEAR needs a setting to find the tls certificate, and OSG needs LD_LIBRARY_PATH so it can find osgPlugins
# currently not including FGDATA, but this could be done easily once FG is updated to change Nav database checks from path to some kind of checksum
#
# issues/errors:
# can't find qt translations - missing something in my build?
#
# errors/comments to enrogue@gmail.com
#clean up any previous build
rm -rf appdir
#create basic structure
mkdir -p appdir/usr/bin
mkdir -p appdir/usr/lib
mkdir -p appdir/usr/share
mkdir -p appdir/usr/qml
mkdir -p appdir/usr/ssl
#copy everything we need in
cp dist/bin/* appdir/usr/bin
cp -d dist/lib64/* appdir/usr/lib
# OSG 3.6 uses lib, not lib64
cp -d dist/lib/* appdir/usr/lib
cp -a dist/lib/osgPlugins-3.6.5 appdir/usr/lib
# adjust the rpath on the copied plugins, so they don't
# require LD_LIBRARY_PATH to be set to load their dependencies
# correctly
patchelf --set-rpath \$ORIGIN/../ appdir/usr/lib/osgPlugins-3.6.5/*.so
cp -r dist/share appdir/usr
# FIXME : only copy the QML plugins we actually need
#cp -a /usr/lib64/qt5/qml/QtQuick* appdir/usr/qml
#cp -a /usr/lib64/qt5/qml/QtQml* appdir/usr/qml
cp /usr/lib64/libsoftokn3.* appdir/usr/lib
cp /usr/lib64/libnsspem.so appdir/usr/lib
cp /usr/lib64/libfreebl* appdir/usr/lib
cp -a /usr/lib64/liblzma* appdir/usr/lib
cp /etc/pki/tls/certs/ca-bundle.crt appdir/usr/ssl/cacert.pem
# HarfBuzz is in /lib64 on CentOS, but still copy it: see
# https://sourceforge.net/p/flightgear/codetickets/2590/
cp -a /lib64/libharfbuzz.so* appdir/usr/lib
# as we are copying over libharfbuzz we need the older libfontconfig,
# libfreetype & libpng15 as 2.11 breaks compatibility: see
# https://sourceforge.net/p/flightgear/codetickets/2651/
cp -a /usr/lib64/libfontconfig.so* appdir/usr/lib
cp -a /usr/lib64/libfreetype.so* appdir/usr/lib
cp -a /usr/lib64/libpng15.so* appdir/usr/lib
patchelf --set-rpath \$ORIGIN appdir/usr/lib/libfontconfig.so*
patchelf --set-rpath \$ORIGIN appdir/usr/lib/libfreetype.so*
patchelf --set-rpath \$ORIGIN appdir/usr/lib/libharfbuzz.so*
#modify the desktop file so that linuxdeployqt doesn't barf (version to 1.0, add semicolon to end of certain line types)
sed -i 's/^Categor.*/&;/ ; s/^Keyword.*/&;/ ; s/1\.1/1\.0/' appdir/usr/share/applications/org.flightgear.FlightGear.desktop
#generate AppRun script
cat << 'EOF' > appdir/AppRun
#!/bin/bash
HERE="$(dirname "$(readlink -f "${0}")")"
BIN_DIR="${HERE}/usr/bin"
EXEC_OPT="--exec-app"
export SIMGEAR_TLS_CERT_PATH=$HERE/usr/ssl/cacert.pem
export OSG_LIBRARY_PATH=${HERE}/usr/lib
export LD_LIBRARY_PATH=${HERE}/usr/lib
# Run launcher directly if no parameters are passed
if [[ "$#" -eq "0" ]]; then
echo "Started with no arguments; assuming --launcher"
exec "${HERE}/usr/bin/fgfs" --launcher
exit "$?"
fi
# Check for special argument "--exec-app=" and execute selected application
if [[ "$1" == ${EXEC_OPT}=* ]] || [[ "$1" == "${EXEC_OPT}" ]]; then
OPT_VAL="${1#*=}"
APP_PATH="${BIN_DIR}/${OPT_VAL}"
# Call without arguments
if [[ "$1" == "${EXEC_OPT}" ]] || [[ -z "${OPT_VAL}" ]]; then
ERROR="1"
# Make sure executable name does not contain any "/"
elif [[ "${OPT_VAL}" == */* ]]; then
echo "Error: path separator \"/\" was used in application name!"
ERROR="1"
# Check if resulting file exists and is executable
elif [[ -z "$(find "${APP_PATH}" -type f \( \( -perm -00005 -a ! -user "$(id -u)" -a ! -group "$(id -g)" \) -o \( -perm -00500 -a -user "$(id -u)" \) -o \( -perm -00050 -a -group "$(id -g)" \) \) 2>/dev/null)" ]]; then
echo "Error: \"${OPT_VAL}\" is not a valid application name or cannot be executed by current user!"
ERROR="1"
fi
# In case of error or no arguments show help
if [[ ! -z "${ERROR}" ]]; then
# Determine AppImage's filename
IMAGE_FILE_NAME="$(basename "${APPIMAGE}" 2>/dev/null)"
if [[ -z "${IMAGE_FILE_NAME}" ]]; then
IMAGE_FILE_NAME="FlightGear.AppImage"
fi
# Print help
echo "Usage: ./${IMAGE_FILE_NAME} ${EXEC_OPT}=<application>"
echo "Pass ${EXEC_OPT} as first positional argument."
echo "Additional arguments are passed to the called application."
echo "Valid values for <application> are:"
while IFS= read -r -d $'\0' bin_exe; do
echo " $(basename "${bin_exe}")"
done < <( find "${BIN_DIR}/" -maxdepth 1 -type f \( \( -perm -00005 -a ! -user "$(id -u)" -a ! -group "$(id -g)" \) -o \( -perm -00500 -a -user "$(id -u)" \) -o \( -perm -00050 -a -group "$(id -g)" \) \) -exec printf "%s\0" "{}" \; )
# We have to use these odd find conditions since "find -executable" also lists non-executables when AppImage is executed. The reason is most likely the way it is mounted.
exit 1
fi
# Execute selected application and pass remaining parameters
# "pop" the first argument
shift
exec "${APP_PATH}" "$@"
else
exec "${HERE}/usr/bin/fgfs" "$@"
fi
EOF
chmod +x appdir/AppRun
#grab continuous linuxdeployqt
wget -c https://github.com/probonopd/linuxdeployqt/releases/download/7/linuxdeployqt-7-x86_64.AppImage
#wget -c https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod +x linuxdeployqt-7-x86_64.AppImage
#set VERSION for AppImage creation
export VERSION=`cat flightgear/flightgear-version`
# Add all executable binaries as additional binaries to AppImage and use special quoted array expansion
ADDITIONAL_EXES=()
while IFS= read -r -d $'\0' bin_exe; do
ADDITIONAL_EXES+=("-executable=${bin_exe}")
done < <( find "appdir/usr/bin/" -maxdepth 1 -type f \( \( -perm -00500 -o -perm -00050 -o -perm -00005 \) -a ! -name "fgfs" \) -exec printf "%s\0" "{}" \; )
# This find statement filters for all files with at least one executability bit set
./linuxdeployqt-7-x86_64.AppImage appdir/usr/share/applications/org.flightgear.FlightGear.desktop -appimage -qmldir=flightgear/src/GUI/qml/ "${ADDITIONAL_EXES[@]}"

View File

@ -5,7 +5,7 @@ if [ "$WORKSPACE" == "" ]; then
exit 1 exit 1
fi fi
VERSION=`cat flightgear/version` VERSION=`cat flightgear/flightgear-version`
##################################################################################### #####################################################################################
# ensure fgrcc can run when linked against libSimGearCore, for example # ensure fgrcc can run when linked against libSimGearCore, for example
@ -22,44 +22,38 @@ rm -rf output/*
##################################################################################### #####################################################################################
echo "Starting on SimGear" echo "Starting on SimGear"
cd sgBuild cd sgBuild
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DENABLE_DNS:BOOL="ON" -DSIMGEAR_SHARED:BOOL="ON" ../simgear cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DENABLE_DNS:BOOL="ON" -DSIMGEAR_SHARED:BOOL="ON" -DCMAKE_BUILD_TYPE=RelWithDebInfo ../simgear
# compile # compile
make ninja
if [ $? -ne '0' ]; then if [ $? -ne '0' ]; then
echo "make simgear failed" echo "make simgear failed"
exit 1 exit 1
fi fi
make install ninja install
# build source package and copy to output # build source package and copy to output
make package_source ninja package_source
cp simgear-*.tar.bz2 ../output/. cp simgear-*.tar.bz2 ../output/.
##################################################################################### #####################################################################################
echo "Starting on FlightGear" echo "Starting on FlightGear"
cd ../fgBuild cd ../fgBuild
cmake -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DSIMGEAR_SHARED:BOOL="ON" -DENABLE_SWIFT:BOOL=ON -DFG_BUILD_TYPE=Release ../flightgear cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DSIMGEAR_SHARED:BOOL="ON" -DENABLE_SWIFT:BOOL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DFG_BUILD_TYPE=Release ../flightgear
# compile # compile
make ninja
if [ $? -ne '0' ]; then if [ $? -ne '0' ]; then
echo "make flightgear failed" echo "make flightgear failed"
exit 1 exit 1
fi fi
make install ninja install
# build source package and copy to output # build source package and copy to output
make package_source ninja package_source
cp flightgear-*.tar.bz2 ../output/. cp flightgear-*.tar.bz2 ../output/.
#####################################################################################
echo "Assembling base package"
cd $WORKSPACE
tar cjf output/FlightGear-$VERSION-data.tar.bz2 fgdata/

View File

@ -14,50 +14,25 @@ REM SET QT5SDK32=C:\Qt\5.6\msvc2015
REM SET QT5SDK64=C:\Qt\5.6\msvc2015_64 REM SET QT5SDK64=C:\Qt\5.6\msvc2015_64
REM SET IS_NIGHTLY_BUILD=1 REM SET IS_NIGHTLY_BUILD=1
SET OSG32=%WORKSPACE%\install\msvc140\OpenSceneGraph
SET OSG64=%WORKSPACE%\install\msvc140-64\OpenSceneGraph SET OSG64=%WORKSPACE%\install\msvc140-64\OpenSceneGraph
REM 32bits SET VSGEN="Visual Studio 16 2019"
md build-sg32
md build-fg32
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
cd ..\build-fg32
cmake ..\flightgear -G "Visual Studio 14" ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-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% ^
-DENABLE_SWIFT:BOOL=ON
cmake --build . --config RelWithDebInfo --target INSTALL
cd ..
REM 64 bits
md build-sg64 md build-sg64
md build-fg64 md build-fg64
cd build-sg64 cd build-sg64
cmake ..\SimGear -G "Visual Studio 14 Win64" ^ cmake ..\SimGear -G %VSGEN% -A x64 ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^ -DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^ -DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^ -DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DCMAKE_PREFIX_PATH:PATH=%OSG64% ^ -DCMAKE_PREFIX_PATH:PATH=%OSG64% ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64 -DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64
cmake --build . --config RelWithDebInfo --target INSTALL cmake --build . --config RelWithDebInfo --target INSTALL
cd ..\build-fg64 cd ..\build-fg64
cmake ..\flightgear -G "Visual Studio 14 Win64" ^ cmake ..\flightgear -G %VSGEN% -A x64 ^
-DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^ -DMSVC_3RDPARTY_ROOT=%WORKSPACE%/windows-3rd-party/msvc140 ^
-DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^ -DBOOST_ROOT=%WORKSPACE%/windows-3rd-party ^
-DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64 ^ -DCMAKE_INSTALL_PREFIX:PATH=%WORKSPACE%/install/msvc140-64 ^
@ -65,14 +40,16 @@ cmake ..\flightgear -G "Visual Studio 14 Win64" ^
-DOSG_FSTREAM_EXPORT_FIXED=1 ^ -DOSG_FSTREAM_EXPORT_FIXED=1 ^
-DFG_BUILD_TYPE=%FGBUILDTYPE% ^ -DFG_BUILD_TYPE=%FGBUILDTYPE% ^
-DENABLE_SWIFT:BOOL=ON -DENABLE_SWIFT:BOOL=ON
cmake --build . --config RelWithDebInfo --target INSTALL cmake --build . --config RelWithDebInfo --target INSTALL
cd .. cd ..
REM Qt5 deployment REM Qt5 deployment
SET QMLDIR=%WORKSPACE%/flightgear/src/GUI/qml 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 Don't copy the compiler runtime libs, since it includes potentially older UCrtbase.
%QT5SDK64%\bin\windeployqt --release --no-compiler-runtime --qmldir %QMLDIR% %WORKSPACE%/install/msvc140-64/bin/fgfs.exe
REM build setup REM build setup
ECHO Packaging root is %WORKSPACE% ECHO Packaging root is %WORKSPACE%
@ -84,24 +61,30 @@ REM ensure output dir is clean since we upload the entirety of it
rmdir /S /Q output rmdir /S /Q output
SET FGFS_PDB=src\Main\RelWithDebInfo\fgfs.pdb SET FGFS_PDB=src\Main\RelWithDebInfo\fgfs.pdb
SET SENTRY_ORG=flightgear SET SENTRY_ORG=flightgear
SET SENTRY_PROJECT=flightgear SET SENTRY_PROJECT=flightgear
REM ensure SENTRY_AUTH_TOKEN is set in the environment REM ensure SENTRY_AUTH_TOKEN is set in the environment
sentry-cli upload-dif %WORKSPACE%\build-fg32\%FGFS_PDB% sentry-cli upload-dif --include-sources %WORKSPACE%\build-fg64\%FGFS_PDB%
sentry-cli upload-dif %WORKSPACE%\build-fg64\%FGFS_PDB%
REM indirect way to get command output into an environment variable REM indirect way to get command output into an environment variable
set PATH=%OSG32%\bin;%PATH% set PATH=%OSG64%\bin;%PATH%
osgversion --so-number > %TEMP%\osg-so-number.txt osgversion --so-number > %TEMP%\osg-so-number.txt
osgversion --version-number > %TEMP%\osg-version.txt osgversion --version-number > %TEMP%\osg-version.txt
osgversion --openthreads-soversion-number > %TEMP%\openthreads-so-number.txt osgversion --openthreads-soversion-number > %TEMP%\openthreads-so-number.txt
SET /P FLIGHTGEAR_VERSION=<flightgear\version SET /P FLIGHTGEAR_VERSION=<flightgear\flightgear-version
SET /P OSG_VERSION=<%TEMP%\osg-version.txt SET /P OSG_VERSION=<%TEMP%\osg-version.txt
SET /P OSG_SO_NUMBER=<%TEMP%\osg-so-number.txt SET /P OSG_SO_NUMBER=<%TEMP%\osg-so-number.txt
SET /P OT_SO_NUMBER=<%TEMP%\openthreads-so-number.txt SET /P OT_SO_NUMBER=<%TEMP%\openthreads-so-number.txt
for /F "tokens=1,2,3 delims=." %%a in ("%FLIGHTGEAR_VERSION%") do (
set FLIGHTGEAR_VERSION_MAJOR=%%a
set FLIGHTGEAR_VERSION_MINOR=%%b
set FLIGHTGEAR_VERSION_PATCH=%%c
)
IF %IS_NIGHTLY_BUILD% EQU 1 ( IF %IS_NIGHTLY_BUILD% EQU 1 (
REM FlightGear nightly: with fgdata, output filename would be "FlightGear-x.x.x-nightly-full.exe" REM FlightGear nightly: with fgdata, output filename would be "FlightGear-x.x.x-nightly-full.exe"
CALL :writeBaseConfig CALL :writeBaseConfig
@ -121,7 +104,9 @@ IF %IS_NIGHTLY_BUILD% EQU 1 (
GOTO End GOTO End
:writeBaseConfig :writeBaseConfig
ECHO #define FGVersion "%FLIGHTGEAR_VERSION%" > InstallConfig.iss ECHO #define FGHarnessPath "x:" > InstallConfig.iss
ECHO #define FGVersion "%FLIGHTGEAR_VERSION%" >> InstallConfig.iss
ECHO #define FGVersionGroup "%FLIGHTGEAR_VERSION_MAJOR%.%FLIGHTGEAR_VERSION_MINOR%" >> InstallConfig.iss
ECHO #define OSGVersion "%OSG_VERSION%" >> InstallConfig.iss ECHO #define OSGVersion "%OSG_VERSION%" >> InstallConfig.iss
ECHO #define OSGSoNumber "%OSG_SO_NUMBER%" >> InstallConfig.iss ECHO #define OSGSoNumber "%OSG_SO_NUMBER%" >> InstallConfig.iss
ECHO #define OTSoNumber "%OT_SO_NUMBER%" >> InstallConfig.iss ECHO #define OTSoNumber "%OT_SO_NUMBER%" >> InstallConfig.iss

View File

@ -8,11 +8,11 @@ md5sums, thumbnails, and previews of these. It consists of the script:
* update-catalog.py * update-catalog.py
And its Python modules: It uses Python modules located under `python3-flightgear/flightgear/meta/`:
* catalog.py * aircraft_catalogs/catalog.py
* catalogTags.py * aircraft_catalogs/catalogTags.py
* sgprogs.py * sgprops.py
Usage Usage
@ -22,6 +22,9 @@ The script can be run directly from this directory, or the script and its
modules can be copied together and run from any location. The steps to use modules can be copied together and run from any location. The steps to use
these are: these are:
* Have something like `export PYTHONPATH="/path/to/fgmeta/python3-flightgear"`
in your shell setup or use a .pth file (see `python3-flightgear/README.md`
for more details).
* Create an output directory where the catalog and zip files will be located. * Create an output directory where the catalog and zip files will be located.
* Copy the configuration files `catalog.config.xml`, `template.xml`, and * Copy the configuration files `catalog.config.xml`, `template.xml`, and
`zip-excludes.lst` from one of the `*catalog*` example directories into the `zip-excludes.lst` from one of the `*catalog*` example directories into the

View File

@ -1,8 +1,10 @@
#!/usr/bin/python #! /usr/bin/env python3
import argparse import argparse
import os import os
import sgprops
from flightgear.meta import sgprops
def check_meta_data(aircraft_dir, set_file, includes): def check_meta_data(aircraft_dir, set_file, includes):
base_file = os.path.basename(set_file) base_file = os.path.basename(set_file)
@ -13,34 +15,35 @@ def check_meta_data(aircraft_dir, set_file, includes):
root_node = sgprops.readProps(set_path, includePaths = includes) root_node = sgprops.readProps(set_path, includePaths = includes)
if not root_node.hasChild("sim"): if not root_node.hasChild("sim"):
print "-set.xml has no <sim> node:", set_path print("-set.xml has no <sim> node:", set_path)
return return
sim_node = root_node.getChild("sim") sim_node = root_node.getChild("sim")
if not sim_node.hasChild('description'): if not sim_node.hasChild('description'):
print "-set.xml missing <description>:", set_path print("-set.xml missing <description>:", set_path)
if not sim_node.hasChild('long-description'): if not sim_node.hasChild('long-description'):
print "-set.xml missing <long-description>:", set_path print("-set.xml missing <long-description>:", set_path)
if not sim_node.hasChild('authors'): if not sim_node.hasChild('authors'):
print "-set.xml is missing structured <authors> data:", set_path print("-set.xml is missing structured <authors> data:", set_path)
if not sim_node.hasChild('tags'): if not sim_node.hasChild('tags'):
print "-set.xml does not define any tags", set_path print("-set.xml does not define any tags", set_path)
# check for non-standard tags # check for non-standard tags
if not sim_node.hasChild('thumbnail'): if not sim_node.hasChild('thumbnail'):
print "-set.xml does not define a thumbnail", set_path print("-set.xml does not define a thumbnail", set_path)
# check thumbnail size and format # check thumbnail size and format
if not sim_node.hasChild('rating'): if not sim_node.hasChild('rating'):
print "-set.xml does not define any ratings", set_path print("-set.xml does not define any ratings", set_path)
if not sim_node.hasChild('minimum-fg-version'): if not sim_node.hasChild('minimum-fg-version'):
print "-set.xml does not define a minimum FG version", set_path print("-set.xml does not define a minimum FG version", set_path)
# check all the -set.xml files in an aircraft directory. # check all the -set.xml files in an aircraft directory.
def check_aircraft_dir(d, includes): def check_aircraft_dir(d, includes):
@ -48,9 +51,10 @@ def check_aircraft_dir(d, includes):
return return
files = os.listdir(d) files = os.listdir(d)
for file in sorted(files, key=lambda s: s.lower()): for f in sorted(files, key=lambda s: s.lower()):
if file.endswith('-set.xml'): if f.endswith('-set.xml'):
check_meta_data(d, file, includes) check_meta_data(d, f, includes)
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--include", help="Include directory to validate -set.xml parsing", parser.add_argument("--include", help="Include directory to validate -set.xml parsing",
@ -60,7 +64,7 @@ args = parser.parse_args()
for d in args.dir: for d in args.dir:
if not os.path.isdir(d): if not os.path.isdir(d):
print "Skipping missing directory:", d print("Skipping missing directory:", d)
names = os.listdir(d) names = os.listdir(d)
for name in sorted(names, key=lambda s: s.lower()): for name in sorted(names, key=lambda s: s.lower()):
@ -70,4 +74,3 @@ for d in args.dir:
acftDir = os.path.join(d, name) acftDir = os.path.join(d, name)
check_aircraft_dir(acftDir, args.include) check_aircraft_dir(acftDir, args.include)

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<PropertyList> <PropertyList>
<template> <template>
<version n="0">2019.*</version> <!-- if we break trunk compat in a substantial way, consider removing these -->
<version n="1">2018.*</version> <version n="2">2020.4.*</version>
<version n="3">2021.*</version>
<id>org.flightgear.fgaddon.trunk</id> <id>org.flightgear.fgaddon.trunk</id>
<license>GPL</license> <license>GPL</license>

View File

@ -10,5 +10,12 @@
by the FlightGear project, under a free-software license. These aircraft by the FlightGear project, under a free-software license. These aircraft
are compatible with FlightGear versions from 2018.</description> are compatible with FlightGear versions from 2018.</description>
<!-- migration to new stable catalog for 2020.3 release -->
<alternate-version>
<version>2020.3.*</version>
<id>org.flightgear.fgaddon.stable_2020</id>
<url>http://mirrors.ibiblio.org/flightgear/ftp/Aircraft-2020/catalog.xml</url>
</alternate-version>
</template> </template>
</PropertyList> </PropertyList>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Template catalog - copy and modify for your site as required-->
<PropertyList>
<local-output>/home/fgaddon/output/Aircraft-2020</local-output>
<download-url n="0">http://mirrors.ibiblio.org/flightgear/ftp/Aircraft-2020/</download-url>
<download-url n="1">http://ukmirror.flightgear.org/fgaddon/Aircraft-2020/</download-url>
<download-url n="2">https://cdn.merspieler.tk/fgaddon/Aircraft-2020/</download-url>
<thumbnail-url n="0">http://mirrors.ibiblio.org/flightgear/ftp/Aircraft-2020/thumbnails</thumbnail-url>
<thumbnail-url n="1">http://ukmirror.flightgear.org/official/Aircraft-2020/thumbnails</thumbnail-url>
<thumbnail-url n="2">https://cdn.merspieler.tk/fgaddon/Aircraft-2020/thumbnails</thumbnail-url>
<!-- share zips with the trunk catalog where possible -->
<share-output>/home/fgaddon/output/Aircraft</share-output>
<share-md5-sums>/home/fgaddon/fgmeta/catalog/fgaddon-catalog-ukmirror/md5sum.xml</share-md5-sums>
<scm>
<type>svn</type>
<path>/home/fgaddon/fgaddon-release-2020.3/Aircraft</path>
<skip>NTPS</skip>
<skip>c172</skip>
<skip>tu134</skip>
</scm>
<include-dir>/home/fgaddon/fgdata-release_2020.2</include-dir>
<include-dir>/home/fgaddon/fgaddon-release-2020.3</include-dir>
<upload n="0">
<enabled type="bool">true</enabled>
<type>rsync-ssh</type>
<remote>ibiblio:/public/mirrors/flightgear/ftp/Aircraft-2020</remote>
</upload>
</PropertyList>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<template>
<version n="0">2020.3.*</version>
<id>org.flightgear.fgaddon.stable_2020</id>
<license>GPL</license>
<url>http://mirrors.ibiblio.org/flightgear/ftp/Aircraft-2020/catalog.xml</url>
<name>FlightGear aircraft distribution for 2020.x versions</name>
<description>This hangar provides aircraft officially supported and maintained
by the FlightGear project, under a free-software license. These aircraft
are compatible with FlightGear versions from 2020.</description>
</template>
</PropertyList>

View File

@ -0,0 +1,5 @@
*/.svn/*
*.xcf
*.blend
*.psd
*~

View File

@ -8,12 +8,14 @@ import os
import re import re
import shutil import shutil
import subprocess import subprocess
import time
import sgprops
import sys import sys
import catalogTags import time
import catalog
from catalog import make_aircraft_node, make_aircraft_zip, parse_config_file, parse_template_file from flightgear.meta import sgprops
from flightgear.meta.aircraft_catalogs import catalogTags
from flightgear.meta.aircraft_catalogs import catalog
from flightgear.meta.aircraft_catalogs.catalog import make_aircraft_node, \
make_aircraft_zip, parse_config_file, parse_template_file
CATALOG_VERSION = 4 CATALOG_VERSION = 4

51
catalog/update_catalogs.sh Executable file
View File

@ -0,0 +1,51 @@
#!/bin/bash
# can't rely on $HOME in cron scripts
script_home=/home/fgaddon
# we assume fgmeta is checked out to $script_home/fgmeta
# add the scripts to the path
catalog_dir=$script_home/fgmeta/catalog
local_www_dir=/var/www/uk-mirror/fgaddon
output_dir=$script_home/output
rsync_args="-avz"
# this assumes there is an 'ibiblio' entry setup in $HOME/.ssh/config with the appropriate
# credentials
ibiblio_prefix=ibiblio:/public/mirrors/flightgear/ftp/
alias python=python3
export PATH=$PATH:$catalog_dir
export PYTHONPATH=$script_home/fgmeta/python3-flightgear
echo "Generating trunk catalog"
update-catalog.py --quiet --update $catalog_dir/fgaddon-catalog-ukmirror
# at some point, we can disable updating the 2018 catalog
echo "Generating stable catalog 2018"
update-catalog.py --quiet --update $catalog_dir/stable-2018-catalog
echo "Generating stable catalog 2020"
update-catalog.py --quiet --update $catalog_dir/stable-2020-catalog
echo "Coping to WWW dir"
rsync -avz $output_dir/Aircraft-trunk $local_www_dir/
rsync -avz $output_dir/Aircraft-2018 $local_www_dir/
rsync -avz $output_dir/Aircraft-2020 $local_www_dir/
# temporarily disabled
echo "Syncing to Ibiblio"
rsync $rsync_args $output_dir/Aircraft-trunk $ibiblio_prefix
rsync $rsync_args $output_dir/Aircraft-2018 $ibiblio_prefix
rsync $rsync_args $output_dir/Aircraft-2020 $ibiblio_prefix
echo "All done"

345
dev-utils/git-date.py Executable file
View File

@ -0,0 +1,345 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# git-date.py --- Find Git commits around some date in one or more repositories.
# Copyright (c) 2021, Florent Rougon
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are
# those of the authors and should not be interpreted as representing official
# policies, either expressed or implied, of the FlightGear project.
# The idea and some Git-fu of this script are from Edward d'Auvergne:
# <https://sourceforge.net/p/flightgear/mailman/message/37004175/>.
import argparse
import locale
import os
import platform
import re
import subprocess
import sys
from collections import namedtuple, OrderedDict
PROGNAME = os.path.basename(sys.argv[0])
PROGVERSION = "0.2"
COPYRIGHT = "Copyright (c) 2021, Florent Rougon"
LICENSE_SUMMARY = """\
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. See the top of {progname}
for more details on the licensing conditions.""".format(progname=PROGNAME)
# Very simple Repository type
Repository = namedtuple('Repository', ['label', 'path'])
class CommitFinder:
def __init__(self, branch, date):
self.branch = branch
self.date = date
def findCommit(self, repo_path):
"""Return a commit ID that belongs to 'repo_path'."""
args = ["git", "rev-list", "--max-count=1",
"--before={}".format(self.date), self.branch]
p = subprocess.run(args, cwd=repo_path, capture_output=True,
check=True, encoding="utf-8")
return p.stdout.strip()
def action(self, repositories):
"""Act on one or more repositories.
'repositories' should be an OrderedDict whose keys are
repository labels and values Repository objects.
"""
for label, repo in repositories.items():
commitId = self.findCommit(repo.path)
if params.let_me_breathe: self.print("-" * 78)
if not params.checkout: # the output would be redundant
if params.only_label:
# Useful with --show-commits
# --show-commits-option='--no-patch'
# --show-commits-option='--format=oneline'
self.print("{}: ".format(label), end='')
else:
self.print("{}: {}".format(label, commitId))
if params.let_me_breathe: self.print()
if params.show_commits:
args = ["git", "-c", "pager.show=false", "show"] + \
params.show_commits_options + [commitId]
subprocess.run(args, cwd=repo.path, check=True)
if params.checkout:
args = ["git", "checkout", commitId]
self.print("{}: checking out commit {}...".format(label,
commitId))
subprocess.run(args, cwd=repo.path, check=True)
if params.let_me_breathe: self.print()
def print(self, *args, **kwargs):
"""Wrapper for print() that defaults to flushing the output stream.
This is particularly useful when stdout is fully buffered (e.g.,
when piping the output of the script through a pager). Without
this 'flush=True' setting, output from Git commands would bypass
the high-level buffering layer in sys.stdout and could come out
before the output of some *later* non-flushed print()
statements.
"""
print(*args, flush=True, **kwargs)
def parseConfigFile(cfgFile, configFileOptSpecified, recognizedParams):
namespace = argparse.Namespace()
l = {}
if configFileOptSpecified or os.path.exists(cfgFile):
# Read the configuration file (i.e., execute it)
with open(cfgFile, "r") as f:
exec(f.read(), {"OrderedDict": OrderedDict}, l)
for p in recognizedParams:
if p in l:
setattr(namespace, p, l[p])
return namespace
def processCommandLineAndConfigFile():
if platform.system() == "Windows":
defaultCfgFile = os.path.join(os.getenv("APPDATA", "C:/"), PROGNAME,
"config.py")
else:
defaultCfgFile = os.path.join(os.getenv('HOME'), ".config", PROGNAME,
"config.py")
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...] DATE [REPOSITORY...]
Find Git commits before DATE in one or more repositories.""",
description="""\
Print information about, and possibly check out the most recent commit
before DATE in each of the specified repositories. By default, commits
are searched for in the 'next' branch, however this can be changed using
the --branch option or the 'branch' variable in the configuration file.
DATE can be in any date format accepted by Git (see the examples below).
If option --repo-args-are-just-paths has been given, each REPOSITORY
argument is literally treated as a path to a repository. Otherwise, each
REPOSITORY argument that has the form LABEL=PATH defines a repository
rooted at PATH with associated LABEL (using this special syntax is not
mandatory, but allows {progname} to refer to your repositories using the
provided labels, which is more user-friendly in general).
Examples (the backslashes just introduce continuation lines):
# One output line per repository (terse)
{progname} "2021-02-28 23:12:00" SG=/path/to/SG \\
FG=/path/to/FG FGData=/path/to/FGData
# Ditto without providing the repository labels
{progname} "2021-02-28 23:12:00" /path/to/SG \\
/path/to/FG /path/to/FGData
# Run 'git show' with the specified options for each commit found.
{progname} --let-me-breathe --show-commits \\
--show-commits-option='--no-patch' \\
--show-commits-option='--format=medium' \\
'2021-02-28 23:12:00' SG=/path/to/SG \\
FG=/path/to/FG FGData=/path/to/FGData
# Run 'git checkout' for each commit found.
{progname} --checkout --let-me-breathe "2021-01-01" SG=/path/to/SG \\
FG=/path/to/FG FGData=/path/to/FGData
# For each repository, print the label, commit ID and one-line description.
{progname} --only-label --show-commits \\
--show-commits-option='--no-patch' \\
--show-commits-option='--format=oneline' \\
"2021-02-28" SG=/path/to/SG \\
FG=/path/to/FG FGData=/path/to/FGData
Note: --show-commits and --show-commits-option may be used in conjunction with
--checkout if so desired.
If $HOME/.config/{progname}/config.py exists or if the --config-file option
has been given, a configuration file is read. This file is executed by
the Python interpreter and must therefore adhere to Python 3 syntax.
Here is a sample configuration file:
------------------------------------------------------------------------------
branch = 'release/2020.3'
# checkout = True
# show_commits = True
# show_commits_options = ['--no-patch', '--format=medium']
# let_me_breathe = True
# only_label = True
# repo_args_are_just_paths = True
# collections.OrderedDict is available for use here:
repositories = OrderedDict(
SimGear = "/path/to/simgear",
FlightGear = "/path/to/flightgear",
FGData = "/path/to/fgdata")
# Same list of repositories but without user-defined labels:
# repositories = [
# "/path/to/simgear",
# "/path/to/flightgear",
# "/path/to/fgdata"]
------------------------------------------------------------------------------
Command-line options take precedence over their counterparts found in
the configuration file. On the other hand, REPOSITORY arguments *extend*
the list of repositories that may be defined in the configuration file
using the 'repositories' variable.""".format(progname=PROGNAME),
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
# This option is actually handled by configFileOptParser because we want to
# treat it before all other options.
parser.add_argument('--config-file', metavar="FILE", default=defaultCfgFile,
help="""\
load configuration from FILE (default: %(default)s)""")
parser.add_argument('-b', '--branch', default="next", help="""\
search the history of BRANCH (default: %(default)s)""")
parser.add_argument('-c', '--checkout', action='store_true', help="""\
run 'git checkout' for the commit found in each repository""")
parser.add_argument('-s', '--show-commits', action='store_true', help="""\
run 'git show' for the commit found in each repository""")
parser.add_argument('-S', '--show-commits-option', action='append',
dest='show_commits_options', help="""\
option passed to 'git show' when --show-commits is used (may be
specified multiple times, as in: --show-commits-option='--no-patch'
--show-commits-option='--format=medium')""")
parser.add_argument('--repo-args-are-just-paths',
action='store_true', help="""\
don't try to recognize and special-case the LABEL=PATH syntax for
repository arguments; treat them literally as paths and simply assign
labels 'Repo 1', 'Repo 2', etc., to the specified repositories""")
parser.add_argument('--let-me-breathe', action='store_true', help="""\
add blank lines and other separators to make the output hopefully more
readable when Git prints a lot of things""")
parser.add_argument('--only-label', action='store_true', help="""\
don't print the commit ID after the repository label (this is useful
when the Git output that comes next already contains the commit ID)""")
parser.add_argument('date', metavar="DATE", help="""\
find commits before this date (any format accepted by Git can be used)""")
parser.add_argument('cmdRepos', metavar="REPOSITORY", nargs='*',
help="""\
path to a repository to act on (actually, each REPOSITORY argument may be
of the form LABEL=PATH in order to assign a label to the repository).
There can be an arbitrary number of such arguments.""")
parser.add_argument('--help', action="help",
help="display this message and exit")
parser.add_argument('--version', action='version',
version="{name} version {version}\n{copyright}\n\n"
"{license}".format(
name=PROGNAME, version=PROGVERSION,
copyright=COPYRIGHT,
license=LICENSE_SUMMARY))
# Find which config file to read and note whether the --config-file option
# was given.
configFileOptParser = argparse.ArgumentParser(add_help=False)
configFileOptParser.add_argument('--config-file')
ns, remaining = configFileOptParser.parse_known_args()
if ns.config_file is not None:
configFileOptSpecified = True
else:
configFileOptSpecified = False
ns.config_file = defaultCfgFile
recognizedParams = ("repo_args_are_just_paths", "branch", "checkout",
"show_commits", "show_commits_options",
"let_me_breathe", "only_label", "repositories")
# Read the config file into 'params' (an argparse.Namespace object)
params = parseConfigFile(ns.config_file, configFileOptSpecified,
recognizedParams)
# Process the rest of the command-line
parser.parse_args(namespace=params)
if "repositories" not in params:
params.repositories = []
# Prepare the list of repositories based on the config file and the command
# line arguments.
params.repositories = initListOfRepositories(
params.repositories, params.cmdRepos, params.repo_args_are_just_paths)
if not params.repositories:
sys.exit(f"{PROGNAME}: no repository was specified, neither in the "
"configuration file\nnor on the command line; exiting.")
return params
# Returns an OrderedDict whose keys are repository labels and values Repository
# objects.
def initListOfRepositories(reposFromCfgFile, reposFromCmdLineArgs,
repoArgsAreJustPaths):
res = OrderedDict()
reposLeftToAdd = []
if isinstance(reposFromCfgFile, OrderedDict):
for label, path in reposFromCfgFile.items():
res[label] = Repository(label, path)
elif isinstance(reposFromCfgFile, list):
reposLeftToAdd.extend(reposFromCfgFile)
else:
sys.exit(f"{PROGNAME}: in the configuration file, 'repositories' must "
"be either an\nOrderedDict or a list.")
repoNum = len(res)
for elt in reposLeftToAdd + reposFromCmdLineArgs:
repoNum += 1
mo = re.match(r"^(?P<label>\w+)=(?P<path>.*)", elt)
if mo is None or repoArgsAreJustPaths:
label = "Repo {}".format(repoNum)
path = elt
else:
label, path = mo.group("label", "path")
res[label] = Repository(label, path)
return res
def main():
global params
locale.setlocale(locale.LC_ALL, '')
# Require Python 3.6 or later because we rely on the retained order for
# keyword arguments passed to the OrderedDict constructor.
if sys.hexversion < 0x030600F0:
sys.exit(f"{PROGNAME}: exiting because Python >= 3.6 is required.")
params = processCommandLineAndConfigFile()
commitFinder = CommitFinder(params.branch, params.date)
commitFinder.action(params.repositories)
sys.exit(0)
if __name__ == "__main__": main()

File diff suppressed because it is too large Load Diff

81
fgaddon/aircraft_updates.py Executable file
View File

@ -0,0 +1,81 @@
#!/usr/bin/env python3
#
# Script to summarize changes to fgaddon Aircraft based on svn activity.
#
# Primarily intended to provide a list of aircraft that have been significantly
# updated since the last release for the change log.
import os, sys
import os.path
import re
from collections import defaultdict
import subprocess
import math
import shlex
extensions = ["*", "xml", "nas", "ac", "png", "jpg"]
new_aircraft_list = []
updated_aircraft_list = []
if (len(sys.argv) != 4):
print("Summarize fgaddon/Aircraft changes in a given branch between two dates.")
print("")
print("Usage: " + sys.argv[0] + " <branch> <from> <to>")
print(" <branch>\tSVN branch to check (e.g trunk, branches/release-2020.3")
print(" <from> \tStart date (e.g. 2020-04-27)")
print(" <to> \tEnd date (e.g. 2020-10-11")
exit(1)
branch = sys.argv[1]
from_date = sys.argv[2]
to_date = sys.argv[3]
# Create a format string listing changes to all the file types above
tableformat = "{:<25}{:>4}"
for ext in extensions:
tableformat = tableformat + "{:>5}"
# Check an individual aircraft for changes since date and output them
def check_aircraft(aircraft):
# This command lists all the changed files since date for a given aircraft
svn_log = "svn log https://svn.code.sf.net/p/flightgear/fgaddon/" + branch + "/Aircraft/" + aircraft + " -r {" + from_date + "}:{" + to_date + "} -v -q"
process = subprocess.Popen(shlex.split(svn_log), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
stdout, stderr = process.communicate()
# Now collect some data
count = []
for ext in extensions:
regexp = " [AM] .*\." + ext + "$"
count.append(len(re.findall(regexp, stdout, flags=re.MULTILINE)))
# Find completely new aircraft.
regexp = " A /.*/Aircraft/" + aircraft + "$"
new_aircraft = ""
if (re.findall(regexp, stdout, flags=re.MULTILINE)):
new_aircraft = "NEW"
new_aircraft_list.append(aircraft)
elif (count[0] > 100) :
updated_aircraft_list.append(aircraft)
# Only output if we have more than 100 changes or it's a new aircraft
if ((count[0] > 100) or (new_aircraft == "NEW")):
print(tableformat.format(aircraft, new_aircraft, count[0], count[1], count[2], count[3], count[4], count[5]))
svn_list = "svn list https://svn.code.sf.net/p/flightgear/fgaddon/" + branch + "/Aircraft/"
process = subprocess.Popen(shlex.split(svn_list), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
stdout, stderr = process.communicate()
print(tableformat.format("Aircraft", "New?", extensions[0], extensions[1], extensions[2], extensions[3], extensions[4], extensions[5]))
aircraft_list = re.split("/\n", stdout)
for ac in aircraft_list:
check_aircraft(ac)
separator = ", "
print("\nNew Aircraft " + separator.join(new_aircraft_list))
print("Update Aircraft " + separator.join(updated_aircraft_list))
print("Total: New aircraft: " + str(len(new_aircraft_list)) + " Updated Aircraft: " + str(len(updated_aircraft_list)));

25
fgaddon/find_md5file.py Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/python
import os, sys, re, fnmatch
import hashlib, glob
def md5(fname):
hash_md5 = hashlib.md5()
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
filepath = sys.argv[1]
searchpath = sys.argv[2]
digest = md5(filepath)
print("Checking for " + digest)
wavfiles = glob.glob(searchpath + "/**/*.wav", recursive=True)
for f in wavfiles:
if (md5(f) == digest):
print(f)

2
fgdata

@ -1 +1 @@
Subproject commit dce80cbf8324134ff8e78b081842d20ac5c5d630 Subproject commit 5981eb11fcdfb528456a4fed2e4c2881080b2649

35
fix_macOS_libevent_rpath.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# libEvent uses absolute paths inside the dylibs on macOS. It's been politely
# suggested they switch to a more standard relative rpath scheme, but so far
# the maintainers are not keen, and instead recommend a post-build
# fix-up step using installnametool, so that's what this script does.
#
# see: https://github.com/libevent/libevent/issues/920
echo "Editing libEvent rpaths in: $1"
pushd $1
names="event|event_core|event_extra"
find -E . -type f -depth 1 \
-regex "\\./lib($names)"'-([0-9]+\.[0-9]+\.[0-9]+)\.dylib$' | \
while read filename; do
filename="${filename#./}" # get rid of the './'
# extract the version part using sed, yuck
version=$(printf "%s" "$filename" | sed -Ee 's@.*-([0-9]+\.[0-9]+\.[0-9]+)\.dylib$@\1@')
echo "Found: '$filename'. Version is: $version"
install_name_tool -id "@rpath/${filename}" ${filename}
# change primary and 'core' library references
# if a reference is not found, it's not touched, so we can apply these each time
install_name_tool -change "$PWD/libevent_core-$version.dylib" "@rpath/libevent_core-$version.dylib" ${filename}
install_name_tool -change "$PWD/libevent-$version.dylib" "@rpath/libevent-$version.dylib" ${filename}
done
popd
echo "Done fixing install names for libEvent"

@ -1 +1 @@
Subproject commit f007dd3ea1238ca73e76a5952d29e8ac12262738 Subproject commit cbf1f3494ab047fcf9158267e9356f27aabc8f4e

@ -1 +1 @@
Subproject commit b7ab2fa1e904119121773fe100ac4f45b3a1144b Subproject commit 4204eb38e72b286d292cfd41d2d036b086bdec46

View File

@ -26,8 +26,15 @@ cmakeCommonArgs="-G Ninja -DCMAKE_INSTALL_PREFIX:PATH=$WORKSPACE/dist -DCMAKE_BU
############################################################################### ###############################################################################
echo "Starting on SimGear" echo "Starting on SimGear"
cmakeSimGearArgs=""
if [ $SG_USE_OPENALSOFT == '1' ]; then
echo "Requested ot build with OpenAL-soft"
cmakeSimGearArgs="-DUSE_OPENALSOFT:BOOL=ON"
fi
pushd sgBuild pushd sgBuild
cmake ${cmakeCommonArgs} ../simgear cmake ${cmakeCommonArgs} ${cmakeSimGearArgs} ../simgear
# compile # compile
cmake --build . --target debug_symbols cmake --build . --target debug_symbols

View File

@ -4,7 +4,7 @@ require 'ERB'
require 'fileutils' #I know, no underscore is not ruby-like require 'fileutils' #I know, no underscore is not ruby-like
include FileUtils include FileUtils
$osgLibs = ['osgFX', 'osgParticle', 'osg', 'osgGA', 'osgText', 'osgUtil', 'osgSim', 'osgViewer', 'osgDB'] $osgLibs = ['osgFX', 'osgParticle', 'osg', 'osgGA', 'osgText', 'osgUtil', 'osgSim', 'osgViewer', 'osgDB', 'osgTerrain']
$osgPlugins = ['ac', 'osg', 'freetype', 'imageio', 'rgb', 'txf', 'mdl', '3ds', 'dds'] $osgPlugins = ['ac', 'osg', 'freetype', 'imageio', 'rgb', 'txf', 'mdl', '3ds', 'dds']
# from http://drawingablank.me/blog/ruby-boolean-typecasting.html # from http://drawingablank.me/blog/ruby-boolean-typecasting.html
@ -70,7 +70,7 @@ t = Time.new
fgCurrentYear = t.year fgCurrentYear = t.year
fgBundleIdentifier = "org.flightgear.mac" fgBundleIdentifier = "org.flightgear.mac"
fgVersion = File.read("#{srcDir}/version").strip fgVersion = File.read("#{srcDir}/flightgear-version").strip
volName="\"FlightGear #{fgVersion}\"" volName="\"FlightGear #{fgVersion}\""
if $isRelease if $isRelease
@ -110,12 +110,24 @@ end
libFile = "libOpenThreads.#{$openThreadsSoVersion}.dylib" libFile = "libOpenThreads.#{$openThreadsSoVersion}.dylib"
`cp #{$prefixDir}/lib/#{libFile} #{$frameworksDir}` `cp #{$prefixDir}/lib/#{libFile} #{$frameworksDir}`
# needed for SWIFT integration
otherLibs = ['dbus-1.3', 'event_core-2.2.1']
# DBus and libEvent needed for SWIFT
# Sentry is crash reporting
otherLibs = ['dbus-1.3', 'event_core-2.1.7','event-2.1.7', 'sentry']
otherLibs.each do |l| otherLibs.each do |l|
`cp #{$prefixDir}/lib/lib#{l}.dylib #{$frameworksDir}` `cp #{$prefixDir}/lib/lib#{l}.dylib #{$frameworksDir}`
end end
# copy OpenAL, but ensure we use the correct dest name for the @rpath value
# this could be nicer but Jenkins 'archive artefacts' doesn't want to
# archive the symlink so we only get the fully versioned .dylib
# in the artefacts
`cp #{$prefixDir}/lib/libopenal.1.*.dylib #{$frameworksDir}/libopenal.1.dylib`
# copy LibLZMA from Homebrew XZ
`cp /usr/local/lib/liblzma.dylib #{$frameworksDir}`
$osgPlugins.each do |p| $osgPlugins.each do |p|
pluginFile = "osgdb_#{p}.dylib" pluginFile = "osgdb_#{p}.dylib"
`cp #{$prefixDir}/lib/osgPlugins/#{pluginFile} #{osgPluginsDir}` `cp #{$prefixDir}/lib/osgPlugins/#{pluginFile} #{osgPluginsDir}`
@ -166,8 +178,9 @@ if !$isRelease
--file #{dmgPath}` --file #{dmgPath}`
else end
puts "Creating full image with data"
puts "Creating full image with data"
`rsync -a fgdata/ #{resourcesDir}/data` `rsync -a fgdata/ #{resourcesDir}/data`
@ -185,8 +198,6 @@ puts "Notarizing DMG #{dmgFullPath}"
--username "zakalawe@mac.com" \ --username "zakalawe@mac.com" \
--password "@keychain:FlightGearAppStoreConnectUserName" \ --password "@keychain:FlightGearAppStoreConnectUserName" \
--file #{dmgFullPath}` --file #{dmgFullPath}`
end
puts "Packaging complete" puts "Packaging complete"

View File

@ -36,6 +36,10 @@ localization files in $FG_ROOT/Translations/<language_code>):
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \ fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
merge-new-master $languages merge-new-master $languages
Note: you may omit $languages in the fg-update-translation-files command if
you want to autodetect the FlightGear-nonQt.xlf files present in
$FG_ROOT/Translations.
Updating XLIFF files to reflect changes in the default translation Updating XLIFF files to reflect changes in the default translation
------------------------------------------------------------------ ------------------------------------------------------------------
@ -45,6 +49,9 @@ modified or removed, or categories added or removed[3]):
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \ fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
merge-new-master $languages merge-new-master $languages
Note: you may omit $languages in this command if you want to autodetect the
FlightGear-nonQt.xlf files present in $FG_ROOT/Translations.
Updating XLIFF files to mark or remove obsolete translated strings Updating XLIFF files to mark or remove obsolete translated strings
------------------------------------------------------------------ ------------------------------------------------------------------
@ -53,9 +60,14 @@ To remove unused translated strings (not to be done too often in my opinion):
fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \ fg-update-translation-files --transl-dir="$FG_ROOT/Translations" \
remove-unused $languages remove-unused $languages
(you may replace 'remove-unused' with 'mark-unused' to just mark the strings Notes:
as not-to-be-translated, however 'merge-new-master' presented above already
does that) - You may omit $languages in this command if you want to autodetect the
FlightGear-nonQt.xlf files present in $FG_ROOT/Translations.
- It is possible to 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 Merging contents from an XLIFF file into another one
---------------------------------------------------- ----------------------------------------------------

View File

@ -0,0 +1,129 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2020 James Turner
#
# 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 re
import sys
import textwrap
import lxml.etree as ET
import flightgear.meta.strutils as strutils
from flightgear.meta import sgprops
PROGNAME = os.path.basename(sys.argv[0])
def processCommandLine():
params = argparse.Namespace()
parser = argparse.ArgumentParser(
usage="""\
%(prog)s [OPTION ...] FGDATA
Copy weather scenario descriptions to the default translation XML""",
description="""\
""",
formatter_class=argparse.RawDescriptionHelpFormatter,
# I want --help but not -h (it might be useful for something else)
add_help=False)
parser.add_argument("fgdata", metavar="FGDATA",
help="""\
location of FGData""")
parser.add_argument("--help", action="help",
help="display this message and exit")
return parser.parse_args(namespace=params)
def insertInitialComment(root_elt, rel_input_path):
"""Insert an XML comment before element 'root_elt'."""
s = textwrap.dedent("""\
This file was automatically generated from {input_file} using the
{progname} script from FGMeta. Modifications should be done either in
{input_file} or in that script.""".format(
progname=PROGNAME,
input_file=os.path.join("$FG_ROOT", rel_input_path)))
filled_paragraph = textwrap.fill(s, width=79)
comment_pseudo_element = ET.Comment(
" !!! Don't modify this file manually. !!!\n" + filled_paragraph + " ")
root_elt.addprevious(comment_pseudo_element)
def stringifyChildValue(node, child):
# The 'or ""' is needed because an empty node is returned as None!
return strutils.simplify(node.getValue(child, "") or "")
def makeXmlLeaf(name, text):
"""Create an XML element with text contents."""
leaf = ET.Element(name)
leaf.text = '' if text is None else str(text)
return leaf
def copyWeatherScenarios(fgdata):
rel_input_path = os.path.join("Environment", "environment.xml")
environment_node = sgprops.readProps(os.path.join(fgdata, rel_input_path))
scenarios = environment_node.getChild('weather-scenarios')
root = ET.Element("PropertyList")
insertInitialComment(root, rel_input_path)
for scen_idx, scen_node in enumerate(scenarios.getChildren("scenario")):
scenarioId = scen_node.getValue("id", None)
if (not scenarioId) or scenarioId != strutils.simplify(scenarioId):
sys.exit(
"{prg}: 'scenario' element number {i} has a missing, empty "
"or suspiciously-formatted 'id' child; aborting.".format(
prg=PROGNAME, i=scen_idx+1))
name = stringifyChildValue(scen_node, "name")
desc = stringifyChildValue(scen_node, "description")
if not (name and desc):
sys.exit(
"{prg}: scenario '{scen}' has an empty or missing name or "
"description after string simplification; aborting.".format(
prg=PROGNAME, scen=scenarioId))
root.append(makeXmlLeaf(scenarioId + "-name", name))
root.append(makeXmlLeaf(scenarioId + "-desc", desc))
default_trans_file = os.path.join(fgdata, "Translations", "default",
"weather-scenarios.xml")
doc = ET.ElementTree(root)
doc.write(default_trans_file, encoding='utf-8',
xml_declaration=True, pretty_print=True)
def main():
global params
locale.setlocale(locale.LC_ALL, '')
params = processCommandLine()
copyWeatherScenarios(params.fgdata)
sys.exit(0)
if __name__ == "__main__": main()

View File

@ -27,6 +27,7 @@ import sys
import flightgear.meta.logging import flightgear.meta.logging
import flightgear.meta.i18n as fg_i18n import flightgear.meta.i18n as fg_i18n
from flightgear.meta.i18n import XliffFormatHandler
PROGNAME = os.path.basename(sys.argv[0]) PROGNAME = os.path.basename(sys.argv[0])
@ -45,7 +46,7 @@ def processCommandLine():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
usage="""\ usage="""\
%(prog)s [OPTION ...] ACTION LANGUAGE_CODE... %(prog)s [OPTION ...] ACTION [LANGUAGE_CODE]...
Update FlightGear XLIFF localization files.""", Update FlightGear XLIFF localization files.""",
description="""\ description="""\
This program performs the following operations (actions) on FlightGear XLIFF This program performs the following operations (actions) on FlightGear XLIFF
@ -68,6 +69,13 @@ translation files (*.xlf):
In the XLIFF localization files corresponding to the specified In the XLIFF localization files corresponding to the specified
language(s), remove all translated strings that are marked as unused. language(s), remove all translated strings that are marked as unused.
If no LANGUAGE_CODE is provided as an argument, then assuming $transl_dir
represents the value passed to --transl-dir, all directories $d such that a
file named FlightGear-nonQt.xlf is found in $transl_dir/$d will be acted on as
if they had been passed as LANGUAGE_CODE arguments (actually, the directory
$transl_dir/default is not considered as a candidate; it is simply skipped).
Typically, $transl_dir is /path/to/FGData/Translations.
A translated string that is marked as unused is still present in the XLIFF 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 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 don't need to worry about it. On the other hand, when a translated string is
@ -105,7 +113,7 @@ general on the short or mid-term: they only take some space.
remove those already marked as unused from the XLIFF remove those already marked as unused from the XLIFF
files corresponding to each given LANGUAGE_CODE (i.e., files corresponding to each given LANGUAGE_CODE (i.e.,
those that are not in the default translation)""") those that are not in the default translation)""")
parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="+", parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="*",
help="""\ help="""\
codes of languages to operate on (e.g., fr, en_GB, it, codes of languages to operate on (e.g., fr, en_GB, it,
es_ES...)""") es_ES...)""")
@ -125,11 +133,19 @@ class MarkOrRemoveUnusedAction(enum.Enum):
mark, remove = range(2) mark, remove = range(2)
def langCodesToActOn():
"""Return an iterable of all language codes we were told to work on."""
if params.lang_code:
return params.lang_code
else:
return XliffFormatHandler.availableTranslations(params.transl_dir)
def markOrRemoveUnused(l10nResPoolMgr, action): def markOrRemoveUnused(l10nResPoolMgr, action):
formatHandler = fg_i18n.XliffFormatHandler() formatHandler = fg_i18n.XliffFormatHandler()
masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl
for langCode in params.lang_code: for langCode in langCodesToActOn():
xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode) xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode)
transl = formatHandler.readTranslation(xliffPath) transl = formatHandler.readTranslation(xliffPath)
@ -148,7 +164,7 @@ def mergeNewMaster(l10nResPoolMgr):
formatHandler = fg_i18n.XliffFormatHandler() formatHandler = fg_i18n.XliffFormatHandler()
masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl masterTransl = l10nResPoolMgr.readFgMasterTranslation().transl
for langCode in params.lang_code: for langCode in langCodesToActOn():
xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode) xliffPath = formatHandler.defaultFilePath(params.transl_dir, langCode)
transl = formatHandler.readTranslation(xliffPath) transl = formatHandler.readTranslation(xliffPath)
transl.mergeMasterTranslation(masterTransl, logger=logger) transl.mergeMasterTranslation(masterTransl, logger=logger)

View File

@ -7,13 +7,14 @@
import os, sys, re, fnmatch import os, sys, re, fnmatch
from subprocess import call from subprocess import call
suffix = '.dmg' suffixes = ['dmg']
release_version = "unknown" release_version = "unknown"
if sys.argv[1] == 'windows': if sys.argv[1] == 'windows':
suffix = '.exe' suffixes = ['exe']
if sys.argv[1] == 'linux': if sys.argv[1] == 'linux':
suffix = '.tar.bz2' suffixes = ['tar.bz2', 'tar.xz', 'txz', 'AppImage']
isRelease = False isRelease = False
if len(sys.argv) > 2 and sys.argv[2] == 'release': if len(sys.argv) > 2 and sys.argv[2] == 'release':
@ -22,37 +23,45 @@ if len(sys.argv) > 2 and sys.argv[2] == 'release':
if len(sys.argv) > 3: if len(sys.argv) > 3:
release_version = sys.argv[3] release_version = sys.argv[3]
allSuffix = '*' + suffix print "are we doing an RC:" + str(isRelease)
sys.stdout.flush()
print "Wildcard pattern is:" + allSuffix
pattern = r'\w+-(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)([\w-]*)' + suffix
sourceForgeUserHost = "jmturner@frs.sourceforge.net" sourceForgeUserHost = "jmturner@frs.sourceforge.net"
sftpCommandFile = "sftp-commands" sftpCommandFile = "sftp-commands"
symbolDir = "/home/jenkins/symbols" symbolDir = "/home/jenkins/symbols"
if isRelease: if isRelease:
publicRoot = "/var/www/html/builds/rc" publicRoot = "/var/www/downloads/builds/rc"
incomingDir = "/home/jenkins/incoming" incomingDir = "/home/jenkins/incoming"
sourceForgePath = "/home/frs/project/f/fl/flightgear/release-" + release_version + "/" sourceForgePath = "/home/frs/project/f/fl/flightgear/release-" + release_version + "/"
else: else:
publicRoot = "/var/www/html/builds/nightly" publicRoot = "/var/www/downloads/builds/nightly"
incomingDir = "/home/jenkins/nightly-incoming" incomingDir = "/home/jenkins/nightly-incoming"
sourceForgePath = "/home/frs/project/f/fl/flightgear/unstable/" sourceForgePath = "/home/frs/project/f/fl/flightgear/unstable/"
os.chdir(publicRoot) os.chdir(publicRoot)
def matchVersionWithSuffix(suffix, file):
pattern = r'\w+-(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)([\w-]*)\.' + suffix
m = re.match(pattern, file)
if (m is None):
return None
return (m.group('major'), m.group('minor'), m.group('patch'))
def findFileVersion(dir): def findFileVersion(dir):
for file in os.listdir(dir): for file in os.listdir(dir):
if fnmatch.fnmatch(file, allSuffix): for suffix in suffixes:
m = re.match(pattern, file) if file.endswith(suffix):
if (m is not None): v = matchVersionWithSuffix(suffix, file)
return (m.group('major'), m.group('minor'), m.group('patch')) if v:
return v
return None return None
incomingVer = findFileVersion(incomingDir) incomingVer = findFileVersion(incomingDir)
if incomingVer is None: if incomingVer is None:
print "No incoming files found matching " + allSuffix print "No incoming files found matching suffixes:" + ', '.join(suffixes)
exit() exit()
existingVer = findFileVersion('.') existingVer = findFileVersion('.')
@ -66,18 +75,40 @@ oldFiles = []
incomingFiles = [] incomingFiles = []
newFiles = [] newFiles = []
# remove all files matching a suffix in the current director
# record removed files (except symlinks) in global-var
# oldFiles, so we could also remove them from SourceForge
def removeFilesMatching(suffix):
for file in os.listdir('.'):
if not fnmatch.fnmatch(file, '*' + suffix):
continue
if not os.path.islink(file):
oldFiles.append(file)
os.remove(file)
if versionChange: if versionChange:
print "Version number changing" print "Version number changing"
for suffix in suffixes:
removeFilesMatching(suffix)
for file in os.listdir('.'): if (sys.argv[1] == 'windows'):
if fnmatch.fnmatch(file, allSuffix): removeFilesMatching('.pdb')
if not os.path.islink(file):
oldFiles.append(file)
os.remove(file)
# collecting incoming files
for file in os.listdir(incomingDir): for file in os.listdir(incomingDir):
if fnmatch.fnmatch(file, allSuffix): for suffix in suffixes:
incomingFiles.append(file) if file.endswith(suffix):
incomingFiles.append(file)
if (sys.argv[1] == 'windows') and fnmatch.fnmatch(file, "*.pdb"):
# manually copy PDBs, don't add to incoming files
srcFile = os.path.join(incomingDir, file)
os.rename(srcFile, file)
newFiles.append(file)
print "Incoming files:" + ', '.join(incomingFiles)
# copy and symlink # copy and symlink
for file in incomingFiles: for file in incomingFiles:
@ -85,19 +116,23 @@ for file in incomingFiles:
srcFile = os.path.join(incomingDir, file) srcFile = os.path.join(incomingDir, file)
outFile = file outFile = file
# insert -rc before suffix # insert -rc before file extension
#if isRelease: if isRelease:
#m = re.match(r'(\w+-\d+\.\d+\.\d+[\w-]*)' + suffix, file) m = re.match(r'(\w+-\d+\.\d+\.\d+[\w-]*)\.(.*)', file)
#outFile = m.group(1) + '-rc' + suffix outFile = m.group(1) + '-rc.' + m.group(2)
#print "RC out name is " + outFile print "RC out name is " + outFile
os.rename(srcFile, outFile) os.rename(srcFile, outFile)
newFiles.append(outFile) newFiles.append(outFile)
if not isRelease: if not isRelease:
# symlink for stable web URL # symlink for stable web URL
m = re.match(r'(\w+)-\d+\.\d+\.\d+-([\w-]+)' + suffix, file) m = re.match(r'(\w+)-\d+\.\d+\.\d+(-[\w-]+)?\.(.*)' , file)
latestName = m.group(1) + '-latest-' + m.group(2) + suffix
if m.group(2):
latestName = m.group(1) + '-latest' + m.group(2) + '.' + m.group(3)
else:
latestName = m.group(1) + '-latest.' + m.group(3)
print "Creating symlink from " + file + " to " + latestName print "Creating symlink from " + file + " to " + latestName
if os.path.exists(latestName): if os.path.exists(latestName):
@ -105,7 +140,6 @@ for file in incomingFiles:
os.remove(latestName) os.remove(latestName)
os.symlink(file, latestName) os.symlink(file, latestName)
# remove files from SF # remove files from SF
#if len(oldFiles) > 0: #if len(oldFiles) > 0:
# f = open(sftpCommandFile, 'w') # f = open(sftpCommandFile, 'w')
@ -120,14 +154,12 @@ for file in incomingFiles:
# os.remove(sftpCommandFile) # os.remove(sftpCommandFile)
# upload to SourceForge # upload to SourceForge
for file in newFiles: # for file in newFiles:
print "Uploading " + file + " to SourceForge" # print "Uploading " + file + " to SourceForge"
call(["scp", file, sourceForgeUserHost + ":" + sourceForgePath + file]) # print "Skipped until SF FRS is fixed"
# # sys.stdout.flush()
# # call(["scp", "-v", file, sourceForgeUserHost + ":" + sourceForgePath + file])
# # call(["rsync", "-e", "ssh", file, sourceForgeUserHost + ":" + sourceForgePath + file])
# # print "...Done"
# sys.stdout.flush()
if sys.argv[1] == 'windows':
print "Archiving PDB files"
for file in os.listdir(incomingDir):
if fnmatch.fnmatch(file, "*.pdb"):
srcFile = os.path.join(incomingDir, file)
outFile = os.path.join(symbolDir, file)
os.rename(srcFile, outFile)

View File

@ -0,0 +1,48 @@
Python code for FlightGear “meta” work
======================================
The `flightgear` directory contains FlightGear-specific Python 3 modules.
These modules are mostly of interest to FlightGear developers.
Telling your Python interpreter how to access the modules
---------------------------------------------------------
In order to run most of the Python scripts in FGMeta, your Python 3
installation must have the `/path/to/fgmeta/python3-flightgear` directory in
its `sys.path`. One way to do this is to use something like the following in
your shell setup:
export PYTHONPATH="/path/to/fgmeta/python3-flightgear"
This example uses Bourne-style syntax; adjust for your particular shell.
Several directories may be added this way using a colon separator on Unix, and
presumably a semicolon on Windows.
An alternative to setting `PYTHONPATH` is to add .pth files in special
directories of your Python installation(s). For instance, you can create a
file, say, `FlightGear-FGMeta.pth`, containing a single line (with no space at
the beginning):
/path/to/fgmeta/python3-flightgear
If you want the modules present in `/path/to/fgmeta/python3-flightgear` to be
accessible to a particular Python interpreter (say, a Python 3.8), simply put
the `.pth` file in `/path/to/python-install-dir/lib/python3.8/site-packages/`.
This can even be a virtual environment if you want. For the system Python
interpreters on Debian, you can put the `.pth` file in, e.g,
`/usr/local/lib/python3.8/dist-packages/`. Note that you may add more lines to
a `.pth` file in case you want to add other paths to the Python interpreter's
`sys.path`.
The scripts
-----------
Once you've done the above setup, the Python 3 scripts in FGMeta should run
fine. This concerns in particular scripts located in the following top-level
directories of FGMeta:
catalog Generation of aircraft catalogs
i18n Management of translations in FlightGear (i18n stands for
“internationalization”)

View File

@ -1,4 +1,4 @@
#!/usr/bin/python # -*- coding: utf-8 -*-
import argparse import argparse
import datetime import datetime
@ -8,11 +8,12 @@ import os
from os.path import exists, join, relpath from os.path import exists, join, relpath
from os import F_OK, access, walk from os import F_OK, access, walk
import re import re
import sgprops
import sys import sys
import catalogTags
import zipfile import zipfile
from flightgear.meta import sgprops, strutils
from . import catalogTags
CATALOG_VERSION = 4 CATALOG_VERSION = 4
quiet = False quiet = False
verbose = False verbose = False
@ -112,9 +113,13 @@ def scan_set_file(aircraft_dir, set_file, includes):
if sim_node.hasChild('minimum-fg-version'): if sim_node.hasChild('minimum-fg-version'):
variant['minimum-fg-version'] = sim_node.getValue('minimum-fg-version', None) variant['minimum-fg-version'] = sim_node.getValue('minimum-fg-version', None)
if sim_node.hasChild('localized'):
variant['localized'] = extract_localized_strings(sim_node.getChild('localized'))
#print(" %s" % variant) #print(" %s" % variant)
return variant return variant
def extract_previews(previews_node, aircraft_dir): def extract_previews(previews_node, aircraft_dir):
result = [] result = []
for node in previews_node.getChildren("preview"): for node in previews_node.getChildren("preview"):
@ -130,6 +135,7 @@ def extract_previews(previews_node, aircraft_dir):
return result return result
def extract_tags(tags_node, set_path): def extract_tags(tags_node, set_path):
result = [] result = []
for node in tags_node.getChildren("tag"): for node in tags_node.getChildren("tag"):
@ -141,6 +147,28 @@ def extract_tags(tags_node, set_path):
return result return result
def extract_localized_strings(localized_node):
result = {}
# iterate langauges below <localized>
for lang in localized_node.getChildren():
strings = {}
# iterate strings below <de> etc
for s in lang.getChildren():
# fix up the name/description confusion here
if s.name == 'description':
strings['name'] = strutils.simplify(s.value)
elif s.name == 'long-description':
strings['description'] = strutils.simplify(s.value)
else:
strings[s.name] = strutils.simplify(s.value)
if strings:
result[lang.name] = strings
return result
# scan all the -set.xml files in an aircraft directory. Returns a # scan all the -set.xml files in an aircraft directory. Returns a
# package dict and a list of variants. # package dict and a list of variants.
def scan_aircraft_dir(aircraft_dir, includes): def scan_aircraft_dir(aircraft_dir, includes):
@ -198,6 +226,7 @@ def make_xml_leaf(name, text):
leaf.text = '' leaf.text = ''
return leaf return leaf
def append_preview_nodes(node, variant, download_base, package_name): def append_preview_nodes(node, variant, download_base, package_name):
if not 'previews' in variant: if not 'previews' in variant:
return return
@ -210,6 +239,7 @@ def append_preview_nodes(node, variant, download_base, package_name):
preview_node.append( make_xml_leaf('path', preview['path']) ) preview_node.append( make_xml_leaf('path', preview['path']) )
node.append(preview_node) node.append(preview_node)
def append_tag_nodes(node, variant): def append_tag_nodes(node, variant):
if not 'tags' in variant: if not 'tags' in variant:
return return
@ -217,6 +247,7 @@ def append_tag_nodes(node, variant):
for tag in variant['tags']: for tag in variant['tags']:
node.append(make_xml_leaf('tag', tag)) node.append(make_xml_leaf('tag', tag))
def append_author_nodes(node, info): def append_author_nodes(node, info):
if 'authors' in info: if 'authors' in info:
node.append(info['authors']._createXMLElement()) node.append(info['authors']._createXMLElement())
@ -224,6 +255,22 @@ def append_author_nodes(node, info):
# traditional single author string # traditional single author string
node.append( make_xml_leaf('author', info['author']) ) node.append( make_xml_leaf('author', info['author']) )
def append_localized_strings(node, variant):
if not 'localized' in variant:
return
localized_node = ET.Element('localized')
for lang, v in variant['localized'].items():
lang_node = ET.Element(lang)
for skey, s in v.items():
lang_node.append(make_xml_leaf(skey, s))
localized_node.append(lang_node)
node.append(localized_node)
def make_aircraft_node(aircraftDirName, package, variants, downloadBase, mirrors): def make_aircraft_node(aircraftDirName, package, variants, downloadBase, mirrors):
#print("package: %s" % package) #print("package: %s" % package)
#print("variants: %s" % variants) #print("variants: %s" % variants)
@ -270,6 +317,7 @@ def make_aircraft_node(aircraftDirName, package, variants, downloadBase, mirrors
append_preview_nodes(variant_node, variant, downloadBase, aircraftDirName) append_preview_nodes(variant_node, variant, downloadBase, aircraftDirName)
append_tag_nodes(variant_node, variant) append_tag_nodes(variant_node, variant)
append_author_nodes(variant_node, variant) append_author_nodes(variant_node, variant)
append_localized_strings(variant_node, variant)
package_node.append( make_xml_leaf('dir', aircraftDirName) ) package_node.append( make_xml_leaf('dir', aircraftDirName) )
@ -289,6 +337,7 @@ def make_aircraft_node(aircraftDirName, package, variants, downloadBase, mirrors
append_preview_nodes(package_node, package, downloadBase, aircraftDirName) append_preview_nodes(package_node, package, downloadBase, aircraftDirName)
append_tag_nodes(package_node, package) append_tag_nodes(package_node, package)
append_localized_strings(package_node, package)
if 'maintainers' in package: if 'maintainers' in package:
package_node.append(package['maintainers']._createXMLElement()) package_node.append(package['maintainers']._createXMLElement())

View File

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
aircraftTypeTags = [ aircraftTypeTags = [
"aerobatic", "aerobatic",
"airship", "airship",
@ -176,7 +178,8 @@ simFeatureTags = [
"wildfire" "wildfire"
] ]
tags = aircraftTypeTags + manufacturerTags + eraTags + simFeatureTags + propulsionTags + featureTags tags = (aircraftTypeTags + manufacturerTags + eraTags + simFeatureTags +
propulsionTags + featureTags)
def isValidTag(maybeTag): def isValidTag(maybeTag):
return maybeTag in tags return maybeTag in tags

View File

@ -65,7 +65,11 @@ from .exceptions import FGPyException
dummyLogger = DummyLogger() dummyLogger = DummyLogger()
# Not including "atc", because it has no translation. Please keep this sorted. # Not including "atc", because it has no translation. Please keep this sorted.
CATEGORIES = ("menu", "options", "sys", "tips") CATEGORIES = ("menu", "options", "sys", "tips", "weather-scenarios")
# BASIC_CATEGORIES lists all categories handled by BasicL10NResourceManager.
# The corresponding master files must have a flat structure where each
# translatable string is found in a direct child of the <PropertyList> element.
BASIC_CATEGORIES = CATEGORIES
# Directory name for the default (master) translation # Directory name for the default (master) translation
DEFAULT_LANG_DIR = "default" DEFAULT_LANG_DIR = "default"
# Root of the base name for the default output files (XLIFF...) # Root of the base name for the default output files (XLIFF...)
@ -94,6 +98,7 @@ PLURAL_FORMS = {
"pt": ["singular", "plural"], "pt": ["singular", "plural"],
"ru": ["singular", "plural"], "ru": ["singular", "plural"],
"sk": ["singular", "paucal", "plural"], "sk": ["singular", "paucal", "plural"],
"tr": ["universal"],
"zh": ["universal"] # universal form "zh": ["universal"] # universal form
} }
@ -457,7 +462,7 @@ class TranslationUnit:
def _stringsKey(self): def _stringsKey(self):
"""Key used to compare the strings of two TranslationUnit instances.""" """Key used to compare the strings of two TranslationUnit instances."""
return (self.self.sourceText, self.targetTexts, self.developerComments, return (self.sourceText, self.targetTexts, self.developerComments,
self.translatorComments) self.translatorComments)
def sameStrings(self, other): def sameStrings(self, other):
@ -1001,6 +1006,33 @@ class AbstractFormatHandler(metaclass=abc.ABCMeta):
baseName = cls.defaultFileBaseName(targetLanguage) baseName = cls.defaultFileBaseName(targetLanguage)
return os.path.join(translationsDir, targetLanguage, baseName) return os.path.join(translationsDir, targetLanguage, baseName)
@classmethod
def availableTranslations(cls, translationsDir):
"""Return a list of all available translations in translationsDir.
This method expects a particular layout for translation files:
the one used in $FG_ROOT/Translations. More precisely, it looks
for all files named LANG_CODE/NAME in translationsDir, where
NAME is cls.defaultFileBaseName(LANG_CODE). The special
directory translationsDir/DEFAULT_LANG_DIR is not explored;
thus, the result cannot contain DEFAULT_LANG_DIR.
Return a list of language codes, sorted with list.sort().
"""
res = []
with os.scandir(translationsDir) as it:
for entry in it:
if (entry.name != DEFAULT_LANG_DIR and entry.is_dir() and
os.path.isfile(
os.path.join(
translationsDir, entry.name,
cls.defaultFileBaseName(entry.name)))):
res.append(entry.name)
res.sort()
return res
@abc.abstractmethod @abc.abstractmethod
def writeTranslation(self, transl, filePath): def writeTranslation(self, transl, filePath):
"""Write a Translation instance to a file.""" """Write a Translation instance to a file."""
@ -1342,14 +1374,16 @@ class XliffFormatReader:
if sourceText is not None: if sourceText is not None:
raise XliffParseError( raise XliffParseError(
"{file}: several 'source' elements inside the same " "{file}: several 'source' elements inside the same "
"'trans-unit' element".format(file=self.file)) "'trans-unit' element ({id})".format(
file=self.file, id=tid))
sourceText = self._handleSourceOrTargetNode(subnode, node.tag) sourceText = self._handleSourceOrTargetNode(subnode, node.tag)
elif subnode.tag == self.qualTagName("target"): elif subnode.tag == self.qualTagName("target"):
if targetText is not None: if targetText is not None:
raise XliffParseError( raise XliffParseError(
"{file}: several 'target' elements inside the same " "{file}: several 'target' elements inside the same "
"'trans-unit' element".format(file=self.file)) "'trans-unit' element ({id})".format(
file=self.file, id=tid))
targetText = self._handleSourceOrTargetNode(subnode, node.tag) targetText = self._handleSourceOrTargetNode(subnode, node.tag)
elif subnode.tag == self.qualTagName("note"): elif subnode.tag == self.qualTagName("note"):
@ -1361,8 +1395,8 @@ class XliffFormatReader:
if sourceText is None: if sourceText is None:
raise XliffParseError( raise XliffParseError(
"{file}: invalid 'trans-unit' element: doesn't contain any " "{file}: invalid 'trans-unit' element ({id}): doesn't contain "
"'source' element".format(file=self.file)) "any 'source' element".format(file=self.file, id=tid))
# The 'else' clause handles two cases: no <target> element, or an empty # The 'else' clause handles two cases: no <target> element, or an empty
# one. # one.
@ -1375,16 +1409,17 @@ class XliffFormatReader:
if self.insidePluralGroup: if self.insidePluralGroup:
if pluralIndex is None: if pluralIndex is None:
raise XliffParseError( raise XliffParseError(
"{file}: invalid plural group: the id attribute value for " "{file}: invalid plural group for '{id}': the id attribute "
"each form must end with the form's plural index inside " "value for each form must end with the form's plural index "
"brackets (an integer)".format(file=self.file)) "inside brackets (an integer)".format(
file=self.file, id=tid))
# Related plural forms will be merged into one TranslationUnit when # Related plural forms will be merged into one TranslationUnit when
# the containing <group restype="x-gettext-plurals"> ends. # the containing <group restype="x-gettext-plurals"> ends.
self.pluralGroupContents.append((tid, pluralIndex, translUnit)) self.pluralGroupContents.append((tid, pluralIndex, translUnit))
elif tid.cat not in self.transl: elif tid.cat not in self.transl:
raise XliffParseError( raise XliffParseError(
"{file}: unknown category: '{cat}'" "{file}: unknown category '{cat}' for '{id}'"
.format(file=self.file, cat=tid.cat)) .format(file=self.file, cat=tid.cat, id=tid))
# Source text empty + inside an x-gettext-msgctxt -> context dev comment # Source text empty + inside an x-gettext-msgctxt -> context dev comment
# (this is how Qt Linguist works) # (this is how Qt Linguist works)
elif (not sourceText and elif (not sourceText and
@ -1672,7 +1707,7 @@ registerFormatHandler("xliff", XliffFormatHandler)
# Could also be a dict # Could also be a dict
def L10nResMgrForCat(category): def L10nResMgrForCat(category):
"""Map from category/resource name to L10NResourceManager class.""" """Map from category/resource name to L10NResourceManager class."""
if category in ("menu", "options", "sys", "tips"): if category in BASIC_CATEGORIES:
return BasicL10NResourceManager return BasicL10NResourceManager
else: else:
assert False, "unexpected category: {!r}".format(category) assert False, "unexpected category: {!r}".format(category)
@ -1714,8 +1749,8 @@ class L10NResourcePoolManager:
""" """
resMgr = L10nResMgrForCat(cat) resMgr = L10nResMgrForCat(cat)
return resMgr._readFgResourceFile(xmlFilePath, None, targetTransl, cat, return resMgr.readFgResourceFile(xmlFilePath, None, targetTransl, cat,
None, logger=self.logger) None, logger=self.logger)
def readFgTranslationFile(self, xmlFilePath, masterTransl, targetTransl, def readFgTranslationFile(self, xmlFilePath, masterTransl, targetTransl,
cat, langCode): cat, langCode):
@ -1729,9 +1764,9 @@ class L10NResourcePoolManager:
""" """
resMgr = L10nResMgrForCat(cat) resMgr = L10nResMgrForCat(cat)
return resMgr._readFgResourceFile(xmlFilePath, masterTransl, return resMgr.readFgResourceFile(xmlFilePath, masterTransl,
targetTransl, cat, langCode, targetTransl, cat, langCode,
logger=self.logger) logger=self.logger)
def readFgMasterTranslation(self): def readFgMasterTranslation(self):
"""Read the FlightGear default translation. """Read the FlightGear default translation.
@ -1881,8 +1916,8 @@ class BasicL10NResourceManager(L10NResourceManagerBase):
return rootNode return rootNode
@classmethod @classmethod
def _readFgResourceFile(cls, xmlFilePath, masterTransl, targetTransl, cat, def readFgResourceFile(cls, xmlFilePath, masterTransl, targetTransl, cat,
langCode, logger=dummyLogger): langCode, logger=dummyLogger):
"""Read a FlightGear XML localization file. """Read a FlightGear XML localization file.
If 'masterTransl' and 'langCode' are None, read the default If 'masterTransl' and 'langCode' are None, read the default

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# strutils.py --- Convenient string helpers
# Copyright (C) 2020 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 re
_simplifyString_cre = re.compile(r"[ \t\n\r]+")
def simplify(s):
"""Strip and replace every internal run of whitespace with a single space.
In this case, whitespace is defined as anything matching the
regular expression '[ \t\n\r]+'.
"""
return _simplifyString_cre.sub(" ", s.strip())

View File

@ -0,0 +1,13 @@
The tests can be run this way:
cd python3-flightgear
python3 -m unittest
If you want to be more specific:
cd python3-flightgear
python3 -m unittest flightgear.meta.tests.test_catalog
python3 -m unittest flightgear.meta.tests.test_sgprops
python3 -m unittest flightgear.meta.tests.test_catalog.UpdateCatalogTests
python3 -m unittest flightgear.meta.tests.test_catalog.UpdateCatalogTests.test_scan_set
etc.

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Template catalog - copy and modify for your site as required-->
<PropertyList>
<local-output>/home/curt/Projects/FlightGear/ftp/Aircraft</local-output>
<download-url n="0">http://mirrors.ibiblio.org/flightgear/ftp/Aircraft/</download-url>
<thumbnail-url n="0">http://mirrors.ibiblio.org/flightgear/ftp/Aircraft/thumbnails</thumbnail-url>
<scm>
<type>svn</type>
<path>/home/curt/Projects/FlightGear/flightgear-fgaddon/Aircraft</path>
<skip>NTPS</skip>
<skip>c172</skip>
<skip>tu134</skip>
</scm>
<include-dir>/home/curt/Projects/FlightGear/flightgear-fgdata</include-dir>
<include-dir>/home/curt/Projects/FlightGear/flightgear-fgaddon</include-dir>
<!-- <scm>
<type>git</type>
<update type="bool">false</update>
<path>/Users/jmt/FGFS/fgdata</path>
<url>git://git.code.sf.net/p/flightgear/fgdata</url>
</scm> -->
<upload n="0">
<enabled type="bool">true</enabled>
<type>rsync-ssh</type>
<remote>fgfs:/home/fgfs/fgfs.goneabitbursar.com/official</remote>
</upload>
</PropertyList>

View File

@ -0,0 +1,516 @@
<?xml version='1.0' encoding='UTF-8'?>
<PropertyList>
<aircraft_14bis>8a4ea48a3bb83b608386f942a85100c9</aircraft_14bis>
<aircraft_21>057bfdb3c3fcfba3f8d31723a77df277</aircraft_21>
<aircraft_707>088f6c3850d9c3f8e94ced2bfc2a65db</aircraft_707>
<aircraft_717>abc393890f7ab49f32c6a2adc01b7823</aircraft_717>
<aircraft_727-230>8e93ee83c42f77db9881f9ca0f00cf8b</aircraft_727-230>
<aircraft_737-100>45fc009e9323de75e477b2548c79cb9a</aircraft_737-100>
<aircraft_737-200>3fb8820c373e78bcd52981293e2d46e8</aircraft_737-200>
<aircraft_737-300>c974d9b2e7c5feba195563433a4c5bc2</aircraft_737-300>
<aircraft_737NG>dd9ab7cb3fb27a4acfc7b634fa9ec396</aircraft_737NG>
<aircraft_747>5779ec5bdab4e9405d0db447c5a73df4</aircraft_747>
<aircraft_747-200>e3565e459436a5e4dcdd260a095c28b2</aircraft_747-200>
<aircraft_747-400>ce6c904cb23df6337ed6bdc1dcf6d68e</aircraft_747-400>
<aircraft_747-8i>92161d0ef86048c0c859241abd64ffcd</aircraft_747-8i>
<aircraft_757-200>9f5841317f4ed65fc815517c6770affd</aircraft_757-200>
<aircraft_767-300>89c1b762b8b58fee4772a94d3c9b81d8</aircraft_767-300>
<aircraft_777>693bf6470439f876edced4bd558b69a1</aircraft_777>
<aircraft_787-8>f450b755c5bad640d8c2ef7312b1a6fb</aircraft_787-8>
<aircraft_A-10>4aaca65794466d8cbf8e9ab29ef1b47b</aircraft_A-10>
<aircraft_A-26-Invader>c57f1d877e851f2164f292997508dd36</aircraft_A-26-Invader>
<aircraft_A-6E>86b52be36911fd0ee5d0b93d4b70a087</aircraft_A-6E>
<aircraft_A24-Viking>904f23999e33d323d3f7a09c1807b71a</aircraft_A24-Viking>
<aircraft_A300>3ae04898384a6531fa2edac2fcd508e9</aircraft_A300>
<aircraft_A320-family>c9ec3df5ce80cbbbec9e39a849877ceb</aircraft_A320-family>
<aircraft_A340-600>f015a7d2c8bde1224298261ae34e04c2</aircraft_A340-600>
<aircraft_A380>4951432b9d39c142e891da3209e3ad32</aircraft_A380>
<aircraft_a4>f175e90ccf2c3ae5118cf6eb1a43867e</aircraft_a4>
<aircraft_A6M2>dfb5b7f4f7233d854dca45ae4521e080</aircraft_A6M2>
<aircraft_Aermacchi-MB-339>f6757f3a4f78364c0439fd7d488c4330</aircraft_Aermacchi-MB-339>
<aircraft_Aero-Commander>021be8bd26c7aa03093e5e356d8c7ef2</aircraft_Aero-Commander>
<aircraft_Aerocar>89c4f1663f6b65ca1f70184dd8886f8b</aircraft_Aerocar>
<aircraft_Aerostar-700>9049ec76bddd80abff57a837313771d8</aircraft_Aerostar-700>
<aircraft_AG-14>4f9c9c24e662036de1cd85ed528c3d4e</aircraft_AG-14>
<aircraft_Aichi-D3A>766eb03f38f36190de94422b5481ce4b</aircraft_Aichi-D3A>
<aircraft_Aichi-M6A>14219343b589d8610da96f7a8ec16cdc</aircraft_Aichi-M6A>
<aircraft_Airco-DH2>67689844de14068b7e95e675c0da6c17</aircraft_Airco-DH2>
<aircraft_AirCrane>44fd70dc27b3d36bbde5766ac528d095</aircraft_AirCrane>
<aircraft_Airspeed-Horsa>dae16af174310b492c4412e0c77593e8</aircraft_Airspeed-Horsa>
<aircraft_airwaveXtreme150>64c7f53c6dac1b4da3813661f7455faf</aircraft_airwaveXtreme150>
<aircraft_Albatros-BII>7ccb293d5808ca0b9c48271a6398de94</aircraft_Albatros-BII>
<aircraft_Albatross>61af35090bbc722076353d1496c2d82f</aircraft_Albatross>
<aircraft_Allegro-2000>edae78dee86c3c0cb741bc4ea8793162</aircraft_Allegro-2000>
<aircraft_Alouette-II>94d5008f7bbfb65a56cff0694983d8ff</aircraft_Alouette-II>
<aircraft_Alouette-III>c267be9f90def2460ff53649c6fee2f0</aircraft_Alouette-III>
<aircraft_Alphajet>3fd4701f2363c41de0374c4703b88e83</aircraft_Alphajet>
<aircraft_AN-225>87a1ad2288b56c71559549d55b93cccd</aircraft_AN-225>
<aircraft_an2>37ccf863b017f0b773885619a671f8f7</aircraft_an2>
<aircraft_an24b>3e26ca3bf5296630eebbcd82859d5ac4</aircraft_an24b>
<aircraft_ANT-20>add26dd267eca688d4a88b672749a155</aircraft_ANT-20>
<aircraft_Antoinette>75e69854bf9d09d16cbd5147926ba7fd</aircraft_Antoinette>
<aircraft_Antonov-An-12>457f71d5be8ec8c3e42c6919b226b549</aircraft_Antonov-An-12>
<aircraft_Antonov-An-22>4a27ba4bb53f82bf2a4b325cd3405a89</aircraft_Antonov-An-22>
<aircraft_apache>b7e3e73c98d17006e984e056442c29ce</aircraft_apache>
<aircraft_AR-234>c0c500c55706fc18d93817ebc3b6e83b</aircraft_AR-234>
<aircraft_Arsenal-VG33>c883cde7942cdcfb8cd69c135c4d29f7</aircraft_Arsenal-VG33>
<aircraft_Arup-S2>70db9ed1cb09e1442e22d020a9dc3069</aircraft_Arup-S2>
<aircraft_as332>c62f9ee3f78c98a6342a6a337089fd10</aircraft_as332>
<aircraft_ASK13>264d821437a558cf71c9209f466f6103</aircraft_ASK13>
<aircraft_ASK21>27923bdc9f0f3ae3449f5d7a17744da5</aircraft_ASK21>
<aircraft_ASK21-MI>023bbe168eb0babb4a68963edffc273b</aircraft_ASK21-MI>
<aircraft_asw20>0926a8a021c4e11fa2610cbb5f6f11b3</aircraft_asw20>
<aircraft_ATC>846d8156216e434e789f5d2b7432b68f</aircraft_ATC>
<aircraft_ATC-ML>887c1bc8ab679604031f983ab6c67974</aircraft_ATC-ML>
<aircraft_ATI-Resolution>915cd6323c113bb2a8b57e4c08900f3e</aircraft_ATI-Resolution>
<aircraft_ATR-72-500>c0fe4169db9a338f5beec102f1efe301</aircraft_ATR-72-500>
<aircraft_Avro-Arrow>4b2acc554752df97194e0da1a1c8638c</aircraft_Avro-Arrow>
<aircraft_AVRO-IV-Triplane>9d3c4b4b66a7140628b79c4f142cc0f4</aircraft_AVRO-IV-Triplane>
<aircraft_Avro-Lancaster>611d6172991766b32a43d19bfb06bbb2</aircraft_Avro-Lancaster>
<aircraft_B-17>7cf94e2ee2c76783bf17c845e12e48cb</aircraft_B-17>
<aircraft_B-1B>6407f6fd1bfe031b280639d20dfe100f</aircraft_B-1B>
<aircraft_B-2>04db71541bc7099383524080a2c64012</aircraft_B-2>
<aircraft_B-24-Liberator>2bdd09054c9c92088ff297d6358a05a8</aircraft_B-24-Liberator>
<aircraft_B-25>51c6e9397e1e8fff65eb1d1671d18067</aircraft_B-25>
<aircraft_B-36D-Peacemaker>3d1883d3213d2b5f7d39ec5221cd4eb2</aircraft_B-36D-Peacemaker>
<aircraft_B-52F>d172dc57ce4e2c15f7f550a5c0c734a8</aircraft_B-52F>
<aircraft_b1900d>db7301be7b428db2070e27a5fe7ee06e</aircraft_b1900d>
<aircraft_b26>a71912ae798780eba390f9b27638b139</aircraft_b26>
<aircraft_b29>7dd2ae465a7710921d11c6c18aa0c0e7</aircraft_b29>
<aircraft_BAC-TSR2>6aaa660040bd40facf28fc68220b3cfc</aircraft_BAC-TSR2>
<aircraft_BAe-125>2a3387f97647ad875060bac1284cfcbd</aircraft_BAe-125>
<aircraft_Beagle-Pup>46a6f17c638e177421d1afc559b9d66a</aircraft_Beagle-Pup>
<aircraft_beaufighter>50af4a2d301fafb2a3e13fe96e9215be</aircraft_beaufighter>
<aircraft_beech99>6395fcaf780d6e43b4dd9f215a24e718</aircraft_beech99>
<aircraft_Beechcraft-C18S>5a133a789694642b9f3e611ddf23d3d6</aircraft_Beechcraft-C18S>
<aircraft_Beechcraft-Staggerwing>b668b91e67ef10757839da013faee44b</aircraft_Beechcraft-Staggerwing>
<aircraft_Bell-222X>635dc4a39a43814f2885d59b1dda8a9d</aircraft_Bell-222X>
<aircraft_Bell-P-39>aba5e103f315014925dff3b39bd2d648</aircraft_Bell-P-39>
<aircraft_Bell-P-59>ba6e32553464e03fe6392303a2072631</aircraft_Bell-P-59>
<aircraft_Bell-X1>3c10ccdf2775cad485bb394d5b1e56eb</aircraft_Bell-X1>
<aircraft_Bell-XFL-1>167d03a6eafc1a3780f6fdf733fc7c6e</aircraft_Bell-XFL-1>
<aircraft_Bernard-HV220>0579472d3185c8beba310aef9bf65f5d</aircraft_Bernard-HV220>
<aircraft_bf109>cb732caa641493f07c4cc564018dd481</aircraft_bf109>
<aircraft_Bleriot-125>21b170a0f9dae055d5c1d1af9946515e</aircraft_Bleriot-125>
<aircraft_Bleriot-5190>4fdcfd3aa209318c07c779e408e81df2</aircraft_Bleriot-5190>
<aircraft_Bleriot-SPAD-S.510>aef8c5f5f68349a7ae804df1d6d07e3f</aircraft_Bleriot-SPAD-S.510>
<aircraft_bleriot-XI>e499504fcba1e95e0cca9c4418bfee23</aircraft_bleriot-XI>
<aircraft_bluebird>a9af2d04a1e7bf279d135a4a06b11181</aircraft_bluebird>
<aircraft_bo105>506a63476d00ef552b8adc3260ba1fa4</aircraft_bo105>
<aircraft_bocian>9a3fd12ef60228dca05efa4ff694a882</aircraft_bocian>
<aircraft_Boeing-247>152fcac32e4bb9f7fce5b6894b6da08b</aircraft_Boeing-247>
<aircraft_Boeing-P26>97a640a4f9eddc33ac626f78adfaecb9</aircraft_Boeing-P26>
<aircraft_Boeing314>f00599943616e14682c2baea90e6173a</aircraft_Boeing314>
<aircraft_Bombardier-415>787d13e37c31fbf894d5a25091e4befc</aircraft_Bombardier-415>
<aircraft_Br-761>78d4695d2466f50d3c45e0374809b386</aircraft_Br-761>
<aircraft_Brabazon>6d0e61e40af698ea72e2978ed50e3a49</aircraft_Brabazon>
<aircraft_Breda-B.Z.308>b3e9444c45cc9c445961b726429c0c7e</aircraft_Breda-B.Z.308>
<aircraft_Breguet-XIX>a230231691ebc4df86e7d645f31a0f07</aircraft_Breguet-XIX>
<aircraft_Buccaneer>84362d957e9dae0e5abc70ba4cb9816e</aircraft_Buccaneer>
<aircraft_Bugatti>311a00f90c55c01980688c1d5504df64</aircraft_Bugatti>
<aircraft_Burnelli-CBY-3>cb75a6990af600c666b02398cf77d6d1</aircraft_Burnelli-CBY-3>
<aircraft_BV-141>a191302bdfb1faff1c6f2dd8a5494381</aircraft_BV-141>
<aircraft_BV-170>258b971dd3041a49a816a2150d7e7125</aircraft_BV-170>
<aircraft_C-160-Transall>695ce9bf3221055eecd24be01acb57e2</aircraft_C-160-Transall>
<aircraft_C-2A>3c341ded96ce7c8832738c34c5c115f8</aircraft_C-2A>
<aircraft_C130>c954a3ab900676c0cbabb1bada93754b</aircraft_C130>
<aircraft_c150>270cabd6289080468d29a807f612cb4c</aircraft_c150>
<aircraft_c172r>60bb07c7cefe930145d4b199b63842a7</aircraft_c172r>
<aircraft_c182>fd61954ffdd247b47fec0fc9074aa40b</aircraft_c182>
<aircraft_c182rg>171f7d74d45a50804c8111f5fab29543</aircraft_c182rg>
<aircraft_c310>604cd9887e8f1c9011581348feca1e3c</aircraft_c310>
<aircraft_c310u3a>80756d598e81a6a09217da9025e6284f</aircraft_c310u3a>
<aircraft_C460>b465d263b244c5860ce010371032b5d3</aircraft_C460>
<aircraft_C561>60cb1a6effe4e0023edd1bfdc109aed3</aircraft_C561>
<aircraft_C684>e2881ea7546775db6847bb3890c04a03</aircraft_C684>
<aircraft_Campini-Caproni-N1>68ec43ed98164bef020452e3758ec22f</aircraft_Campini-Caproni-N1>
<aircraft_CanberraBI8>a865e922bec69cf8a6fe1f8d53dbc71b</aircraft_CanberraBI8>
<aircraft_Cap10B>4a7cb6a6f5f6d71d5eb2da025b42d71f</aircraft_Cap10B>
<aircraft_Cap10C>bd103f5fa8a8ac980b8c4ed3a041ff6b</aircraft_Cap10C>
<aircraft_Caproni-C22J>d4eb3933d210d1a8f1deaf8b43a65960</aircraft_Caproni-C22J>
<aircraft_Caproni-Ca3>0ad6cdbf91f37b6c71f94268914d2615</aircraft_Caproni-Ca3>
<aircraft_Caproni-Stipa>d94119914089db0f7b6d43ddf20cb302</aircraft_Caproni-Stipa>
<aircraft_Caravelle>826b017ad5bc1c77c65959367f41415f</aircraft_Caravelle>
<aircraft_Carreidas>4cc78b3c9c421c382b4e197de6589535</aircraft_Carreidas>
<aircraft_Caudron-G3>6c8b251c720301a00276f91db736ee85</aircraft_Caudron-G3>
<aircraft_Caudron-G4>28ebd3b1236a53a0b15bf9c6f5cc79d6</aircraft_Caudron-G4>
<aircraft_Cessna-208-Caravan>edbaa02c5b837b9522ad8d0fd7da81e8</aircraft_Cessna-208-Caravan>
<aircraft_Cessna-421-Golden-Eagle>e16b7b135dbe3fa75539931c950116b6</aircraft_Cessna-421-Golden-Eagle>
<aircraft_Cessna337>bf3b60a808daefd7b7374f934e7b10bf</aircraft_Cessna337>
<aircraft_ch47>d46d6e08cd90412088abffe2dbd03982</aircraft_ch47>
<aircraft_ch53e>55d564ff1b335a723d144e423b9a3c10</aircraft_ch53e>
<aircraft_Cirrus-SR22>a3bbd80a8c11bea16f567eafa898db8f</aircraft_Cirrus-SR22>
<aircraft_Citation>c6f74c5596f959608e1810004abba534</aircraft_Citation>
<aircraft_Citation-Bravo>a6743e193bb01776107fec98595555e4</aircraft_Citation-Bravo>
<aircraft_CitationX>8bf718df53a6af7777f087a302641061</aircraft_CitationX>
<aircraft_Coanda-1910>b66f175629a52396dd1db3f1718d2028</aircraft_Coanda-1910>
<aircraft_colditz>77100ce686eee7ae2b5950df44a38709</aircraft_colditz>
<aircraft_Commonwealth-Ca-12>f132805e11b1c1e60908080b9b6533ad</aircraft_Commonwealth-Ca-12>
<aircraft_ComperSwift>8b227cd83d5f1f3b3b44bb7b46714349</aircraft_ComperSwift>
<aircraft_Concorde>566f1dc35ae741cdeee125111f1e0c20</aircraft_Concorde>
<aircraft_Convair-XFY-1-Pogo>633550eae44633a9b23777ffab527f1b</aircraft_Convair-XFY-1-Pogo>
<aircraft_couzinet70>d8fa7f026fc404ad20b7c7f6a11619ee</aircraft_couzinet70>
<aircraft_cri-cri>bc2267347bc48ba2377926a7a6515274</aircraft_cri-cri>
<aircraft_CRJ-200>0d500b113ae2d633e5f0bf36a1d19fd9</aircraft_CRJ-200>
<aircraft_CRJ700-family>d935f718bed4a71069122fe5214ecd2e</aircraft_CRJ700-family>
<aircraft_Curtiss-Jenny>6062a91295fbf99801e65197a71451c5</aircraft_Curtiss-Jenny>
<aircraft_Curtiss-Model-F>8ca56323ab3db01ec034f231490a7702</aircraft_Curtiss-Model-F>
<aircraft_Curtiss-P40>a0d00a78d80e4a621a1cfb55c0658fe3</aircraft_Curtiss-P40>
<aircraft_D510>8b09cc7658164d311f4e70e36f463cde</aircraft_D510>
<aircraft_D520>b967ca884dd02b37ad9c247d31bdf1c7</aircraft_D520>
<aircraft_DaSH>f9c33778a3805892fbd0e6de35e54e91</aircraft_DaSH>
<aircraft_Dassault-Mystere-IV>387fd1c59b2e5934ffcd888df39b7174</aircraft_Dassault-Mystere-IV>
<aircraft_Dauphin>bdc3b2e695db1588827d000b55bbebda</aircraft_Dauphin>
<aircraft_DC-10-30>1d37211f993a920b0806b95db0f8ea7c</aircraft_DC-10-30>
<aircraft_dc2>77f9e6a9e1647dcd012966af7df1d4be</aircraft_dc2>
<aircraft_dc6>dbfd9548db8318098daa75733171a18e</aircraft_dc6>
<aircraft_dc8-63>70cff7394ced9ab348653ad82ece3c10</aircraft_dc8-63>
<aircraft_dc8-73>26883edc54c7a02e208ce51e7b964e2e</aircraft_dc8-73>
<aircraft_Deperdussin>00fc8120294619b97ccf0e04a6145c1f</aircraft_Deperdussin>
<aircraft_DerKleineUhu>9003650773fd4933b40089d146484045</aircraft_DerKleineUhu>
<aircraft_Deuche>033799e2157ac9ffc6ac04fcdfeafe04</aircraft_Deuche>
<aircraft_DG-101G>02e81c7a33551c2581f8d5767e464518</aircraft_DG-101G>
<aircraft_DH-106>f7ac35642502a83a265f7b6594650279</aircraft_DH-106>
<aircraft_DH-88>be3e5fcef3000c72a2d85fb9eb827793</aircraft_DH-88>
<aircraft_DH-89>c745759b0e259323b20ba2e535284e7d</aircraft_DH-89>
<aircraft_DH-91>8b24f65ff28f7c66e65bcf7025582575</aircraft_DH-91>
<aircraft_dhc1>14b8d09e2debfdfd9cac81b8b67c9498</aircraft_dhc1>
<aircraft_dhc2>ff6f3470289772182d931daa00f6057f</aircraft_dhc2>
<aircraft_dhc3>a0506714e972c2a58f745c6bd7cc4fe2</aircraft_dhc3>
<aircraft_dhc4>4a792858aa65aada7cb91a47a9cf8c5d</aircraft_dhc4>
<aircraft_dhc6>81fb6e7b8ff50d43180bb758d1a56121</aircraft_dhc6>
<aircraft_dhc8>cca58285c8c814dfe923aaec656b1d9c</aircraft_dhc8>
<aircraft_Diamond-Da40>26885d6e6a849ad9dd54829baa26daee</aircraft_Diamond-Da40>
<aircraft_Diamond-Da42>e9992fcecbc66640a932c1c8fb7e71ae</aircraft_Diamond-Da42>
<aircraft_DO-228>8915f9465c563740f9f8f2cf32f1dd74</aircraft_DO-228>
<aircraft_DO-26>80757f34ea04417b6b30d65092ce50ab</aircraft_DO-26>
<aircraft_DO-335>ba8bbc9e04405db298beb9c24c6200c3</aircraft_DO-335>
<aircraft_DO-X>41356deabb2cd689393f36b96123a330</aircraft_DO-X>
<aircraft_Douglas-Dc3>b57c14a1791a20bccbf23db826a22dbb</aircraft_Douglas-Dc3>
<aircraft_Douglas-Dolphin>578771e25e6d7d81e5574d8cd1d19de0</aircraft_Douglas-Dolphin>
<aircraft_DR400>01c814d7ddeb0adcee0ed58022ebf6a8</aircraft_DR400>
<aircraft_DR400-dauphin>259cd05cfbf4b80b2cb4be07cf4bf781</aircraft_DR400-dauphin>
<aircraft_Dragonfly>012f8917ef6d7ec50d8a73c0508e5b47</aircraft_Dragonfly>
<aircraft_Dromader>9f77b8fbf981c4d761d8c497b6ef0868</aircraft_Dromader>
<aircraft_Dunne-D.5>48795402cda50957be7b7504b4d82389</aircraft_Dunne-D.5>
<aircraft_E-2C>d015100dfb5381135d221f41b293584d</aircraft_E-2C>
<aircraft_E3B>894c16ccfa5aed2778c7be4873947b69</aircraft_E3B>
<aircraft_eastbourne_mono>a99c8114ca48074fea2c675a8e6908e0</aircraft_eastbourne_mono>
<aircraft_ec130>684d979f81bf15b2adf47b52d6ca21f7</aircraft_ec130>
<aircraft_ec135>39631381049db9e54655c499f91bfb31</aircraft_ec135>
<aircraft_Embraer-ERJ-145>ef5ed515fe8f93876137bb6b27f3b158</aircraft_Embraer-ERJ-145>
<aircraft_ercoupe>bdaa474d4be6e51b21266ce0c8782c2c</aircraft_ercoupe>
<aircraft_Etrich-Taube>f6ba735798172b43abf417c80c1c4db4</aircraft_Etrich-Taube>
<aircraft_eurofighter>0f915d06528b1cc2dcc16f7be3b9ab37</aircraft_eurofighter>
<aircraft_extra500>72a8b154cda42a2ec507b6a4c604afcb</aircraft_extra500>
<aircraft_F-106-dart>84bfa325c11d56920062e8516bfc146e</aircraft_F-106-dart>
<aircraft_F-117>ba904d06c2ddb28a7fd3f95ac344de7a</aircraft_F-117>
<aircraft_f-14b>3c0963e6203c4a6315155012bbbb8096</aircraft_f-14b>
<aircraft_F-15>43f556905826c6ad5c80af409eb8a76c</aircraft_F-15>
<aircraft_F-35B>e1875c6efdc7ffe1160d8e64ac5f5fd7</aircraft_F-35B>
<aircraft_F-86>ea67ec6bb6c981dbbd391003f997c6ef</aircraft_F-86>
<aircraft_F-8E-Crusader>41b4502a287018e27402925094324209</aircraft_F-8E-Crusader>
<aircraft_f16>25805162fbd9d4d00e09c814f0beef9b</aircraft_f16>
<aircraft_f18>45264d8293d22533f56f571283940754</aircraft_f18>
<aircraft_F4U>fb47e4425240141a45818dcdc8060a4b</aircraft_F4U>
<aircraft_F6F-Hellcat>b4fcbc6e73565001d25f3cd64fb85a77</aircraft_F6F-Hellcat>
<aircraft_F7F-Tigercat>0ea6ad997b8595f97530d9aed5529ec9</aircraft_F7F-Tigercat>
<aircraft_F80C>9a7c5ac1aabe992abf14fd4b53c1712c</aircraft_F80C>
<aircraft_F9F-Panther>305fc09e91c52fefd2b67d6925baff38</aircraft_F9F-Panther>
<aircraft_fa223>3746de4faf66266399a9273321088ce2</aircraft_fa223>
<aircraft_Fairchild-C119>ec397cdc0f61d78ecc28d2cc564becd6</aircraft_Fairchild-C119>
<aircraft_Fairchild-Metroliner>3248a3f496cc146fcd95c61ec2538ae7</aircraft_Fairchild-Metroliner>
<aircraft_Fairey-Gannet>96e43cd67c0c8b9fd6e158a3ee46fbdc</aircraft_Fairey-Gannet>
<aircraft_Falcon-50>6d78633d200d8f945be6400027116539</aircraft_Falcon-50>
<aircraft_Farman-III>3e0a4af617e2064e78cee25e1d8af653</aircraft_Farman-III>
<aircraft_Farman-IV>42f45908ac131a855f66e63c09279562</aircraft_Farman-IV>
<aircraft_Fiat-G55>15f03458e112d4d7d3ff674dc20286c2</aircraft_Fiat-G55>
<aircraft_Fiat-G91>a3854718af2cf6c4c0512a166e283b4c</aircraft_Fiat-G91>
<aircraft_FK9MK2>24144321fdadaf71e81f8b014ad0e16b</aircraft_FK9MK2>
<aircraft_fkdr1>2294512dc1cdb63a8b90a21ba48875c7</aircraft_fkdr1>
<aircraft_flash2a>c56ee7fbdb10b1ba979d019cc26972cf</aircraft_flash2a>
<aircraft_Focke-Wulf-F19-ente>8bd5f800b24dbfc37f59fe368a748af1</aircraft_Focke-Wulf-F19-ente>
<aircraft_Focke-Wulf-Ta.154>f926af126c01eabd3ceb0398b178519a</aircraft_Focke-Wulf-Ta.154>
<aircraft_Fokker-Eindecker-EIII>29cd9e7ea06489595979f3df518813dd</aircraft_Fokker-Eindecker-EIII>
<aircraft_Fokker-G1>ea6025e2b6cdffc86764c5ee5a949c9a</aircraft_Fokker-G1>
<aircraft_Fokker-S-11>c3f68417e01ab653e66131bd446f8940</aircraft_Fokker-S-11>
<aircraft_Fokker-Spin>2fc955ad2ecb4ba0a7899097e7e4b226</aircraft_Fokker-Spin>
<aircraft_fokker100>83874804ebae4b77f6ac92f55c19ba91</aircraft_fokker100>
<aircraft_fokker50>da5fc6e9761203e6dd26dc3f01a2fe68</aircraft_fokker50>
<aircraft_followme>6b17d6d7bc78b5424420d47c0d737fa9</aircraft_followme>
<aircraft_Ford-Trimotor>83743f288a09c89716ac2a2e212b11bc</aircraft_Ford-Trimotor>
<aircraft_Fouga-Magister>866329f60e90f3404a6bace54e733b73</aircraft_Fouga-Magister>
<aircraft_fw190>449953e8d06e61e78e94e520d8fbc3e3</aircraft_fw190>
<aircraft_Fw200>5179bd127ee44112ec06887e322725aa</aircraft_Fw200>
<aircraft_Fw61>049759aaa0c615f71b0e1e2d683cb3ba</aircraft_Fw61>
<aircraft_G-164>977f70220ecee03ef7367b940956122a</aircraft_G-164>
<aircraft_Gee-Bee>bf993f8a5499538d2b5f5f5ec0c7574d</aircraft_Gee-Bee>
<aircraft_Gloster-Gladiator>65223229f5f8adc17c534412fb1b2bc8</aircraft_Gloster-Gladiator>
<aircraft_Gloster-Meteor>9905dc7569bc1e9cf750e47cc138dbeb</aircraft_Gloster-Meteor>
<aircraft_Gloster-Whittle>ef530cb8d0f3b53b83d993f4284bc4c3</aircraft_Gloster-Whittle>
<aircraft_Gotha-G-V>d18ed659fb34df8e078b36d0156de731</aircraft_Gotha-G-V>
<aircraft_Grob-Astir>57ada6ce17e8dda569e49ef29a517b90</aircraft_Grob-Astir>
<aircraft_Grob-G109>65c28732f4909889ca9739953c7b2032</aircraft_Grob-G109>
<aircraft_Grob-G115>82ca3e94ee5a1ee711fbc73e7ab99645</aircraft_Grob-G115>
<aircraft_Grob-Gf200>b80921cb1ec91813ba6912abf8d3d73c</aircraft_Grob-Gf200>
<aircraft_Grumman-American-AA1>40f6523b7cc0aff71281820d54bdaa0f</aircraft_Grumman-American-AA1>
<aircraft_H-21C-Shawnee>515e08d2a12b2cc1891f23e086aa5933</aircraft_H-21C-Shawnee>
<aircraft_H1-Racer>d8250d2d9f842108ffed965ced81ab64</aircraft_H1-Racer>
<aircraft_H4-Hercules>34ea914ec8c9f7c85ba3c243c6d0f981</aircraft_H4-Hercules>
<aircraft_Handley-Page-Halifax>837d0bc1db372b8d18e251fb63aa13ea</aircraft_Handley-Page-Halifax>
<aircraft_Hansajet>98a417480a3126432d9214fe0efb83c9</aircraft_Hansajet>
<aircraft_harrier>568eeccd7ffc3b08937fdf2da81a972a</aircraft_harrier>
<aircraft_Harrier-GR1>8f90009d9f8c66ba0dafc1c05ff2c685</aircraft_Harrier-GR1>
<aircraft_Harrier-GR3>b3d6038ff416a64372b663e9f3ccc137</aircraft_Harrier-GR3>
<aircraft_Hawker-Siddeley-Nimrod>e78cd169d9423dc9a9126d51fbeeb91e</aircraft_Hawker-Siddeley-Nimrod>
<aircraft_He-111>febb50152f339e23040815432e8fd6d4</aircraft_He-111>
<aircraft_He162>a27b2dd3efe6a362d135d55eca70d134</aircraft_He162>
<aircraft_Heinkel-He-111>941ab65d0ee6a8c0578e87b8d881ffc0</aircraft_Heinkel-He-111>
<aircraft_Heinkel-He-177>3bc698cc3b8937609e715c12fb135ca0</aircraft_Heinkel-He-177>
<aircraft_Heinkel-He-178>8a646c02ac858485f683301e5d98adb5</aircraft_Heinkel-He-178>
<aircraft_Heinkel-He-280>f4656701178b9d1eea30aa73b6a96ea2</aircraft_Heinkel-He-280>
<aircraft_Heston-Type5>11ef72971dce2d4b47f9899fabc4e591</aircraft_Heston-Type5>
<aircraft_HM-14>aa1c16c7731e99ebc6cd536ce26daa14</aircraft_HM-14>
<aircraft_Hornet>5dacabf98fe85149246cd5fc9bae6c39</aircraft_Hornet>
<aircraft_Horsa>1ddf68bca0c4a97d263a2d1718f87d2e</aircraft_Horsa>
<aircraft_Horten-Ho-IX>e8e04eb1d9bd25e270944775d8cb4100</aircraft_Horten-Ho-IX>
<aircraft_HS-P-75>90f738b3a6362f787e2170cb3d7317f0</aircraft_HS-P-75>
<aircraft_Hughes-XF11>bcf549f662ba17ac5896ef38b824f13e</aircraft_Hughes-XF11>
<aircraft_Hunter>608118d1e8019c92a22c275b8ce02c4a</aircraft_Hunter>
<aircraft_HUP-Retriever>5a2683f3d5a170495dc0ed3ed8cfa3f2</aircraft_HUP-Retriever>
<aircraft_Hurricane>0f64845ba2b2a4bc6a5f5637d261b93b</aircraft_Hurricane>
<aircraft_Icaro_MRX13>5f873b418694a01d049664ae58ad69a8</aircraft_Icaro_MRX13>
<aircraft_IL-2>cdc9eeae48d8760204735cf3dfdfbec9</aircraft_IL-2>
<aircraft_j22>14d705864d455ec73ca9c373f6d61d58</aircraft_j22>
<aircraft_J3Cub>f978f4a979edc6b3ac3c6b0cbd631c83</aircraft_J3Cub>
<aircraft_j7w>b777fc0d1a2c85ce6c0a03dfd90df48b</aircraft_j7w>
<aircraft_JA37>ef141db8c2469b1421c8e74f018ee8a4</aircraft_JA37>
<aircraft_Jaguar>7a0a5d5f93e34dd40fcdce3f06848908</aircraft_Jaguar>
<aircraft_JAS39-Gripen>ed3685660909e7e831d7711a2cc7b7b0</aircraft_JAS39-Gripen>
<aircraft_jeep>59341e0675583a826c34c625ba277345</aircraft_jeep>
<aircraft_jetman>67a0cbf1e934dd6552cf3f231ed65964</aircraft_jetman>
<aircraft_Jodel-D140>0cfed1923e5d2b849760df5ced30a175</aircraft_Jodel-D140>
<aircraft_JT-5B>0650d1a62cce431fa07e64bf8845a904</aircraft_JT-5B>
<aircraft_Ju-87>91a6f9e779d641b451efa777b6f81e81</aircraft_Ju-87>
<aircraft_Ju-88>ebdd6f04edccd2205bcaed1e845b567d</aircraft_Ju-88>
<aircraft_ju52>ee7f03a89cabb1370183f8a88dad1e9d</aircraft_ju52>
<aircraft_Junkers-F13>f88670ae7d834818ba14d71a7e0036e3</aircraft_Junkers-F13>
<aircraft_Junkers-G.38ce>7ad891738873394a7626882fd86e2031</aircraft_Junkers-G.38ce>
<aircraft_Junkers-Ju-390>be9047b6412830adcf9a7d68cb4574d1</aircraft_Junkers-Ju-390>
<aircraft_Junkers-W34>b5e96c226c4a2277b34dee97efc1d960</aircraft_Junkers-W34>
<aircraft_K-7>cb160921e2c703bbbdafcb51d49c266f</aircraft_K-7>
<aircraft_K5Y1>f72439b0db6a44fde139cb7651c28207</aircraft_K5Y1>
<aircraft_Ka-50>96aae67efd76fb6bfce1a97b1fbdbefd</aircraft_Ka-50>
<aircraft_Katana>151fbc5f85a7acd78039d2f074901028</aircraft_Katana>
<aircraft_Kawasaki-Ki-61-Hien>4ab8429c7200f96c144439fe50cda12d</aircraft_Kawasaki-Ki-61-Hien>
<aircraft_KC135>28519bdf05d7b1c5601ebfe9b7d95c0d</aircraft_KC135>
<aircraft_Ki-84>fbee5f8f188262cf1e09c168dd1014db</aircraft_Ki-84>
<aircraft_KM>3031820f648fe2fb15f8c9d64c104387</aircraft_KM>
<aircraft_kodiak>947daecf702214b7708c8d7df872366b</aircraft_kodiak>
<aircraft_L-1011-500>14670bbba47068cc5914c399c51a20e3</aircraft_L-1011-500>
<aircraft_l39>1d42f9adf23bf70ef1f9ba1695b9f794</aircraft_l39>
<aircraft_La-5>75204b0421e9835bf3ac3d2a0d198163</aircraft_La-5>
<aircraft_Lancair-235>6fbd208db0830b462fe2d105d1924f1e</aircraft_Lancair-235>
<aircraft_LATE-29>5ad79d5b9a17f3ac79b71722547fb6ff</aircraft_LATE-29>
<aircraft_Late-631>421b4ec83fe86c82e0bb952d3ee08780</aircraft_Late-631>
<aircraft_Leduc-022>2d3c15a8151e86b497900f6873b1875b</aircraft_Leduc-022>
<aircraft_Lightning>b80a9a8c89b05c4fa22a314ea56b32ab</aircraft_Lightning>
<aircraft_Lionceau>93a573bcf722ce69de872674b3f9dd27</aircraft_Lionceau>
<aircraft_Lockheed-Martin-FA-22A-Raptor>97c2da3770e378b72637b09c0475156f</aircraft_Lockheed-Martin-FA-22A-Raptor>
<aircraft_Lockheed-NF104>572acc2315b077411699eba35c0655d1</aircraft_Lockheed-NF104>
<aircraft_Lockheed-NF104A>41347e33250b355077aba64c671a44ce</aircraft_Lockheed-NF104A>
<aircraft_Lockheed-P38>53cd0af0a81de17378a7d3201c31dbb9</aircraft_Lockheed-P38>
<aircraft_Lockheed-SR71>99485aa18c25c0e6537334d63ccfe2c6</aircraft_Lockheed-SR71>
<aircraft_Lockheed-U-2S>b00db640f9f0f490b0bfa7d6d8b40163</aircraft_Lockheed-U-2S>
<aircraft_Lockheed-Vega>04e530018ec557294dd90128fc0c4a56</aircraft_Lockheed-Vega>
<aircraft_Lockheed1049>99539707fa1c283b6513be48996d8d14</aircraft_Lockheed1049>
<aircraft_Lockheed1049h>8da4141b5716e4321d1d5dcf3cfd30e6</aircraft_Lockheed1049h>
<aircraft_Long-EZ>6e5a8b2abc701632f9b9ab7a839eee4d</aircraft_Long-EZ>
<aircraft_Lynx-WG13>9add8ac0325547a52fa53e03b06d23b9</aircraft_Lynx-WG13>
<aircraft_M-XE>1978498650f9f5ae335cfd702a6d16f6</aircraft_M-XE>
<aircraft_Macchi-Castoldi-MC72>6952026a71d24cf0b11baca0320ab087</aircraft_Macchi-Castoldi-MC72>
<aircraft_Macchi-M33>90dc0d1bce4c19822312f51be82e9c98</aircraft_Macchi-M33>
<aircraft_marchetti>b6959644da3e1acbdd2f63af0cc529f0</aircraft_marchetti>
<aircraft_Martin-Baker-MB5>5c21bdb968a38b57b911aa998b9db99d</aircraft_Martin-Baker-MB5>
<aircraft_MB326>1a61bc6d32a3ed512b51535c46dc6991</aircraft_MB326>
<aircraft_MD-312-Flamant>be65efca7b7d7fc246c373e391996978</aircraft_MD-312-Flamant>
<aircraft_MD11>e772e7fae851948c6f6b19c0191821aa</aircraft_MD11>
<aircraft_ME-209-V1>3de79c61240e8e04a24d95c707a61a2b</aircraft_ME-209-V1>
<aircraft_ME-262>9960374b772e64e5ad75e0d3b6e12f08</aircraft_ME-262>
<aircraft_ME-262HGIII>3dfa621d920cecce3585b0f1ccb6be72</aircraft_ME-262HGIII>
<aircraft_me163>687309052c27966bd4d3bbd023237c17</aircraft_me163>
<aircraft_me323>0d615e9e715d3d4e150e836fbf43f426</aircraft_me323>
<aircraft_Messerschmitt-BF110>39b9d8b0a4aafa4e1b25992520deb011</aircraft_Messerschmitt-BF110>
<aircraft_Messerschmitt-Libelle>ed7ad8c54b6c2d9d1727e85a1a198a31</aircraft_Messerschmitt-Libelle>
<aircraft_Messerschmitt-P1101>3b989b232dd121eff6b0b230e9e85f6c</aircraft_Messerschmitt-P1101>
<aircraft_MFI-9>a566bad5dc6de5bc8d782c4f292e34ed</aircraft_MFI-9>
<aircraft_MiG-15>9bb9d2c8983b99f4f74e063f3d1e3479</aircraft_MiG-15>
<aircraft_MiG-21bis>d749c64a1fa96fbb0f13fc3d41b646e9</aircraft_MiG-21bis>
<aircraft_Mig-29>c6b9271b94abdf0770612a5cf4555f91</aircraft_Mig-29>
<aircraft_Mil-Mi-12>e1d83cafee3b3cecfdc3e473913df264</aircraft_Mil-Mi-12>
<aircraft_Mil-Mi-24>9fe6b04de733a20290141310f02abdcf</aircraft_Mil-Mi-24>
<aircraft_Mirage-2000>7bf582dfc110cfe38d616b1cdeed91ee</aircraft_Mirage-2000>
<aircraft_mirage2000>faa0e38bdadaadb61fa28e968f8a2122</aircraft_mirage2000>
<aircraft_Mirage_F1>dc188baadc7e6b3033845cfd48a14163</aircraft_Mirage_F1>
<aircraft_MirageIII>9f814e7ec8180ca71bbaf721d9337e70</aircraft_MirageIII>
<aircraft_MirageIV>a969aedf03beddd8ee89367d6179e1a4</aircraft_MirageIV>
<aircraft_mosquito>15eac7459f9aeafabdce72df42a4ba69</aircraft_mosquito>
<aircraft_MPCarrier>280758b9c9b1ec90f2010f1b1ab06ba7</aircraft_MPCarrier>
<aircraft_MRJ>ad879791f1e9d0e2d719d6a4518bbe2c</aircraft_MRJ>
<aircraft_MS-406>4507e58972e6bc69ba4f46ea3db455ec</aircraft_MS-406>
<aircraft_Nakajima-B5N>02e681d40a2427610dd55c643e89b01d</aircraft_Nakajima-B5N>
<aircraft_Nieuport-11>701b0401fb152e87a40c8b5babe87798</aircraft_Nieuport-11>
<aircraft_Noratlas>b177adbf225feca2f7d39f80d5acc352</aircraft_Noratlas>
<aircraft_Nord-1405-Gerfaut-II>a862bcf397791708ef2e0441282b2b69</aircraft_Nord-1405-Gerfaut-II>
<aircraft_Nord-2502>c6f4dc65ba8177e50ef5742b3ecb52b7</aircraft_Nord-2502>
<aircraft_Nordstern>6df28cb4a7d5e8907391c3ed8e70b6e0</aircraft_Nordstern>
<aircraft_North-American-T28D-Trojan>5fee1165f23a11eeca4d24d766117377</aircraft_North-American-T28D-Trojan>
<aircraft_North-American-T6-Texan>7ee82c752779d1c51f7b92660006aad2</aircraft_North-American-T6-Texan>
<aircraft_Northrop-P61>23a394d7e36aa653bff9b32fc9548250</aircraft_Northrop-P61>
<aircraft_Northrop-xb35>e4ec374be03638c10a88f351e8f09bad</aircraft_Northrop-xb35>
<aircraft_ogel>26e51eabb21a9a71f1b5a685e3061843</aircraft_ogel>
<aircraft_OH-1>49259a0e7725bb2c6809e1aae15e8fac</aircraft_OH-1>
<aircraft_OH-58D>40801a1693b0b8bd33178d4a5bf67765</aircraft_OH-58D>
<aircraft_ornithopter>7b0c70f7b8de3e1a5c19d32c36fa7d00</aircraft_ornithopter>
<aircraft_OV10>74faff4f12efb353ccc61689fe96c46c</aircraft_OV10>
<aircraft_P-38-Lightning>43c98dfe30fecc4c2448dc51750154ee</aircraft_P-38-Lightning>
<aircraft_P130UL>ea0a540d06226687e3409c1226a1cc1d</aircraft_P130UL>
<aircraft_P180>ab8760c0219835fe97dcbbf698b39fa4</aircraft_P180>
<aircraft_P47>cc9b6238b260d924338d2c4ee2dafc95</aircraft_P47>
<aircraft_p51d>7caa4abbdb5dba23edbdc02cf2693909</aircraft_p51d>
<aircraft_pa22>da2990b33cef4afe7d629530b274632a</aircraft_pa22>
<aircraft_pa24-250>65a95dd87096e2377dff6fe917befb8a</aircraft_pa24-250>
<aircraft_pa28-161>02f4a01e218da00e8969d4ae52c84193</aircraft_pa28-161>
<aircraft_PaperAirplane>2b7fbfc1efdf6ab2663e8b3d7cd3daed</aircraft_PaperAirplane>
<aircraft_Parachutist>79da74f4e265f5290b4cf35b740663a7</aircraft_Parachutist>
<aircraft_paraglider>6531e09545716af63e4ef5cf8feb8ec1</aircraft_paraglider>
<aircraft_payen-pa100>2f86aa5353798f3a4202e403bfa12c02</aircraft_payen-pa100>
<aircraft_payen-pa350cd>b6e5e2bb9985effc63bdcb2177ec681b</aircraft_payen-pa350cd>
<aircraft_PBY-Catalina>937f55e89ec3df58c2d0339f9a1dd622</aircraft_PBY-Catalina>
<aircraft_PC-12>70352371bec5bee2af6bfa7fceb7da5e</aircraft_PC-12>
<aircraft_PC-21>a53d16394c2492eb0a713ecfd8dbaf8e</aircraft_PC-21>
<aircraft_PC-6>b4fbd66018b94d83d11e3e6e7e0fac1d</aircraft_PC-6>
<aircraft_PC-9M>7c90665c0c85a3e81b15a0ea69befeeb</aircraft_PC-9M>
<aircraft_pc7>6eea7be83224abc9a1c3da0ce2fe6c82</aircraft_pc7>
<aircraft_Percival-Mew-Gull>e2e0f33e2d38ad747f5c738230439ad6</aircraft_Percival-Mew-Gull>
<aircraft_Piaggio-P166>66de4194f057e4a5248d19c5d51f88ca</aircraft_Piaggio-P166>
<aircraft_Piaggio-Pegna-Pc-7>6944e2533d7ddca2752df6300a281b16</aircraft_Piaggio-Pegna-Pc-7>
<aircraft_Pioneer-200>8e89696bf062126e4fe969a65ea5da1f</aircraft_Pioneer-200>
<aircraft_Piper-PA-18>466c8c681f2c6c942668d769e79defba</aircraft_Piper-PA-18>
<aircraft_Piper-PA-28>f7f176d0ff24d09134c43f0e0bc57d5b</aircraft_Piper-PA-28>
<aircraft_Piper-PA-32>601545618b8fe3c210b4514a25242faf</aircraft_Piper-PA-32>
<aircraft_pittss1c>427efb1a07d99ca6c99698de322b7d74</aircraft_pittss1c>
<aircraft_Polikarpov-I16>3926f7b7e584ad63327a622dbac60564</aircraft_Polikarpov-I16>
<aircraft_Pond-Racer>46e6876c63888a593dd46307b7fe0965</aircraft_Pond-Racer>
<aircraft_Potez-630>228dab05bac8112a51265a509d28adc3</aircraft_Potez-630>
<aircraft_Pterodactyl>aa747cdb68e4ce5bcf3fcf3a7fa9b371</aircraft_Pterodactyl>
<aircraft_Pterosaur>fec9ddaa76f650624821341e07c32ef5</aircraft_Pterosaur>
<aircraft_pushback>8fa3ff17dbf4f5216d2b038af30b6d4b</aircraft_pushback>
<aircraft_Quickie>9e12e7ae2a644e77749efb5d5c4d0917</aircraft_Quickie>
<aircraft_R22>7c66503ed0253f16ad021be72e4abfa7</aircraft_R22>
<aircraft_R44>4db8a423cab299263b5139e0b44c4884</aircraft_R44>
<aircraft_RAF-S-E-5>267a979bb7fcadac5698365c158f8fbf</aircraft_RAF-S-E-5>
<aircraft_rah-66>14d8af5d3bc22ac49c5bdfcb8f63c9d8</aircraft_rah-66>
<aircraft_rallye-MS893>7afb876e7a2e7b7bfaa8619bf0c07265</aircraft_rallye-MS893>
<aircraft_Rascal>640eafc8068633c0e48ed3a569d18870</aircraft_Rascal>
<aircraft_RV-6A>27238520cd1123eb6e832489ed6d5a65</aircraft_RV-6A>
<aircraft_Ryan-Navion>e64d386ede9f5d1ab93bbe212246086f</aircraft_Ryan-Navion>
<aircraft_Ryan-PT22>dee77f1d0d3de7f0ce6859006e0ba642</aircraft_Ryan-PT22>
<aircraft_Ryan-SoSL>93e380e1b639a5d063be34521ef058a1</aircraft_Ryan-SoSL>
<aircraft_S-51-Dragonfly>fa4c3f5a64725039c6ac69dc817d0861</aircraft_S-51-Dragonfly>
<aircraft_SaabJ35F>d9c356d0f282204a451c7acb86a0df95</aircraft_SaabJ35F>
<aircraft_santa>cd6232d913be2a512d2e8fcae806afad</aircraft_santa>
<aircraft_Saunders-Roe-Princess>a6cef52c80b2fd0ebc43e26183d9a668</aircraft_Saunders-Roe-Princess>
<aircraft_seahawk>792aa8e491c51b10898600e5fce883fd</aircraft_seahawk>
<aircraft_SeaVixen>21e9817040f8a9ab9160745591915f28</aircraft_SeaVixen>
<aircraft_SenecaII>a769ea7ad74deb9a793966b98be001a0</aircraft_SenecaII>
<aircraft_sf25b>664ad64136e6958a39b292ec54607037</aircraft_sf25b>
<aircraft_sgs233>86308422b554356c850dffb9d0c90b2a</aircraft_sgs233>
<aircraft_Short-Stirling>96a0604d6e963d36a35e919f3ca01310</aircraft_Short-Stirling>
<aircraft_Short_Empire>868a7faef6fb3bca64a0bcb19b32840c</aircraft_Short_Empire>
<aircraft_shuttle>4e24a9c27d36afaec32256a211bef2c3</aircraft_shuttle>
<aircraft_SIAI-Marchetti-S.205R>2771caeaa310c1a6970e95c0ea403f3a</aircraft_SIAI-Marchetti-S.205R>
<aircraft_SIAI-Marchetti-SF.260>dcab556a830e493703640fd1fdad70eb</aircraft_SIAI-Marchetti-SF.260>
<aircraft_Sikorsky-76C>679c00028ac62b9aa3368840147170b5</aircraft_Sikorsky-76C>
<aircraft_Sikorsky-S38>3856921a90f947ec2f3e70fa23a1f6ea</aircraft_Sikorsky-S38>
<aircraft_Sikorsky-S58>9abb2fc4e373ab4431920fdaf45d8a87</aircraft_Sikorsky-S58>
<aircraft_Sky-sportster>d9b9c033f30335a81558a201810f862e</aircraft_Sky-sportster>
<aircraft_Skyranger>0a7450c02b7ff3de085087668ba975e7</aircraft_Skyranger>
<aircraft_Skyvan>712723a74eaa5f47d905c5938d1ecfa3</aircraft_Skyvan>
<aircraft_SM-55>dad894bca78456b5e2ba2e2005d2f29a</aircraft_SM-55>
<aircraft_sm79>626844492e56226455fa3a399f41c9e9</aircraft_sm79>
<aircraft_snowplow>e9eb491ec0bf4d3ad2c2690b94a9be95</aircraft_snowplow>
<aircraft_Socata-ST10>37b95c63434f398743ebbdfd2bee8089</aircraft_Socata-ST10>
<aircraft_sopwithCamel>7792f06b71703a39936f75eb1f0f1e05</aircraft_sopwithCamel>
<aircraft_SpaceShip-One>d082a2f287fc96ade10753e47cff2977</aircraft_SpaceShip-One>
<aircraft_SpaceShuttle>39c46f24941da46177122a83f119e8b7</aircraft_SpaceShuttle>
<aircraft_SPAD-VII>f250ae8d2a2b28eb4f736aa28e8f6abf</aircraft_SPAD-VII>
<aircraft_Spitfire>ca055bf7c4d39b07a40bb465ad635146</aircraft_Spitfire>
<aircraft_spitfireIX>690b3c6a74770738d2d5173fefb48e61</aircraft_spitfireIX>
<aircraft_sr20>cbecc0a364fbe6a7aa0c0ea683ce62ea</aircraft_sr20>
<aircraft_SR71-BlackBird>29a5495e10aa160cf94b0b9a06e94b48</aircraft_SR71-BlackBird>
<aircraft_Stampe-SV4>54ed408f46a6ae86d2b609c58caa2348</aircraft_Stampe-SV4>
<aircraft_Starship>078d68204b7b7d11103f97d6067693d2</aircraft_Starship>
<aircraft_Stearman>791b0a572eba95a6d0fcfdee605b284e</aircraft_Stearman>
<aircraft_Stieglitz>7c5d4939a29bbde445fa5a51a806a600</aircraft_Stieglitz>
<aircraft_Stiletto>f469bf3d05e34508c4644c9f21adde9b</aircraft_Stiletto>
<aircraft_Storch>987d5891ea899b92697b3dbae69f4290</aircraft_Storch>
<aircraft_Su-25>fc53b9f9e774bf455099a41e44f163e0</aircraft_Su-25>
<aircraft_SU-37>f0f2e74ef26520d16f11c26adcfa7244</aircraft_SU-37>
<aircraft_Submarine_Scout>57853593a2c72148f0de00faa70d67d4</aircraft_Submarine_Scout>
<aircraft_Super-Etendard>ea86ee06b4d358790036fe22ae8673a3</aircraft_Super-Etendard>
<aircraft_Super-Frelon>92a9c71fb1666816273b3283e7d02504</aircraft_Super-Frelon>
<aircraft_superguppySGT>86c50734cf3e657a4bb0646ae4848af3</aircraft_superguppySGT>
<aircraft_Supermarine-S.6B>b59d6790040c27853338b680067edc52</aircraft_Supermarine-S.6B>
<aircraft_Superwal>92158d7e55f4a892b3d3640cf0b254f0</aircraft_Superwal>
<aircraft_T-4>8518cfd8bec8278d0681f67dc7293906</aircraft_T-4>
<aircraft_T-50>2e45346a0f377bcb6adc59be3c05d72a</aircraft_T-50>
<aircraft_T37>7607a3732fee1ad3b43d44875764afe0</aircraft_T37>
<aircraft_T38>1039def0bf9d28ef2cc3a4b5649a9bcb</aircraft_T38>
<aircraft_TBM-Avenger>3118e96ceee1f63c4c5f916e48a62e3c</aircraft_TBM-Avenger>
<aircraft_Tecnam-P2006T>45daae280d68e757730051ce96933435</aircraft_Tecnam-P2006T>
<aircraft_Tecnam-P2010>d27cfef60c88f2785585db762aff50c0</aircraft_Tecnam-P2010>
<aircraft_Tecnam-P92>eefbe319cbc34fed4d63ace54f2fc1c8</aircraft_Tecnam-P92>
<aircraft_Tigre>806acc4c1616d1d940e61d27737e39f6</aircraft_Tigre>
<aircraft_TU-114>f6ce2c5a24ea1545e1d22956017e31b0</aircraft_TU-114>
<aircraft_Tu-134>66cee3c0d3e34c4bd97599c1a633c7db</aircraft_Tu-134>
<aircraft_TU-95>71c35b11bb1662bd612bc8e3e21232e5</aircraft_TU-95>
<aircraft_Tu-SB2bis-M103>50cd266f7a98b7d19ec75b9be804e715</aircraft_Tu-SB2bis-M103>
<aircraft_tu154>e5fd32dabb3412be5797805b5b00c002</aircraft_tu154>
<aircraft_tu154b>7a7bd91ea1d3c40e3f52a3453f6d5789</aircraft_tu154b>
<aircraft_UH-1>0c2692680244c3848e16c5f5cc6e525f</aircraft_UH-1>
<aircraft_UH-60>3126bd7f0dc24fb15fbaa6516bbc08d9</aircraft_UH-60>
<aircraft_V22-Osprey>1b1eb3803d01ea5dbfaee1836c9efb02</aircraft_V22-Osprey>
<aircraft_Velocity-XL>85770badb88a7a876bb828718cc4a30f</aircraft_Velocity-XL>
<aircraft_Vickers-Vanguard>1c9f328d29ee7e2453bf30a6b05939f4</aircraft_Vickers-Vanguard>
<aircraft_Vickers-Vimy>5d6709607fc95b3867fc491c0fe5e5e3</aircraft_Vickers-Vimy>
<aircraft_victor>ee0b3f5284765e02f1357f1cf7071ee1</aircraft_victor>
<aircraft_VMX22-Osprey>39f6e98033e45e3b599cdff5b72d7328</aircraft_VMX22-Osprey>
<aircraft_Vostok-1>9dc57923ec3e984723338db44460b4fe</aircraft_Vostok-1>
<aircraft_vulcanb2>f2eabbfcc31b0ab183fb4b91ba4f19c4</aircraft_vulcanb2>
<aircraft_Westland-Whirlwind>cce4ae63928058699f87b61a9604d1b1</aircraft_Westland-Whirlwind>
<aircraft_wrightFlyer1903>04d855def138064915a06781720d33cc</aircraft_wrightFlyer1903>
<aircraft_X15>a4e382d1493412f3d5cb1e06f9ec9b88</aircraft_X15>
<aircraft_x24b>c209d368e99561002a43697c0496d87d</aircraft_x24b>
<aircraft_XB-70>749a85a21354df350ddb8c50a5561b22</aircraft_XB-70>
<aircraft_XP-67>83cebd2f3cf663215a8bb97dcd38b13e</aircraft_XP-67>
<aircraft_Yak-130>b867555c6e06befe0715665c2a10931d</aircraft_Yak-130>
<aircraft_Yak-18T>e514c7719ac869a86ff466a22de3554d</aircraft_Yak-18T>
<aircraft_Yak-23>c1e1b2a685c99e73720bca83f0c01405</aircraft_Yak-23>
<aircraft_Yak-36>2db3c206f581c88c329567013d16aca3</aircraft_Yak-36>
<aircraft_yak3>62ff0d85b3b5d71c2854623bcad155cb</aircraft_yak3>
<aircraft_YardStik>44106df1f8f1145bb7f9d465a3d85233</aircraft_YardStik>
<aircraft_YF-23>bf82709deb10a369d7eaa23d623f631a</aircraft_YF-23>
<aircraft_YS-11>f32ab303e103ceeb6ca46926f2c1f510</aircraft_YS-11>
<aircraft_ZF_Navy_free_balloon>d6d11bb00006f7b6da2f4939ef06af23</aircraft_ZF_Navy_free_balloon>
<aircraft_ZivkoEdge>01893b6c69d97c42f223d95ff8595ff7</aircraft_ZivkoEdge>
<aircraft_Zlin-50lx>ec52deb7d44c5186c324ac0532ff2bc8</aircraft_Zlin-50lx>
<aircraft_ZLT-NT>60ffdd2bd30dc4a02dfca2ced49bbec5</aircraft_ZLT-NT>
<aircraft_IL-76>4a8d5a29427d179a6b0566d79555cbad</aircraft_IL-76>
<aircraft_SuperGuepard912>eedc5b614bac903c03dfdd287dc0123a</aircraft_SuperGuepard912>
<aircraft_Heinkel-He-111Z>e1f2b5c9d0a65366efd6f4840725d3c5</aircraft_Heinkel-He-111Z>
<aircraft_c182s>e307c8d98edfad2432ceea160a5b455d</aircraft_c182s>
<aircraft_Cessna-L19>3c40924714e6511a2c7c2e8d64a22e4c</aircraft_Cessna-L19>
<aircraft_Boomerang>e9c38c20924902a8cb168d69adf028c5</aircraft_Boomerang>
<aircraft_Arsenal-Delanne-10>e01bdd83f13783e98eae4d89d7c55405</aircraft_Arsenal-Delanne-10>
</PropertyList>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Template catalog - copy and modify for your site as required-->
<PropertyList>
<template>
<version n="0">3.4.*</version>
<version n="1">3.5.*</version>
<version n="2">3.6.*</version>
<version n="3">3.7.*</version>
<version n="5">2016.*.*</version>
<version n="6">2017.*.*</version>
<version n="7">2018.*.*</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>
<description>This hangar provides aircraft officially supported and maintained by the FlightGear project, under a free-software license.</description>
<de>
<description>Auf Deutsch</description>
</de>
<fr>
<description>En Francais</description>
</fr>
</template>
</PropertyList>

View File

@ -0,0 +1,11 @@
*/.svn/*
*.xcf*
*.XCF*
*.blend*
*.psd
*~
*/dev/*
*/Dev/*
*/development/*
*/src/*
*/Resources/*

View File

@ -7,6 +7,17 @@
<primary-set type="bool">true</primary-set> <primary-set type="bool">true</primary-set>
<localized>
<de>
<long-description>Describe the F16-A in German</long-description>
</de>
<fr>
<long-description>Describe the F16-A in French</long-description>
</fr>
</localized>
<rating> <rating>
<FDM type="int">3</FDM> <FDM type="int">3</FDM>
<systems type="int">1</systems> <systems type="int">1</systems>

View File

@ -6,6 +6,16 @@
<long-description>The F16-B is an upgraded version of the F16A.</long-description> <long-description>The F16-B is an upgraded version of the F16A.</long-description>
<variant-of>f16a</variant-of> <variant-of>f16a</variant-of>
<localized>
<de>
<long-description>Describe the F16-B in German</long-description>
</de>
<fr>
<long-description>Describe the F16-B in French</long-description>
</fr>
</localized>
<authors n="0"> <authors n="0">
<author n="0"> <author n="0">
<name>James T Kirk</name> <name>James T Kirk</name>

View File

@ -1,21 +1,32 @@
#!/usr/bin/python #! /usr/bin/env python3
import unittest import unittest
import sgprops
import os import os
from os.path import join from os.path import join
import catalog
import lxml.etree as ET import lxml.etree as ET
from shutil import rmtree from shutil import rmtree
from tempfile import mkdtemp from tempfile import mkdtemp
import zipfile import zipfile
from flightgear.meta import sgprops
from flightgear.meta.aircraft_catalogs import catalog
baseDir = os.path.dirname(__file__)
def testData(*args):
return join(baseDir, "testData", *args)
# This is the file from this directory (tests)
fgaddon_catalog_zip_excludes = join(baseDir, "fgaddon-catalog",
"zip-excludes.lst")
catalog.quiet = True catalog.quiet = True
class UpdateCatalogTests(unittest.TestCase): class UpdateCatalogTests(unittest.TestCase):
def test_scan_set(self): def test_scan_set(self):
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) info = catalog.scan_set_file(testData("Aircraft", "f16"),
"f16a-set.xml", [testData("OtherDir")])
self.assertEqual(info['id'], 'f16a') self.assertEqual(info['id'], 'f16a')
self.assertEqual(info['name'], 'F16-A') self.assertEqual(info['name'], 'F16-A')
self.assertEqual(info['primary-set'], True) self.assertEqual(info['primary-set'], True)
@ -39,9 +50,13 @@ class UpdateCatalogTests(unittest.TestCase):
self.assertEqual(authors.getValue('author[0]/email'), 'ww@wright.com') self.assertEqual(authors.getValue('author[0]/email'), 'ww@wright.com')
self.assertEqual(authors.getValue('author[1]/name'), 'Orville Wright') self.assertEqual(authors.getValue('author[1]/name'), 'Orville Wright')
locDe = info['localized']['de']
self.assertEqual(locDe["description"], "Describe the F16-A in German")
def test_scan_dir(self): def test_scan_dir(self):
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"]) (pkg, variants) = catalog.scan_aircraft_dir(
testData("Aircraft", "f16"), [testData("OtherDir")])
self.assertEqual(pkg['id'], 'f16a') self.assertEqual(pkg['id'], 'f16a')
f16trainer = next(v for v in variants if v['id'] == 'f16-trainer') f16trainer = next(v for v in variants if v['id'] == 'f16-trainer')
@ -59,6 +74,9 @@ class UpdateCatalogTests(unittest.TestCase):
self.assertEqual(f16b['variant-of'], 'f16a') self.assertEqual(f16b['variant-of'], 'f16a')
self.assertEqual(f16b['primary-set'], False) self.assertEqual(f16b['primary-set'], False)
locFr = f16b['localized']['fr']
self.assertEqual(locFr["description"], "Describe the F16-B in French")
authorsArray = f16b['authors'] authorsArray = f16b['authors']
self.assertNotIn('author', f16b) self.assertNotIn('author', f16b)
@ -75,13 +93,15 @@ class UpdateCatalogTests(unittest.TestCase):
# test some older constructs for compat # test some older constructs for compat
def test_scan_dir_legacy(self): def test_scan_dir_legacy(self):
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/c172", []) (pkg, variants) = catalog.scan_aircraft_dir(
testData("Aircraft", "c172"), [])
self.assertEqual(pkg['id'], 'c172') self.assertEqual(pkg['id'], 'c172')
self.assertEqual(pkg['author'], 'Wilbur Wright') self.assertEqual(pkg['author'], 'Wilbur Wright')
def test_extract_previews(self): def test_extract_previews(self):
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) info = catalog.scan_set_file(testData("Aircraft", "f16"),
"f16a-set.xml", [testData("OtherDir")])
previews = info['previews'] previews = info['previews']
self.assertEqual(len(previews), 3) self.assertEqual(len(previews), 3)
self.assertEqual(2, len([p for p in previews if p['type'] == 'exterior'])) self.assertEqual(2, len([p for p in previews if p['type'] == 'exterior']))
@ -89,11 +109,13 @@ class UpdateCatalogTests(unittest.TestCase):
self.assertEqual(1, len([p for p in previews if p['path'] == 'Previews/exterior-1.png'])) self.assertEqual(1, len([p for p in previews if p['path'] == 'Previews/exterior-1.png']))
def test_extract_tags(self): def test_extract_tags(self):
info = catalog.scan_set_file("testData/Aircraft/f16", "f16a-set.xml", ["testData/OtherDir"]) info = catalog.scan_set_file(testData("Aircraft", "f16"),
"f16a-set.xml", [testData("OtherDir")])
tags = info['tags'] tags = info['tags']
def test_node_creation(self): def test_node_creation(self):
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/f16", ["testData/OtherDir"]) (pkg, variants) = catalog.scan_aircraft_dir(testData("Aircraft", "f16"),
[testData("OtherDir")])
catalog_node = ET.Element('PropertyList') catalog_node = ET.Element('PropertyList')
catalog_root = ET.ElementTree(catalog_node) catalog_root = ET.ElementTree(catalog_node)
@ -107,7 +129,7 @@ class UpdateCatalogTests(unittest.TestCase):
if not os.path.isdir("testOutput"): if not os.path.isdir("testOutput"):
os.mkdir("testOutput") os.mkdir("testOutput")
cat_file = os.path.join("testOutput", 'catalog_fragment.xml') cat_file = join("testOutput", "catalog_fragment.xml")
catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True)
parsed = sgprops.readProps(cat_file) parsed = sgprops.readProps(cat_file)
@ -134,8 +156,9 @@ class UpdateCatalogTests(unittest.TestCase):
self.assertEqual(parsedPkgNode.getValue('rating/cockpit'), 2) self.assertEqual(parsedPkgNode.getValue('rating/cockpit'), 2)
self.assertEqual(parsedPkgNode.getValue('rating/model'), 5) self.assertEqual(parsedPkgNode.getValue('rating/model'), 5)
self.assertEqual(parsedPkgNode.getValue('localized/de/description'), "Describe the F16-A in German")
# author data verification # author data verification
self.assertFalse(parsedPkgNode.hasChild('author')); self.assertFalse(parsedPkgNode.hasChild('author'));
parsedAuthors = parsedPkgNode.getChild("authors").getChildren('author') parsedAuthors = parsedPkgNode.getChild("authors").getChildren('author')
@ -171,8 +194,12 @@ class UpdateCatalogTests(unittest.TestCase):
self.assertEqual(author1.getValue("email"), "shatner@enterprise.com") self.assertEqual(author1.getValue("email"), "shatner@enterprise.com")
self.assertEqual(author1.getValue("description"), "Everything") self.assertEqual(author1.getValue("description"), "Everything")
self.assertEqual(pv.getValue('localized/de/description'), "Describe the F16-B in German")
def test_node_creation2(self): def test_node_creation2(self):
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/dc3", ["testData/OtherDir"]) (pkg, variants) = catalog.scan_aircraft_dir(testData("Aircraft", "dc3"),
[testData("OtherDir")])
catalog_node = ET.Element('PropertyList') catalog_node = ET.Element('PropertyList')
catalog_root = ET.ElementTree(catalog_node) catalog_root = ET.ElementTree(catalog_node)
@ -183,7 +210,7 @@ class UpdateCatalogTests(unittest.TestCase):
if not os.path.isdir("testOutput"): if not os.path.isdir("testOutput"):
os.mkdir("testOutput") os.mkdir("testOutput")
cat_file = os.path.join("testOutput", 'catalog_fragment2.xml') cat_file = join("testOutput", "catalog_fragment2.xml")
catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True)
parsed = sgprops.readProps(cat_file) parsed = sgprops.readProps(cat_file)
@ -210,7 +237,8 @@ class UpdateCatalogTests(unittest.TestCase):
def test_minimalAircraft(self): def test_minimalAircraft(self):
# test an aircraft with a deliberately spartan -set.xml file with # test an aircraft with a deliberately spartan -set.xml file with
# most interesting data missing # most interesting data missing
(pkg, variants) = catalog.scan_aircraft_dir("testData/Aircraft/c150", ["testData/OtherDir"]) (pkg, variants) = catalog.scan_aircraft_dir(
testData("Aircraft", "c150"), [testData("OtherDir")])
catalog_node = ET.Element('PropertyList') catalog_node = ET.Element('PropertyList')
catalog_root = ET.ElementTree(catalog_node) catalog_root = ET.ElementTree(catalog_node)
@ -221,7 +249,7 @@ class UpdateCatalogTests(unittest.TestCase):
if not os.path.isdir("testOutput2"): if not os.path.isdir("testOutput2"):
os.mkdir("testOutput2") os.mkdir("testOutput2")
cat_file = os.path.join("testOutput2", 'catalog_fragment.xml') cat_file = join("testOutput2", "catalog_fragment.xml")
catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True) catalog_root.write(cat_file, encoding='utf-8', xml_declaration=True)
parsed = sgprops.readProps(cat_file) parsed = sgprops.readProps(cat_file)
@ -247,7 +275,7 @@ class ZipTests(unittest.TestCase):
"""General checks for the zip file.""" """General checks for the zip file."""
# Check for file existence. # Check for file existence.
self.assert_(os.access(file_name, os.F_OK)) self.assertTrue(os.access(file_name, os.F_OK))
# Check the contents. # Check the contents.
file = zipfile.ZipFile(file_name) file = zipfile.ZipFile(file_name)
@ -291,7 +319,9 @@ class ZipTests(unittest.TestCase):
# Create a basic zip file. # Create a basic zip file.
name = "c172" name = "c172"
catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'fgaddon-catalog/zip-excludes.lst'), verbose=False) catalog.make_aircraft_zip(testData("Aircraft"), name,
join(self.tmpdir, name + '.zip'),
fgaddon_catalog_zip_excludes, verbose=False)
# Checks. # Checks.
self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c172/c172-set.xml']) self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c172/c172-set.xml'])
@ -302,8 +332,9 @@ class ZipTests(unittest.TestCase):
# Create a basic zip file. # Create a basic zip file.
name = "dc3" name = "dc3"
catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'fgaddon-catalog/zip-excludes.lst'), verbose=False) catalog.make_aircraft_zip(testData("Aircraft"), name,
join(self.tmpdir, name + '.zip'),
fgaddon_catalog_zip_excludes, verbose=False)
# Checks. # Checks.
self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['dc3/dc3-set.xml']) self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['dc3/dc3-set.xml'])
@ -313,7 +344,11 @@ class ZipTests(unittest.TestCase):
# Create a basic zip file. # Create a basic zip file.
name = "c150" name = "c150"
catalog.make_aircraft_zip(join(os.getcwd(), "testData/Aircraft"), name, join(self.tmpdir, name+'.zip'), join(os.getcwd(), 'testData/Aircraft/c150/zip-excludes.lst'), verbose=False) catalog.make_aircraft_zip(testData("Aircraft"), name,
join(self.tmpdir, name + '.zip'),
testData("Aircraft", "c150",
"zip-excludes.lst"),
verbose=False)
# Checks. # Checks.
self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c150/c150-set.xml', 'c150/Resources/crazy_20Gb_file']) self.check_zip(join(self.tmpdir, name+'.zip'), expected_content=['c150/c150-set.xml', 'c150/Resources/crazy_20Gb_file'])

View File

@ -1,22 +1,31 @@
#! /usr/bin/env python3
import os
import unittest import unittest
import types from flightgear.meta import sgprops
import sgprops
baseDir = os.path.dirname(__file__)
def testData(*args):
return os.path.join(baseDir, "testData", *args)
class SGProps(unittest.TestCase): class SGProps(unittest.TestCase):
def test_parse(self): def test_parse(self):
parsed = sgprops.readProps("testData/props1.xml") parsed = sgprops.readProps(testData("props1.xml"))
self.assertEqual(parsed.getValue("value"), 42) self.assertEqual(parsed.getValue("value"), 42)
self.assertEqual(type(parsed.getValue("value")), types.IntType) self.assertEqual(type(parsed.getValue("value")), int)
valNode = parsed.getChild("value") valNode = parsed.getChild("value")
self.assertEqual(valNode.parent, parsed) self.assertEqual(valNode.parent, parsed)
self.assertEqual(valNode.name, "value") self.assertEqual(valNode.name, "value")
self.assertEqual(valNode.value, 42) self.assertEqual(valNode.value, 42)
self.assertEqual(type(valNode.value), types.IntType) self.assertEqual(type(valNode.value), int)
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
missingNode = parsed.getChild("missing") missingNode = parsed.getChild("missing")
@ -38,10 +47,10 @@ class SGProps(unittest.TestCase):
def test_invalidIndex(self): def test_invalidIndex(self):
with self.assertRaises(IndexError): with self.assertRaises(IndexError):
parsed = sgprops.readProps("testData/bad-index.xml") parsed = sgprops.readProps(testData("bad-index.xml"))
def test_include(self): def test_include(self):
parsed = sgprops.readProps("testData/props2.xml") parsed = sgprops.readProps(testData("props2.xml"))
# test that value in main file over-rides the one in the include # test that value in main file over-rides the one in the include
self.assertEqual(parsed.getValue("value"), 33) self.assertEqual(parsed.getValue("value"), 33)

View File

@ -42,8 +42,8 @@ NEXT_MINOR_VERSION=${VERSION_A[1]}
setVersionTo() { setVersionTo() {
local V="$1" local V="$1"
echo "setting version to $V" echo "setting version to $V"
echo "$V" > version echo "$V" > flightgear-version
git add version git add flightgear-version
echo "new version: $V" | git commit --file=- echo "new version: $V" | git commit --file=-
# git tag "version/$V" # git tag "version/$V"
} }

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
THIS_RELEASE="2019.1" THIS_RELEASE="2020.2"
NEXT_RELEASE="2019.2" NEXT_RELEASE="2020.3"
SUBMODULES="simgear flightgear fgdata getstart" SUBMODULES="simgear flightgear fgdata getstart"
#:<< 'COMMENT_END' #:<< 'COMMENT_END'
@ -39,6 +39,6 @@ done
# IdentitiesOnly yes # IdentitiesOnly yes
# User user_sf_username # User user_sf_username
svn copy svn+ssh://svn.code.sf.net/p/flightgear/fgaddon/trunk \ #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} \ # svn+ssh://svn.code.sf.net/p/flightgear/fgaddon/branches/release-${THIS_RELEASE} \
-m "branching for release ${THIS_RELEASE}" # -m "branching for release ${THIS_RELEASE}"

View File

@ -0,0 +1,65 @@
#!/bin/bash
#####################################################################################
if [ "$WORKSPACE" == "" ]; then
echo "ERROR: Missing WORKSPACE environment variable."
exit 1
fi
if [ ! -d "$WORKSPACE/fgdata" ]; then
echo "No fgdata subdir in WORKSPACE: can't continue"
exit 1
fi
VERSION=`cat fgdata/version`
BASE_VERSION_TAG="version/2020.3.1"
SCENERY_PACK_AIRPORT=BIKF
SCENERY_PACK_URI="https://sourceforge.net/projects/flightgear/files/scenery/SceneryPack.${SCENERY_PACK_AIRPORT}.tgz/download"
echo "Assembling base package for $VERSION"
cd $WORKSPACE
# wipe directories and re-create
rm -rf staging
mkdir -p output
mkdir -p staging
# wipe existing data TXZs
rm output/FlightGear-$VERSION*data.txz
rsync -az --exclude=".git" --exclude="Textures/Unused" --exclude="*.xcf" fgdata staging/
# add all the scenery pack files into it
SCENERY_PACK_NAME=SceneryPack_${SCENERY_PACK_AIRPORT}.tgz
# Should we re-download the SceneryPack periodically? Or just rely on doing a workspace wipe?
if [ ! -f $SCENERY_PACK_NAME ]; then
echo "Downlaod scenery pack from ${SCENERY_PACK_URI}"
# -L to follow the SF redirect
curl -L $SCENERY_PACK_URI --output $SCENERY_PACK_NAME
fi
tar -xf $SCENERY_PACK_NAME --directory staging/fgdata
pushd staging/fgdata
mv SceneryPack.${SCENERY_PACK_AIRPORT} Scenery
popd
# Creating full base package TXZ
OUTPUT_NAME=FlightGear-$VERSION-data
tar -cJf output/$OUTPUT_NAME.txz --directory staging fgdata
echo "Creating updates package"
pushd fgdata
git diff --name-only --line-prefix="fgdata/" $BASE_VERSION_TAG..HEAD > ../fgdata_changes
popd
tar -cJf output/FlightGear-$VERSION-update-data.txz -T fgdata_changes
echo "Done, data TXZs are in output/"

View File

@ -33,9 +33,9 @@ MICRO_VERSION=${VERSION_A[2]}
setVersionTo() { setVersionTo() {
local V="$1" local V="$1"
echo "setting version to $V" echo "setting version to $V in $2"
echo "$V" > version echo "$V" > $2
git add version git add $2
echo "new version: $V" | git commit --file=- echo "new version: $V" | git commit --file=-
git tag "version/$V" git tag "version/$V"
} }
@ -43,9 +43,22 @@ setVersionTo() {
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
echo "Processing $1" echo "Processing $1"
pushd $1 > /dev/null pushd $1 > /dev/null
case $1 in
flightgear)
versionFileName="flightgear-version"
;;
simgear)
versionFileName="simgear-version"
;;
*)
versionFileName="version"
;;
esac
git config user.name "Automatic Release Builder" git config user.name "Automatic Release Builder"
git config user.email "build@flightgear.org" git config user.email "build@flightgear.org"
setVersionTo "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}" setVersionTo "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}" $versionFileName
popd > /dev/null popd > /dev/null
shift shift
done done

View File

@ -0,0 +1,37 @@
#!/bin/bash
# TODO: detect this some smarter way (or make it an arg?)
versionMajor=2020.3
patchLevel=7
version=$versionMajor.$patchLevel
echo "Moving RC for $version to SourceForge FRS"
server=jmturner@frs.sourceforge.net
destination=/home/frs/project/f/fl/flightgear
source=/var/www/downloads/builds/rc
localDest=/var/www/downloads/builds/$versionMajor
mkdir -p $localDest
scp $source/FlightGear-$version-rc.dmg $server:$destination/release-$versionMajor/FlightGear-$version.dmg
scp $source/FlightGear-$version-rc.exe $server:$destination/release-$versionMajor/FlightGear-$version.exe
scp $source/FlightGear-$version-x86_64-rc.AppImage $server:$destination/release-$versionMajor/FlightGear-$version-x86_64.AppImage
scp $source/flightgear-$version-rc.tar.bz2 $server:$destination/release-$versionMajor/flightgear-$version.tar.bz2
scp $source/simgear-$version-rc.tar.bz2 $server:$destination/release-$versionMajor/simgear-$version.tar.bz2
scp $source/FlightGear-$version-data-rc.txz $server:$destination/release-$versionMajor/FlightGear-$version-data.txz
scp $source/FlightGear-$version-update-data-rc.txz $server:$destination/release-$versionMajor/FlightGear-$version-update-data.txz
cp $source/FlightGear-$version-rc.dmg $localDest/FlightGear-$version.dmg
cp $source/FlightGear-$version-rc.exe $localDest/FlightGear-$version.exe
cp $source/FlightGear-$version-x86_64-rc.AppImage $localDest/FlightGear-$version-x86_64.AppImage
cp $source/flightgear-$version-rc.tar.bz2 $localDest/flightgear-$version.tar.bz2
cp $source/simgear-$version-rc.tar.bz2 $localDest/simgear-$version.tar.bz2
cp $source/FlightGear-$version-data-rc.txz $localDest/FlightGear-$version-data.txz
cp $source/FlightGear-$version-update-data-rc.txz $localDest/FlightGear-$version-update-data.txz
echo "All done"

@ -1 +1 @@
Subproject commit f96437402732f979f5921e2fde4fa97fbe4e5cd7 Subproject commit 3075b8bcc4b1513fce346212128547c8de2f7d62

29
sync_to_SF_frs.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
versionMajor=2018.3
patchLevel=6
version=$versionMajor.$patchLevel
echo "Moving RC for $version to SourceForge FRS"
server=jmturner@frs.sourceforge.net
destination=/home/frs/project/f/fl/flightgear
source=/var/www/html/builds/rc
localDest=/var/www/html/builds/$versionMajor
scp $source/FlightGear-$version-rc.dmg $server:$destination/release-$versionMajor/FlightGear-$version.dmg
scp $source/FlightGear-$version-rc.exe $server:$destination/release-$versionMajor/FlightGear-$version.exe
scp $source/flightgear-$version-rc.tar.bz2 $server:$destination/release-$versionMajor/flightgear-$version.tar.bz2
scp $source/simgear-$version-rc.tar.bz2 $server:$destination/release-$versionMajor/simgear-$version.tar.bz2
scp $source/FlightGear-$version-data-rc.tar.bz2 $server:$destination/release-$versionMajor/FlightGear-$version-data.tar.bz2
cp $source/FlightGear-$version-rc.dmg $localDest/FlightGear-$version.dmg
cp $source/FlightGear-$version-rc.exe $localDest/FlightGear-$version.exe
cp $source/flightgear-$version-rc.tar.bz2 $localDest/flightgear-$version.tar.bz2
cp $source/simgear-$version-rc.tar.bz2 $localDest/simgear-$version.tar.bz2
cp $source/FlightGear-$version-data-rc.tar.bz2 $localDest/FlightGear-$version-data.tar.bz2
echo "All done"

View File

@ -1 +1 @@
2020.1.1 2020.4.0

BIN
windows/flightgear.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -0,0 +1,20 @@
FlightGear Unstable
===================
Contains FlightGear from the source code repository ('next' branch).
Please note that this installer is using the latest development code.
There is no guarantee that the code does not contain serious bugs and other issues.
It contains in-development features which are not yet considered stable, but whichare ready for
testing and feedback.
I have found a bug!
--------------------
If you find serious bugs, instability, performance degradation:
- look at the FlightGear Tickets page (on the SourceForge project page)
- ask on the FlightGear forum (explicitly say that you're using unstable version)
- look at the flightgear-devel mailing list
Many problems are already known or reported, but don't be afraid to ask and check.

View File

@ -0,0 +1,21 @@
FlightGear Unstable
===================
Zawiera kod źródłowy FlightGear z repozytorium kodu źródłowego (gałąź 'next').
Proszę, zauważ że to jest instalator, który zawiera najnowszy kod rozwojowy.
Nie ma gwarancji, że ten kod nie zawiera poważnych błędów i innych problemów.
Niemniej, to jest pakiet, który zawiera najwięcej nowej funkcjonalności, która
nie jest jeszcze dostępna w oficjalnej, stabilnej wersji oprogramowania.
Miłej zabawy i korzystania z niego !
Znalazłem błąd !
--------------------
Jeśli znalazłeś poważny błąd, niestabilność, ograniczenie wydajności:
- sprawdź stronę ze zgłoszeniami błędów FlightGear (na stronie projektu SourceForge)
- zapytaj na forum FlightGear (wskaż jasno, że korzystasz z wersji niestabilnej/unstable)
- sprawdź mailową listę dyskusyjną flightgear-devel
Jest prawdopodobne, że programiści już pracują nad rozwiązaniem tego problemu !

BIN
windows/setupimg.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
windows/setupsmall.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

8
ws30/README.TXT Normal file
View File

@ -0,0 +1,8 @@
A set of trivial python scripts to generate World Scenery 3.0 (ws30) scenery
features from openstreetmap data, using the overpass API to retrieve data at
runtime.
These scripts are very simplistic and don't attempt to be particularly efficient
in their use of the API. The should be improved before use on the entire world,
as they can (and do) result in being blocked from the overpass API if used on
and unreasonably large area.

206
ws30/calc_tile.py Executable file
View File

@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
"""
shamelessly translated from calc-tile.pl
"""
import logging
from math import floor
import os
from typing import List, Tuple
import unittest
import numpy as np
def bucket_span(lat: float) -> float:
"""Latitude Range -> Tile Width (deg)"""
abs_lat = abs(lat)
if abs_lat >= 89:
return 360
elif abs_lat >= 88:
return 8
elif abs_lat >= 86:
return 4
elif abs_lat >= 83:
return 2
elif abs_lat >= 76:
return 1
elif abs_lat >= 62:
return .5
elif abs_lat >= 22:
return .25
elif abs_lat >= 0:
return .125
return 360
def format_lon(lon):
"""Format longitude as e/w."""
if lon < 0.:
return "w%03d" % int(0. - lon)
else:
return "e%03d" % int(lon)
def format_lat(lat):
"""Format latitude as n/s."""
if lat < 0.:
return "s%02d" % int(0. - lat)
else:
return "n%02d" % int(lat)
def directory_name(lon_lat: Tuple[float, float], separator: str = None) -> str:
"""Generate the directory name for a location."""
(lon, lat) = lon_lat
lon_floor = floor(lon)
lat_floor = floor(lat)
lon_chunk = floor(lon/10.0) * 10
lat_chunk = floor(lat/10.0) * 10
if separator:
return '{}{}{}{}{}'.format(format_lon(lon_chunk), format_lat(lat_chunk), separator,
format_lon(lon_floor), format_lat(lat_floor))
return os.path.join(format_lon(lon_chunk) + format_lat(lat_chunk), format_lon(lon_floor) + format_lat(lat_floor))
def calc_tile_index(lon_lat: Tuple[float, float], x: int = 0, y: int = 0) -> int:
"""See http://wiki.flightgear.org/Tile_Index_Scheme"""
(lon, lat) = lon_lat
if x == 0 and y == 0:
y = calc_y(lat)
x = calc_x(lon, lat)
index = (int(floor(lon)) + 180) << 14
index += (int(floor(lat)) + 90) << 6
index += y << 3
index += x
return index
def calc_tile_location(tile_index: int) -> Tuple[Tuple[float, float], Tuple[float, float]]:
"""The lon/lat as well as x/y tuples for the location of a tile by its index"""
lon = tile_index >> 14
index = tile_index - (lon << 14)
lon = lon - 180
lat = index >> 6
index = index - (lat << 6)
lat = lat - 90
y = index >> 3
index = index - (y << 3)
x = index
return (lon, lat), (x, y)
def log_tile_info(tile_index: int) -> None:
"""logs information about the tile to logging.debug."""
(lon, lat), (x, y) = calc_tile_location(tile_index)
center_lat = lat + y / 8.0 + 0.0625
center_lon = bucket_span(center_lat)
if center_lon >= 1.0:
center_lon = lon + center_lon / 2.0
else:
center_lon = lon + x * center_lon + center_lon / 2.0
tile_info = 'Tile location: {}; lon: {}, lat: {}; x: {}, y: {}; tile span degrees: {}; center lon/lat: {}/{}.'
logging.debug(tile_info.format(tile_index, lon, lat, x, y, bucket_span(lat), center_lon, center_lat))
def construct_path_to_files(base_directory: str, scenery_type: str, center_global: Tuple[float, float]) -> str:
"""Returns the path to the stg-files in a FG scenery directory hierarchy at a given global lat/lon location.
The scenery type is e.g. 'Terrain', 'Object', 'Buildings'."""
return os.path.join(base_directory, scenery_type, directory_name(center_global))
def construct_stg_file_name(center_global: Tuple[float, float]) -> str:
"""Returns the file name of the stg-file at a given global lat/lon location"""
return construct_stg_file_name_from_tile_index(calc_tile_index(center_global))
def construct_stg_file_name_from_tile_index(tile_idx: int) -> str:
return str(tile_idx) + '.stg'
def construct_btg_file_name_from_tile_index(tile_idx: int) -> str:
return str(tile_idx) + '.btg.gz'
def construct_btg_file_name_from_airport_code(airport_code: str) -> str:
return airport_code + '.btg.gz'
def get_north_lat(lat, y):
return float(floor(lat)) + y / 8.0 + .125
def get_south_lat(lat, y):
return float(floor(lat)) + y / 8.0
def get_west_lon(lon, lat, x):
if x == 0:
return float(floor(lon))
else:
return float(floor(lon)) + x * (bucket_span(lat))
def get_east_lon(lon, lat, x):
if x == 0:
return float(floor(lon)) + (bucket_span(lat))
else:
return float(floor(lon)) + x * (bucket_span(lat)) + (bucket_span(lat))
def calc_x(lon: float, lat: float) -> int:
"""
FIXME: is this correct? Also: some returns do not take calculations into account.
"""
epsilon = 0.0000001
span = bucket_span(lat)
if span < epsilon:
lon = 0
return 0
elif span <= 1.0:
return int((lon - floor(lon)) / span)
else:
if lon >= 0:
lon = int(int(lon/span) * span)
else:
lon = int(int((lon+1)/span) * span - span)
if lon < -180:
lon = -180
return 0
def calc_y(lat: float) -> int:
return int((lat - floor(lat)) * 8)
def get_stg_files_in_boundary(boundary_west: float, boundary_south: float, boundary_east: float, boundary_north: float,
path_to_scenery: str, scenery_type: str) -> List[str]:
"""Based on boundary rectangle returns a list of stg-files (incl. full path) to be found within the boundary of
the scenery"""
stg_files = []
for my_lat in np.arange(boundary_south, boundary_north, 0.125): # latitude; 0.125 as there are always 8 tiles
for my_lon in np.arange(boundary_west, boundary_east, bucket_span(my_lat)): # longitude
coords = (my_lon, my_lat)
stg_files.append(os.path.join(construct_path_to_files(path_to_scenery, scenery_type, coords),
construct_stg_file_name(coords)))
return stg_files
# ================ UNITTESTS =======================
class TestCalcTiles(unittest.TestCase):
def test_calc_tiles(self):
self.assertEqual(5760, calc_tile_index((-179.9, 0.1)))
self.assertEqual(5752, calc_tile_index((-179.9, -0.1)))
self.assertEqual(5887623, calc_tile_index((179.9, 0.1)))
self.assertEqual(5887615, calc_tile_index((179.9, -0.1)))
self.assertEqual(2954880, calc_tile_index((0.0, 0.0)))
self.assertEqual(2938495, calc_tile_index((-0.1, -0.1)))
def test_file_name(self):
self.assertEqual("3088961.stg", construct_stg_file_name((8.29, 47.08)))

131
ws30/gencoastline.py Executable file
View File

@ -0,0 +1,131 @@
#!/usr/bin/python
# gencoastline.py - create appropriate COASTLINE_LIST STG files for ws30 from openstreetmap
# Copyright (C) 2021 Stuart Buchanan
#
# 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.
# You will need Python Overpass API - "pip install overpy"
import xml.etree.ElementTree as etree
import os
import shutil
import re
import sys
import collections
from math import floor
import calc_tile
import overpy
nodes = {}
curr_coast_count = 0
coast_count = 0
if (len(sys.argv) != 6):
print("Simple generation of COASTLINE_LIST files")
print("")
print("Usage: " + sys.argv[0] + " <scenery_dir> <lon1> <lat1> <lon2> <lat2>")
print(" <scenery_dir> \tScenery directory to write to")
print(" <lon1> <lat1> \tBottom left lon/lat of bounding box")
print(" <lon2> <lat2> \tTop right lon/lat of bounding box")
exit(1)
scenery_prefix = sys.argv[1]
lon1 = sys.argv[2]
lat1 = sys.argv[3]
lon2 = sys.argv[4]
lat2 = sys.argv[5]
os.makedirs(scenery_prefix, exist_ok=True)
def feature_file(lat, lon):
index = calc_tile.calc_tile_index((lon,lat))
return str(index) + "_Coastline.txt"
def add_to_stg(lat, lon):
index = calc_tile.calc_tile_index((lon, lat))
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
#print("Writing " + stg)
with open(stg, 'a') as f:
f.write("COASTLINE_LIST " + feature_file(lat, lon) + "\n")
def write_feature(lon, lat, coast):
index = calc_tile.calc_tile_index((lon,lat))
dirname = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)))
os.makedirs(dirname, exist_ok=True)
txt = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), feature_file(lat, lon))
#print("Writing " + txt)
with open(txt, 'a') as f:
for pt in coast :
f.write(" " + str(pt.lon) + " " + str(pt.lat))
f.write("\n")
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
if not os.path.isfile(stg) :
# No STG - generate
add_to_stg(lat, lon)
else :
road_exists = 0
with open(stg, 'r') as f:
for line in f:
if line.startswith("COASTLINE_LIST " + feature_file(lat, lon)) :
road_exists = 1
if road_exists == 0 :
add_to_stg(lat, lon)
def parse_way(way) :
global curr_coast_count, lat1, lon1, lat2, lon2
pts = []
width = 6.0
road = 0
river = 0
# It's a road or river. Add it to appropriate tile entries.
tileids = set()
for pt in way.nodes:
lon = float(pt.lon)
lat = float(pt.lat)
idx = calc_tile.calc_tile_index([lon, lat])
if ((float(lon1) <= lon <= float(lon2)) and (float(lat1) <= lat <= float(lat2)) and (idx not in tileids)) :
# Write the feature to a bucket provided it's within the lat/lon bounds and if we've not already written it there
curr_coast_count = curr_coast_count + 1
write_feature(lon, lat, way.nodes)
tileids.add(idx)
def writeOSM(result):
for child in result.ways:
parse_way(child)
# Get River data
for lat in range(int(lat1), int(lat2)):
for lon in range(int(lon1), int(lon2)):
osm_bbox = ",".join([str(lat), str(lon), str(lat+1), str(lon+1)])
#api = overpy.Overpass(url="https://lz4.overpass-api.de/api/interpreter")
api = overpy.Overpass(url="https://overpass.kumi.systems/api/interpreter")
coast_query = "way[\"natural\"=\"coastline\"](" + osm_bbox + ");(._;>;);out;"
curr_coast_count = 0
result = api.query(coast_query)
writeOSM(result)
print(str(lat) + "," + str(lon) + ": " + str(curr_coast_count) + " pieces of coastline")
coast_count = coast_count + curr_coast_count
print(str(lat1) + "," + str(lon1) + " " + str(lat2) + "," + str(lon2))
print("Wrote total of " + str(coast_count) + " pieces of coastline")

230
ws30/genroads.py Executable file
View File

@ -0,0 +1,230 @@
#!/usr/bin/python
# genroads.py - create appropriate ROAD_LIST STG files for ws30 from openstreetmap
# Copyright (C) 2021 Stuart Buchanan
#
# 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 generate of line feature - roads, railways, rivers
# You will need Python Overpass API - "pip install overpy"
import xml.etree.ElementTree as etree
import os
import shutil
import re
import sys
import collections
from math import floor
import calc_tile
import overpy
nodes = {}
curr_road_count = 0
curr_river_count = 0
road_count = 0
river_count = 0
if (len(sys.argv) != 6):
print("Simple generation of LINEAR_FEATURE_LIST files")
print("")
print("Usage: " + sys.argv[0] + " <scenery_dir> <lon1> <lat1> <lon2> <lat2>")
print(" <scenery_dir> \tScenery directory to write to")
print(" <lon1> <lat1> \tBottom left lon/lat of bounding box")
print(" <lon2> <lat2> \tTop right lon/lat of bounding box")
exit(1)
scenery_prefix = sys.argv[1]
lon1 = sys.argv[2]
lat1 = sys.argv[3]
lon2 = sys.argv[4]
lat2 = sys.argv[5]
os.makedirs(scenery_prefix, exist_ok=True)
def feature_file(lat, lon, type):
index = calc_tile.calc_tile_index((lon,lat))
return str(index) + "_" + type + ".txt"
def add_to_stg(lat, lon, type):
index = calc_tile.calc_tile_index((lon, lat))
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
#print("Writing " + stg)
with open(stg, 'a') as f:
f.write("LINE_FEATURE_LIST " + feature_file(lat, lon, type) + " " + type + "\n")
def write_feature(lon, lat, road, type, width, lit):
index = calc_tile.calc_tile_index((lon,lat))
dirname = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)))
os.makedirs(dirname, exist_ok=True)
txt = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), feature_file(lat, lon, type))
#print("Writing " + txt)
with open(txt, 'a') as f:
f.write(str(width) + " " + str(lit) + " 1 1 1 1") # Width plus currently unused generic attributes.
for pt in road :
f.write(" " + str(pt.lon) + " " + str(pt.lat))
f.write("\n")
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
if not os.path.isfile(stg) :
# No STG - generate
add_to_stg(lat, lon, type)
else :
road_exists = 0
with open(stg, 'r') as f:
for line in f:
if line.startswith("LINE_FEATURE_LIST " + feature_file(lat, lon, type)) :
road_exists = 1
if road_exists == 0 :
add_to_stg(lat, lon, type)
def parse_way(way) :
global curr_road_count, curr_river_count, lat1, lon1, lat2, lon2
pts = []
width = 6.0
lit = 0
road = 0
river = 0
rail = 0
highway = way.tags.get("highway")
waterway = way.tags.get("waterway")
railway = way.tags.get("railway")
feature_type = "None"
if way.tags.get("tunnel") == None or way.tags.get("tunnel") != "yes":
if (highway=="motorway_junction") or (highway=="motorway") or (highway=="motorway_link"):
width = 15.0
feature_type = "ws30Freeway"
curr_road_count = curr_road_count + 1
if (highway=="primary") or (highway=="trunk") or (highway=="trunk_link") or (highway=="primary_link") :
width = 12.0
feature_type = "ws30Freeway"
curr_road_count = curr_road_count + 1
if (highway=="secondary") or (highway=="secondary_link") :
width = 12.0
feature_type = "ws30Road"
curr_road_count = curr_road_count + 1
if (highway=="unclassified") or (highway=="tertiary") or (highway=="tertiary_link") or (highway=="service") or (highway=="residential"):
width = 6.0
feature_type = "ws30Road"
curr_road_count = curr_road_count + 1
if (waterway=="river") or (waterway=="canal") :
width = 10.0
feature_type = "ws30River"
curr_river_count = curr_river_count + 1
if (railway=="rail") or (railway=="preserved") or (railway=="disused") :
width = 4.2 # Standard guage ~ 1.4m, with twice the space either side
feature_type = "ws30Railway"
# Use the width if defined and parseable
if (way.tags.get("width") != None) :
width_str = way.tags.get("width")
try:
if (' m' in width_str) :
width = float(width_str[0:width_str.find(" m")])
if (' ft' in width_str) :
width = 0.3 * float(width_str[0:width_str.find(" ft")])
except ValueError :
print("Unable to parse width " + width_str)
# Use the lit tag if defined and parseable
if (way.tags.get("lit") != None) :
lit_str = way.tags.get("lit")
if ((lit_str == "no") or (lit == "disused")) :
# Specific tags for unlit ways
lit = 0
else :
# Everything else indicates some form of lighting
lit = 1
if (feature_type != "None") :
# It's a road or river. Add it to appropriate tile entries.
tileids = set()
for pt in way.nodes:
lon = float(pt.lon)
lat = float(pt.lat)
idx = calc_tile.calc_tile_index([lon, lat])
if ((float(lon1) <= lon <= float(lon2)) and (float(lat1) <= lat <= float(lat2)) and (idx not in tileids)) :
# Write the feature to a bucket provided it's within the lat/lon bounds and if we've not already written it there
write_feature(lon, lat, way.nodes, feature_type, width, lit)
tileids.add(idx)
def writeOSM(result):
for child in result.ways:
parse_way(child)
for lat in range(int(lat1), int(lat2)):
for lon in range(int(lon1), int(lon2)):
curr_road_count = 0
curr_river_count = 0
osm_bbox = ",".join([str(lat), str(lon), str(lat+1), str(lon+1)])
#api = overpy.Overpass(url="https://lz4.overpass-api.de/api/interpreter")
api = overpy.Overpass(url="https://overpass.kumi.systems/api/interpreter")
# Get River data
river_query = "(way[\"waterway\"=\"river\"](" + osm_bbox + "); way[\"waterway\"=\"canal\"](" + osm_bbox + "););(._;>;);out;"
result = api.query(river_query)
writeOSM(result)
railway_query = "("
railway_types = ["rail", "preserved", "disused", "subway", "narrow_gauge"]
for r in railway_types :
railway_query = railway_query + "way[\"railway\"=\"" + r + "\"](" + osm_bbox + ");"
railway_query = railway_query + ");(._;>;);out;"
result = api.query(railway_query)
writeOSM(result)
road_query = "("
#road_types = ["unclassified", "tertiary", "service", "secondary", "primary", "motorway_junction", "motorway"]
#road_types = ["tertiary", "secondary", "primary", "motorway_junction", "motorway"]
road_types = ["motorway", "trunk", "primary", "secondary", "tertiary", "unclassified", "residential", "motorway_link", "trunk_link", "primary_link", "secondary_link", "tertiary_link"]
for r in road_types :
road_query = road_query + "way[\"highway\"=\"" + r + "\"](" + osm_bbox + ");"
road_query = road_query + ");(._;>;);out;"
result = api.query(road_query)
writeOSM(result)
print(str(lat) + "," + str(lon) + ": " + str(curr_road_count) + " roads " + str(curr_river_count) + " rivers")
road_count += curr_road_count
river_count += curr_river_count
print(str(lat1) + "," + str(lon1) + " " + str(lat2) + "," + str(lon2))
print("Wrote total of " + str(road_count) + " roads " + str(river_count) + " rivers")
#
#
#
#
#time ./genroads.py /tmp/OSMTEST/Terrain/ -3.5 55.0 -2.5 56.0
#2005 time ./genroads.py /tmp/OSMTEST/Terrain/ -12 59.0 -10 61.0
# 2006 time ./genroads.py /tmp/OSMTEST/Terrain/ -10 59.0 -8 61.0
# 2007 time ./genroads.py /tmp/OSMTEST/Terrain/ -8 59.0 -4 61.0
# 2008 time ./genroads.py /tmp/OSMTEST/Terrain/ -4 59.0 0 61.0
# 2009 time ./genroads.py /tmp/OSMTEST/Terrain/ 0 59.0 4 61.0
# 2010 time ./genroads.py /tmp/OSMTEST/Terrain/ -12 57.0 -10 59.0
# 2011 time ./genroads.py /tmp/OSMTEST/Terrain/ -10 57.0 -6 59.0
# 2012 time ./genroads.py /tmp/OSMTEST/Terrain/ -6 57.0 -2 59.0
# 2013 time ./genroads.py /tmp/OSMTEST/Terrain/ -2 57.0 4 59.0

146
ws30/genwater.py Executable file
View File

@ -0,0 +1,146 @@
#!/usr/bin/python
# genwater.py - create appropriate AREA_FEATURE_LIST STG files for ws30 from openstreetmap
# Copyright (C) 2021 Stuart Buchanan
#
# 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.
# You will need Python Overpass API - "pip install overpy"
import xml.etree.ElementTree as etree
import os
import shutil
import re
import sys
import collections
from math import floor
import calc_tile
import overpy
nodes = {}
road_count = 0
river_count = 0
if (len(sys.argv) != 6):
print("Simple generation of AREA_FEATURE_LIST files")
print("")
print("Usage: " + sys.argv[0] + " <scenery_dir> <lon1> <lat1> <lon2> <lat2>")
print(" <scenery_dir> \tScenery directory to write to")
print(" <lon1> <lat1> \tBottom left lon/lat of bounding box")
print(" <lon2> <lat2> \tTop right lon/lat of bounding box")
exit(1)
scenery_prefix = sys.argv[1]
lon1 = sys.argv[2]
lat1 = sys.argv[3]
lon2 = sys.argv[4]
lat2 = sys.argv[5]
os.makedirs(scenery_prefix, exist_ok=True)
def feature_file(lat, lon, type):
index = calc_tile.calc_tile_index((lon,lat))
return str(index) + "_area_" + type + ".txt"
def add_to_stg(lat, lon, type):
index = calc_tile.calc_tile_index((lon, lat))
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
#print("Writing " + stg)
with open(stg, 'a') as f:
f.write("AREA_FEATURE_LIST " + feature_file(lat, lon, type) + " " + type + "\n")
def write_feature(lon, lat, pts, type):
index = calc_tile.calc_tile_index((lon,lat))
dirname = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)))
os.makedirs(dirname, exist_ok=True)
txt = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), feature_file(lat, lon, type))
#print("Writing " + txt)
with open(txt, 'a') as f:
f.write("10000000 0 1 1 1 1") # Currently unused generic attributes. Also set area to 2000m^2
for pt in pts :
f.write(" " + str(pt.lon) + " " + str(pt.lat))
f.write("\n")
stg = os.path.join(scenery_prefix, calc_tile.directory_name((lon, lat)), str(index) + ".stg")
if not os.path.isfile(stg) :
# No STG - generate
add_to_stg(lat, lon, type)
else :
pts_exists = 0
with open(stg, 'r') as f:
for line in f:
if line.startswith("AREA_FEATURE_LIST " + feature_file(lat, lon, type)) :
pts_exists = 1
if pts_exists == 0 :
add_to_stg(lat, lon, type)
def parse_way(way) :
global road_count, river_count, lat1, lon1, lat2, lon2
pts = []
#feature_type = way.tags.get("water")
feature_type = "Lake"
# Add it to appropriate tile entries.
tileids = set()
for pt in way.nodes:
lon = float(pt.lon)
lat = float(pt.lat)
idx = calc_tile.calc_tile_index([lon, lat])
if ((float(lon1) <= lon <= float(lon2)) and (float(lat1) <= lat <= float(lat2)) and (idx not in tileids)) :
# Write the feature to a bucket provided it's within the lat/lon bounds and if we've not already written it there
write_feature(lon, lat, way.nodes, feature_type)
tileids.add(idx)
def get_first_node(way) :
return way.nodes[0]
def get_last_node(way) :
return way.nodes[-1]
def parse_multi(relation):
for way in relation.members:
if (way.tags.get("role") == "outer") :
parse_way(way)
def writeOSM(result):
#for child in result.relations:
#parse_multi(child)
for child in result.ways:
parse_way(child)
# Get Lake data
osm_bbox = ",".join([lat1, lon1, lat2, lon2])
api = overpy.Overpass(url="https://lz4.overpass-api.de/api/interpreter")
query = "("
water_types = ["lake", "basin", "oxbow", "lagoon", "reservoir"]
for r in water_types :
query = query + "way[\"water\"=\"" + r + "\"](" + osm_bbox + ");"
query = query + "way[\"landuse\"=\"" + r + "\"](" + osm_bbox + ");"
query = query + "way[\"natural\"=\"water\"](" + osm_bbox + ");"
for r in water_types :
query = query + "relation[\"water\"=\"" + r + "\"][\"type\"=\"multipolygon\"](" + osm_bbox + ");"
query = query + ");(._;>;);out;"
result = api.query(query)
writeOSM(result)

2
ws30/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
numpy==1.22.1
overpy==0.6

View File

@ -0,0 +1,19 @@
# Data files
*.zip
*.hdr
*.tfw
*.tif
## Corine
data/u2018_clc2018_v2020_20u1_raster100m/
## SRTM
data/readme.txt
# macOS
*.DS_Store
# Output folder
output
# build dir
build

View File

@ -0,0 +1,76 @@
FROM ubuntu:focal AS build
# Set timezone:
RUN ln -snf /usr/share/zoneinfo/$CONTAINER_TIMEZONE /etc/localtime && echo $CONTAINER_TIMEZONE > /etc/timezone
RUN apt-get update && \
apt-get install -y \
build-essential \
cmake \
git \
libnvtt-dev
RUN useradd --create-home --home-dir=/home/flightgear --shell=/bin/false flightgear
USER flightgear
WORKDIR /home/flightgear/build/
ARG INSTALLPREFIX=/home/flightgear/dist
RUN git clone --branch release/2.4 https://github.com/OSGeo/gdal.git
WORKDIR /home/flightgear/build/gdal/gdal
RUN ./configure --prefix=${INSTALLPREFIX}
RUN make -j $(nproc)
RUN make install
WORKDIR /home/flightgear/build/
RUN git clone --branch OpenSceneGraph-3.6.5 https://github.com/openscenegraph/OpenSceneGraph.git
RUN mkdir OpenSceneGraph/build/
USER root
RUN cat /etc/apt/sources.list
RUN sed -i 's/# deb-src/deb-src/' /etc/apt/sources.list
RUN cat /etc/apt/sources.list
RUN apt-get update && apt-get build-dep -y openscenegraph
USER flightgear
WORKDIR OpenSceneGraph/build
RUN cmake -D CMAKE_BUILD_TYPE="Release" -D CMAKE_CXX_FLAGS_RELEASE="-O3 -pipe" -D CMAKE_C_FLAGS_RELEASE="-O3 -pipe" -D CMAKE_PREFIX_PATH:PATH=${INSTALLPREFIX} -D CMAKE_INSTALL_PREFIX:PATH=${INSTALLPREFIX} -D CMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOLEAN="true" -G "Unix Makefiles" ..
RUN make -j $(nproc)
RUN make install
WORKDIR /home/flightgear/build/
RUN git clone https://github.com/openscenegraph/VirtualPlanetBuilder.git && cd VirtualPlanetBuilder && git checkout VirtualPlanetBuilder-1.0
RUN mkdir VirtualPlanetBuilder/build/
WORKDIR /home/flightgear/build/VirtualPlanetBuilder/build/
RUN cmake -D CMAKE_PREFIX_PATH:PATH=${INSTALLPREFIX} -D CMAKE_INSTALL_PREFIX:PATH=${INSTALLPREFIX} ..
RUN make -j $(nproc)
RUN make install
WORKDIR /home/flightgear/
COPY build/fgmeta fgmeta
FROM ubuntu:focal
LABEL maintainer="Fahim Dalvi"
LABEL version="1"
LABEL description="FlightGear WS30 VPB tools"
RUN true && \
apt-get update && \
apt-get install -y libgl1 libfontconfig libnvtt-dev libproj-dev python3 python3-pip && \
rm -rf /var/lib/apt/lists/* && \
groupadd --gid 1000 flightgear && useradd --uid 1000 --gid flightgear --create-home --home-dir=/home/flightgear --shell=/bin/bash flightgear
WORKDIR /home/flightgear
COPY --from=build /home/flightgear/dist/bin/* /usr/local/bin/
COPY --from=build /home/flightgear/dist/share/* /usr/local/share/
COPY --from=build /home/flightgear/dist/lib/* /usr/lib/
COPY --from=build /home/flightgear/dist/lib64/* /usr/lib64/
COPY --from=build /home/flightgear/fgmeta/ws30 /home/flightgear/scripts
RUN ln -s /usr/bin/python3 /usr/bin/python
USER flightgear
RUN pip install -r scripts/requirements.txt
ENV LD_LIBRARY_PATH /usr/lib64:/usr/lib
ENV GDAL_DATA /usr/local/share
CMD ["/bin/bash"]

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,32 @@
# VirtualPlanetBuilder Terrain Generation for FlightGear
This repository provides a DockerFile that can generate an image to build VPB terrain. It is currently based on the following versions:
* Ubuntu 20.04 (LTS)
* GDAL 2.4
* OpenSceneGraph 3.6.5
* VirtualPlanetBuilder 1.0
The image is available on [Docker Hub](https://hub.docker.com/r/flightgear/ws30-vbp-generator/), so docker will download it automatically when it is requested for the first time.
## Building terrain
The provided `run_image.sh` will launch a container and present a `bash` prompt with the environment for building all set up:
* GDAL and VPB executables will be available to run
* The `data` directory will be mounted at `/home/flightgear/data/` inside the container (readonly)
* The `output` directory will be mounted at `/home/flightgear/output` inside the container with write access
A sample script in `data/run.sh` is provided to automatically build a small area around Edinburgh. To build the terrain:
1. First download SRTM heightmap and CORINE landclass data (see the wiki for details: [https://wiki.flightgear.org/Virtual_Planet_Builder](https://wiki.flightgear.org/Virtual_Planet_Builder) and `data/run.sh` for links)
2. Extract the files to `./data`
3. Launch the container with `./run_image.sh`
4. Run `./data/run.sh` at the prompt. The script will saves all output to the mounted `./output` folder, so its accessible outside the container.
A shorthand for steps 3-4 is also available:
```bash
./run_image.sh ./data/run.sh
```
## Building Image locally
To build the image locally for debugging or contributing, run `build_image.sh`. This will build and tag the image with the name `flightgear/ws30-vbp-generator:v1`.

View File

@ -0,0 +1,16 @@
#!/bin/bash
# Clone fgmeta
mkdir -p build
cd build
if [ -d "fgmeta" ]; then
cd fgmeta
git pull origin next
cd ..
else
git clone --branch next https://git.code.sf.net/p/flightgear/fgmeta fgmeta
fi
cd ..
# Build docker image
docker build . -t flightgear/ws30-vbp-generator:v1.1

Some files were not shown because too many files have changed in this diff Show More