/usr/bin/lensfun-update-data is in liblensfun-bin 0.3.2-3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This program fetches the latest version of the Lensfun database from the
Internet and places it on the local system. This way, the user can update the
database conveniently. Unfortunately, we have to take into account that the
Git database may have a too new format for the locally installed Lensfun.
Then, it may fetch backports of the database from other URLs.
This program must be called with root privileges. It stores the new database
in `/var/lib/lensfun-updates`.
The repository of databases resides at a base URL. Below that URL, there is
the file versions.json. It contains a list with three elements. The first is
the database timestamp, the second is a list of available version numbers, and
the third is a list of strings which represents further alternative base URLs
to look at. So, the file may contain the following::
[1386797501, [1, 2, 3], ["http://wilson.bronger.org/"]]
All URLs must end with a slash. For every version number, there must be a file
called version_<versionnumber>.tar.bz2. So in our case, there must be the
files
::
version_1.tar.bz2
version_2.tar.bz2
version_3.tar.bz2
in the same directory as versions.json. These tar balls contain the Lensfun
database with the given timestamp and version.
The timestamps are the number of seconds since the Epoch as an int.
Diagnostics:
Status code 0 -- successfully installed updates
1 -- no newer upstream database found for last installed Lensfun
3 -- no location was responsive; maybe network problems
"""
import urllib.request, shutil, sys, os, time, calendar, tarfile, json, glob
import lensfun
database_version = lensfun.get_database_version()
lensfun_updates_dir = "/var/lib/lensfun-updates"
if os.name == "posix" and os.geteuid() != 0:
lensfun_updates_dir = os.path.join(os.path.expanduser("~"),
".local", "share", "lensfun", "updates")
print("Info: root privileges needed for updating the system database.")
print("Info: updating user DB in '%s'" % lensfun_updates_dir)
def seconds_since_epoch():
return calendar.timegm(time.gmtime())
def detect_local_timestamp(version):
if version == database_version:
return lensfun.get_core_database()[0]
def detect_single_timestamp(path):
try:
return int(open(os.path.join(path, "version_{}".format(version), "timestamp.txt")).read())
except (FileNotFoundError, ValueError):
return 0
directory_candidates = {"/usr/share/lensfun", "/usr/local/share/lensfun",
"/var/lib/lensfun-updates", os.path.expanduser("~/.local/share/lensfun/updates")}
return max(map(detect_single_timestamp, directory_candidates))
class Location:
def __init__(self, base_url, version, timestamp):
self.base_url, self.version, self.timestamp = base_url, version, timestamp
def __lt__(self, other):
return self.timestamp < other.timestamp
def extract(self, directory):
tar = tarfile.open(fileobj=urllib.request.urlopen(self.base_url + "version_{}.tar.bz2".format(self.version)),
mode="r|*")
tar.extractall(directory)
tar.close()
def detect_local_database_versions():
versions = {database_version}
for directory in glob.glob("/usr/share/lensfun/version_*") + glob.glob("/usr/local/share/lensfun/version_*"):
if os.path.isdir(directory):
try:
versions.add(int(directory.partition("version_")[2]))
except ValueError:
pass
return versions
local_database_versions = detect_local_database_versions()
locations = {version: set() for version in local_database_versions}
local_timestamps = {version: detect_local_timestamp(version) for version in local_database_versions}
seen_urls = set()
at_least_one_responsive_location = False
def read_location(base_url):
global at_least_one_responsive_location
if base_url not in seen_urls and len(seen_urls) < 50:
seen_urls.add(base_url)
print("Reading {} …".format(base_url + "versions.json"))
try:
response = urllib.request.urlopen(base_url + "versions.json")
except (urllib.error.HTTPError, ValueError):
print(" Error: URL could not be opened.")
else:
try:
timestamp, versions, alternatives = json.loads(response.read().decode("utf-8"))
except ValueError:
print(" Error: Invalid data received.")
else:
at_least_one_responsive_location = True
versions = set(versions) & set(locations)
for version in versions:
if timestamp > local_timestamps[version]:
locations[version].add(Location(base_url, version, timestamp))
for base_url in alternatives:
read_location(base_url)
read_location("http://lensfun.sourceforge.net/db/")
read_location("http://wilson.bronger.org/lensfun-db/")
if not at_least_one_responsive_location:
print("Fatal: No location was responsive. Network down?")
sys.exit(3)
elif not locations[database_version]:
print("Info: No newer database was found for last installed Lensfun.")
sys.exit(1)
for version, location_list in locations.items():
try:
best_location = max(location_list)
except ValueError:
continue
updates_dir = os.path.join(lensfun_updates_dir, "version_{}".format(version))
shutil.rmtree(updates_dir, ignore_errors=True)
os.makedirs(updates_dir)
best_location.extract(updates_dir)
open(os.path.join(updates_dir, "timestamp.txt"), "w").write(str(best_location.timestamp))
print("Successfully updated the database in " + updates_dir + ".")
|