1
0
Fork 0
flightgear/scripts/python/terrasync.py
2016-05-11 14:59:36 +02:00

168 lines
5.1 KiB
Python
Executable file

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Torsten Dreyer
#
# 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.
#
# terrasync.py - synchronize terrascenery data to your local disk
# needs dnspython (pip install dnspython)
#
# this is a terrible stub, please improve
import os
import hashlib
import urllib.request
dirindex = ".dirindex"
DIRINDEXVERSION = 1
URL="automatic"
TARGET="."
########################################################################
def fn_hash_of_file(fname):
hash = hashlib.sha1()
try:
with open(fname, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash.update(chunk)
except:
pass
return hash.hexdigest()
########################################################################
def do_download_file( _url, _path, _localfile, _hash ):
if os.path.exists( _localfile ):
h = fn_hash_of_file(_localfile)
if h == _hash:
print("hash match for ", _localfile)
return
r = urllib.request.urlopen( _url + _path )
f = open(_localfile, 'wb')
f.write( r.read() )
f.close()
print("downloaded ", _localfile, " from ", _url + _path )
########################################################################
def do_terrasync( _url, _path, _localdir ):
url = _url + _path
print("syncing ",url, " to ", _localdir )
if not os.path.exists( _localdir ):
os.makedirs( _localdir )
try:
for line in urllib.request.urlopen(url + "/.dirindex").readlines():
tokens = line.decode("utf-8").rstrip().split(':')
if( len(tokens) == 0 ):
continue
# TODO: check version number, should be equal to DIRINDEXVERSION
# otherwise complain and terminate
if( tokens[0] == "version" ):
continue
if( tokens[0] == "path" ):
continue
if( tokens[0] == "d" ):
do_terrasync( url, "/" + tokens[1], os.path.join(_localdir,tokens[1] ) )
if( tokens[0] == "f" ):
do_download_file( url, "/" + tokens[1], os.path.join(_localdir,tokens[1]), tokens[2] )
except urllib.error.HTTPError as err:
if err.code == 404 and _path == "":
# HACK: only the master on SF provides .dirindex for root, fake it if it's missing
print("Using static root hack.")
if not _url.startswith("http://flightgear.sourceforge.net/scenery") and _path == "":
for _sub in ("Models", "Terrain", "Objects", "Airports" ):
do_terrasync( _url, "/" + _sub, os.path.join(_localdir,_sub) )
return
else:
raise
#TODO: cleanup orphan files
########################################################################
import getopt, sys, random, re
try:
opts, args = getopt.getopt(sys.argv[1:], "u:t:", [ "url=", "target=" ])
except getopt.GetoptError:
print("terrasync.py [--url=http://some.server.org/scenery] [--target=/some/path]")
sys.exit(2)
for opt, arg in opts:
if opt in( "-u", "--url"):
URL = arg
elif opt in ( "-t", "--target"):
TARGET= arg
# automatic URL lookup from DNS NAPTR
# - lookup terrasync.flightgear.org, type=NAPTR, service="ws20", flags="U"
# - sort by order,preference ascending
# - pick entries with lowest order and preference
# - randomly pick one of those
# - use regexp fields URL
if URL == "automatic":
import dns.resolver
dnsResolver = dns.resolver.Resolver()
order = -1
preference = -1
# find lowes preference/order for service 'ws20' and flags 'U'
dnsAnswer = dnsResolver.query("terrasync.flightgear.org", "NAPTR" )
for naptr in dnsAnswer:
if naptr.service != b'ws20' or naptr.flags != b'U':
continue
if order == -1 or naptr.order < order:
order = naptr.order
preference = naptr.preference
if order == naptr.order:
if naptr.preference < preference:
preference = naptr.preference
# grab candidats
candidates = []
for naptr in dnsAnswer:
if naptr.service != b'ws20' or naptr.flags != b'U' or naptr.preference != preference or naptr.order != order:
continue
candidates.append( naptr.regexp.decode('utf-8') )
if not candidates:
print("sorry, no terrascenery URLs found. You may specify one with --url=http://some.url.org/foo")
sys.exit(3)
_url = random.choice(candidates)
_subst = _url.split(_url[0]) # split string, first character is separator <sep>regex<sep>replacement<sep>
URL = re.sub(_subst[1], _subst[2], "" ) # apply regex substitude on empty string
print( "terrasyncing from ", URL, "to ", TARGET )
do_terrasync( URL, "", TARGET )
########################################################################