Return update results as unified UpdateInfo objects. Prepared more
features in OptionParser.
This commit is contained in:
parent
64be0eb894
commit
319197c88b
@ -20,6 +20,8 @@ optp.add_option("-W", "--webupdater", action="store_false", dest="express", defa
|
|||||||
optp.add_option("--id", dest="unit_id", help="Specify custom Unit ID")
|
optp.add_option("--id", dest="unit_id", help="Specify custom Unit ID")
|
||||||
optp.add_option("--code", action="append", dest="unlock_codes", metavar="UNLOCK_CODE", default=[], help="Specify map unlock codes")
|
optp.add_option("--code", action="append", dest="unlock_codes", metavar="UNLOCK_CODE", default=[], help="Specify map unlock codes")
|
||||||
optp.add_option("--devicexml", dest="devicexml", metavar="FILE", help="Use specified GarminDevice.xml (also implies -E)")
|
optp.add_option("--devicexml", dest="devicexml", metavar="FILE", help="Use specified GarminDevice.xml (also implies -E)")
|
||||||
|
optp.add_option("--json", action="store_true", dest="json", default=False, help="Output JSON")
|
||||||
|
optp.add_option("--list-devices", action="store_true", dest="list_devices", default=False, help="Show a list of SKUs and product names")
|
||||||
|
|
||||||
optp.usage = """
|
optp.usage = """
|
||||||
%prog [options] SKU1 [SKU2..SKUn]
|
%prog [options] SKU1 [SKU2..SKUn]
|
||||||
|
@ -7,7 +7,7 @@ See https://github.com/AlexWhiter/GarminRelatedStuff/tree/master/GetFirmwareUpda
|
|||||||
|
|
||||||
from . import devices
|
from . import devices
|
||||||
from .proto import GetAllUnitSoftwareUpdates_pb2
|
from .proto import GetAllUnitSoftwareUpdates_pb2
|
||||||
from xml.dom.minidom import getDOMImplementation
|
from xml.dom.minidom import getDOMImplementation, parseString
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
PROTO_API_GETALLUNITSOFTWAREUPDATES_URL = "http://omt.garmin.com/Rce/ProtobufApi/SoftwareUpdateService/GetAllUnitSoftwareUpdates"
|
PROTO_API_GETALLUNITSOFTWAREUPDATES_URL = "http://omt.garmin.com/Rce/ProtobufApi/SoftwareUpdateService/GetAllUnitSoftwareUpdates"
|
||||||
@ -16,8 +16,85 @@ GRMN_CLIENT_VERSION = "6.17.0.0"
|
|||||||
|
|
||||||
class UpdateInfo:
|
class UpdateInfo:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.source = None
|
||||||
|
self.sku = None
|
||||||
|
self.device_name = None
|
||||||
|
self.fw_version = None
|
||||||
|
self.license_url = None
|
||||||
|
self.changelog = None
|
||||||
|
self.notes = None
|
||||||
|
self.language_code = None
|
||||||
|
self.update_type = None
|
||||||
|
self.local_filename = None
|
||||||
|
self.files = []
|
||||||
|
self.build_type = None
|
||||||
|
self.additional_info_url = None
|
||||||
|
|
||||||
|
def fill_from_protobuf(self, protobuf_info):
|
||||||
|
self.source = "Express"
|
||||||
|
self.sku = protobuf_info.product_sku
|
||||||
|
self.device_name = protobuf_info.device_name
|
||||||
|
self.fw_version = protobuf_info.fw_version
|
||||||
|
self.license_url = protobuf_info.license_url
|
||||||
|
self.changelog = "\n".join(protobuf_info.changelog)
|
||||||
|
self.language_code = protobuf_info.language
|
||||||
|
self.local_filename = protobuf_info.update_file
|
||||||
|
self.update_type = protobuf_info.file_type
|
||||||
|
for i in protobuf_info.files_list:
|
||||||
|
self.files.append( {
|
||||||
|
"url": i.url,
|
||||||
|
"md5": i.md5,
|
||||||
|
"size": i.file_size,
|
||||||
|
"size_is_rounded": False,
|
||||||
|
} )
|
||||||
|
|
||||||
|
# From https://docs.python.org/3/library/xml.dom.minidom.html
|
||||||
|
def dom_get_text(self, node_list):
|
||||||
|
rc = []
|
||||||
|
for rnode in node_list:
|
||||||
|
for node in rnode.childNodes:
|
||||||
|
if node.nodeType == node.TEXT_NODE:
|
||||||
|
rc.append(node.data)
|
||||||
|
return ''.join(rc)
|
||||||
|
|
||||||
|
def fill_from_response_dom(self, dom):
|
||||||
|
self.source = "WebUpdater"
|
||||||
|
self.sku = self.dom_get_text(dom.getElementsByTagName("RequestedPartNumber"))
|
||||||
|
self.device_name = self.dom_get_text(dom.getElementsByTagName("Description"))
|
||||||
|
version_major = self.dom_get_text(dom.getElementsByTagName("VersionMajor"))
|
||||||
|
version_minor = self.dom_get_text(dom.getElementsByTagName("VersionMinor"))
|
||||||
|
self.fw_version = "{}.{:0>2s}".format(version_major, version_minor)
|
||||||
|
self.license_url = self.dom_get_text(dom.getElementsByTagName("LicenseLocation"))
|
||||||
|
self.changelog = self.dom_get_text(dom.getElementsByTagName("ChangeDescription"))
|
||||||
|
self.notes = self.dom_get_text(dom.getElementsByTagName("Notes"))
|
||||||
|
self.language_code = self.dom_get_text(dom.getElementsByTagName("RequestedRegionId"))
|
||||||
|
self.build_type = self.dom_get_text(dom.getElementsByTagName("BuildType"))
|
||||||
|
self.additional_info_url = self.dom_get_text(dom.getElementsByTagName("AdditionalInfo"))
|
||||||
|
files = dom.getElementsByTagName("UpdateFile")
|
||||||
|
for f in files:
|
||||||
|
# For some reason, WebUpdater returns file size in KiB instead of Bytes
|
||||||
|
size_kb = self.dom_get_text(f.getElementsByTagName("Size"))
|
||||||
|
size_bytes = float(size_kb) * 1024
|
||||||
|
self.files.append( {
|
||||||
|
"url": self.dom_get_text(f.getElementsByTagName("Location")),
|
||||||
|
"md5": self.dom_get_text(f.getElementsByTagName("MD5Sum")),
|
||||||
|
"size": size_bytes,
|
||||||
|
"size_is_rounded": True,
|
||||||
|
} )
|
||||||
|
|
||||||
|
def get_json(self):
|
||||||
|
# TODO
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
url = "-"
|
||||||
|
if len(self.files) > 0:
|
||||||
|
url = self.files[0]["url"]
|
||||||
|
return "[{}] {} {} {}: {}".format(self.source, self.sku, self.device_name, self.fw_version, url)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "[{}] {} {} {}".format(self.source, self.sku, self.device_name, self.fw_version)
|
||||||
|
|
||||||
class UpdateServer:
|
class UpdateServer:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -29,13 +106,30 @@ class UpdateServer:
|
|||||||
# Garmin Express Protobuf API
|
# Garmin Express Protobuf API
|
||||||
device_xml = self.get_device_xml(sku_numbers)
|
device_xml = self.get_device_xml(sku_numbers)
|
||||||
reply = self.get_unit_updates(device_xml)
|
reply = self.get_unit_updates(device_xml)
|
||||||
return reply
|
results = []
|
||||||
|
for i in range(0, len(reply.update_info)):
|
||||||
|
ui = reply.update_info[i]
|
||||||
|
r = UpdateInfo()
|
||||||
|
r.fill_from_protobuf(ui)
|
||||||
|
results.append(r)
|
||||||
|
return results
|
||||||
|
|
||||||
def query_webupdater(self, sku_numbers):
|
def query_webupdater(self, sku_numbers):
|
||||||
# WebUpdater
|
# WebUpdater
|
||||||
requests_xml = self.get_requests_xml(sku_numbers)
|
requests_xml = self.get_requests_xml(sku_numbers)
|
||||||
reply = self.get_webupdater_softwareupdate(requests_xml)
|
reply = self.get_webupdater_softwareupdate(requests_xml)
|
||||||
return reply
|
|
||||||
|
# ElementTree might have been easier if it wouldn't be so obnoxious with namespaces
|
||||||
|
# See https://stackoverflow.com/questions/14853243/parsing-xml-with-namespace-in-python-via-elementtree
|
||||||
|
dom = parseString(reply)
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for resp in dom.getElementsByTagName("Response"):
|
||||||
|
r = UpdateInfo()
|
||||||
|
r.fill_from_response_dom(resp)
|
||||||
|
results.append(r)
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
def query_updates(self, sku_numbers, query_express=True, query_webupdater=True):
|
def query_updates(self, sku_numbers, query_express=True, query_webupdater=True):
|
||||||
results = []
|
results = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user