Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/version_util.py : 52%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
2# This file is part of Xpra.
3# Copyright (C) 2011-2021 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7import sys
8import os
9import socket
10import platform
12#tricky: use xpra.scripts.config to get to the python "platform" module
13import xpra
14from xpra.util import updict, envbool, obsc, typedict, get_util_logger
15from xpra.os_util import get_linux_distribution, BITS, POSIX, WIN32
17XPRA_VERSION = xpra.__version__ #@UndefinedVariable
19CHECK_SSL = envbool("XPRA_VERSION_CHECK_SSL", True)
20SSL_CAFILE = None
21if WIN32:
22 try:
23 import certifi #@UnresolvedImport
24 SSL_CAFILE = certifi.where()
25 except (ImportError, AttributeError):
26 get_util_logger().error("failed to locate SSL ca file", exc_info=True)
27SSL_CAFILE = os.environ.get("XPRA_SSL_CAFILE", SSL_CAFILE)
30def log(msg, *args, **kwargs):
31 get_util_logger().debug(msg, *args, **kwargs)
32def warn(msg, *args, **kwargs):
33 get_util_logger().warn(msg, *args, **kwargs)
36def full_version_str() -> str:
37 rstr = revision_str()
38 return XPRA_VERSION if not rstr else XPRA_VERSION+"-"+rstr
40def caps_to_version(caps : typedict) -> str:
41 return caps.strget("version")+"-"+caps_to_revision(caps)
43def caps_to_revision(caps : typedict) -> str:
44 revision = caps.strget("revision")
45 local_modifications = caps.intget("local_modifications")
46 commit = caps.strget("commit")
47 branch = caps.strget("branch")
48 return make_revision_str(revision, local_modifications, branch, commit)
50def revision_str() -> str:
51 try:
52 from xpra.src_info import REVISION, LOCAL_MODIFICATIONS, BRANCH, COMMIT #pylint: disable=import-outside-toplevel
53 except ImportError:
54 pass
55 else:
56 return make_revision_str(REVISION, LOCAL_MODIFICATIONS, BRANCH, COMMIT)
57 return ""
59def make_revision_str(revision, local_modifications, branch, commit) -> str:
60 rstr = ""
61 try:
62 rstr += "r"+revision
63 if local_modifications>0:
64 rstr += "M"
65 if branch=="master" and commit:
66 rstr += " (%s)" % commit
67 except TypeError:
68 pass
69 return rstr
73def version_as_numbers(version : str):
74 return [int(x) for x in version.split(".")]
76def version_compat_check(remote_version : str):
77 if remote_version is None:
78 msg = "remote version not available!"
79 log(msg)
80 return msg
81 rv = version_as_numbers(remote_version)
82 lv = version_as_numbers(XPRA_VERSION)
83 if rv==lv:
84 log("identical remote version: %s", remote_version)
85 return None
86 if rv[0:3]<[0, 14, 10]:
87 #this is the oldest version we support
88 msg = "remote version %s is too old, sorry" % str(rv[:2])
89 log(msg)
90 return msg
91 if rv[0]>0:
92 log("newer remote version %s may work, we'll see..", remote_version)
93 return None
94 log("local version %s should be compatible with remote version: %s", XPRA_VERSION, remote_version)
95 return None
98def get_host_info(obfuscate=False) -> dict:
99 #this function is for non UI thread info
100 info = {
101 "pid" : os.getpid(),
102 "byteorder" : sys.byteorder,
103 "python" : {
104 "bits" : BITS,
105 "full_version" : sys.version,
106 "version" : ".".join(str(x) for x in sys.version_info[:3]),
107 },
108 }
109 try:
110 hostname = socket.gethostname()
111 if obfuscate and hostname.find(".")>0:
112 parts = hostname.split(".")
113 for i, part in enumerate(parts):
114 if i>0:
115 parts[i] = obsc(part)
116 hostname = ".".join(parts)
117 if hostname:
118 info["hostname"] = hostname
119 except OSError:
120 pass
121 if POSIX:
122 info.update({
123 "uid" : os.getuid(),
124 "gid" : os.getgid(),
125 })
126 return info
128def get_version_info() -> dict:
129 props = {
130 "version" : XPRA_VERSION
131 }
132 try:
133 from xpra.src_info import LOCAL_MODIFICATIONS, REVISION, COMMIT, BRANCH
134 props.update({
135 "local_modifications" : LOCAL_MODIFICATIONS,
136 "revision" : REVISION,
137 "branch" : BRANCH,
138 "commit" : COMMIT,
139 })
140 except ImportError as e:
141 warn("missing some source information: %s", e)
142 return props
144def get_version_info_full() -> dict:
145 props = get_version_info()
146 try:
147 from xpra import build_info
148 #rename these build info properties:
149 for k,bk in {
150 "date" : "BUILD_DATE",
151 "time" : "BUILD_TIME",
152 "bit" : "BUILD_BIT",
153 "cpu" : "BUILD_CPU",
154 "compiler" : "COMPILER_VERSION",
155 "nvcc" : "NVCC_VERSION",
156 "linker" : "LINKER_VERSION",
157 "python" : "PYTHON_VERSION",
158 "cython" : "CYTHON_VERSION",
159 }.items():
160 v = getattr(build_info, bk, None)
161 if v:
162 props[k] = v
163 #record library versions:
164 d = dict((k.lstrip("lib_"), getattr(build_info, k)) for k in dir(build_info) if k.startswith("lib_"))
165 updict(props, "lib", d)
166 except Exception as e:
167 warn("missing some build information: %s", e)
168 log("get_version_info_full()=%s", props)
169 return props
171def do_get_platform_info() -> dict:
172 from xpra.os_util import platform_name, platform_release
173 pp = sys.modules.get("platform", platform)
174 def get_processor_name():
175 if pp.system() == "Windows":
176 return pp.processor()
177 if pp.system() == "Darwin":
178 os.environ['PATH'] = os.environ['PATH'] + os.pathsep + '/usr/sbin'
179 command = ["sysctl", "-n", "machdep.cpu.brand_string"]
180 import subprocess
181 return subprocess.check_output(command).strip()
182 if pp.system() == "Linux":
183 with open("/proc/cpuinfo") as f:
184 data = f.read()
185 import re
186 for line in data.split("\n"):
187 if "model name" in line:
188 return re.sub(".*model name.*:", "", line,1).strip()
189 return pp.processor()
190 info = {}
191 ld = get_linux_distribution()
192 if ld:
193 info["linux_distribution"] = ld
194 try:
195 release = platform_release(pp.release())
196 except OSError:
197 log("do_get_platform_info()", exc_info=True)
198 release = "unknown"
199 info.update({
200 "" : sys.platform,
201 "name" : platform_name(sys.platform, info.get("linux_distribution") or release),
202 "release" : pp.release(),
203 "sysrelease": release,
204 "platform" : pp.platform(),
205 "machine" : pp.machine(),
206 "architecture" : pp.architecture(),
207 "processor" : get_processor_name(),
208 })
209 return info
210#cache the output:
211platform_info_cache = None
212def get_platform_info():
213 global platform_info_cache
214 if platform_info_cache is None:
215 platform_info_cache = do_get_platform_info()
216 return platform_info_cache
219def get_version_from_url(url):
220 e = None
221 try:
222 from urllib.request import urlopen
223 except ImportError:
224 log("get_version_from_url(%s) urllib2 not found: %s", url, e)
225 return None
226 try:
227 response = urlopen(url, cafile=SSL_CAFILE)
228 latest_version = response.read().rstrip(b"\n\r")
229 latest_version_no = tuple(int(y) for y in latest_version.split(b"."))
230 log("get_version_from_url(%s)=%s", url, latest_version_no)
231 return latest_version_no
232 except Exception as e:
233 log("get_version_from_url(%s)", url, exc_info=True)
234 if getattr(e, "code", 0)==404:
235 log("no version at url=%s", url)
236 else:
237 log("Error retrieving URL '%s': %s", url, e)
238 return None
240def version_update_check():
241 FAKE_NEW_VERSION = envbool("XPRA_FAKE_NEW_VERSION", False)
242 CURRENT_VERSION_URL = "%s://xpra.org/CURRENT_VERSION" % ("https" if CHECK_SSL else "http")
243 PLATFORM_FRIENDLY_NAMES = {
244 "linux2" : "LINUX",
245 "win" : "WINDOWS",
246 "darwin" : "OSX",
247 }
248 our_version_no = tuple(int(y) for y in XPRA_VERSION.split("."))
249 platform_name = PLATFORM_FRIENDLY_NAMES.get(sys.platform, sys.platform)
250 arch = get_platform_info().get("machine")
251 latest_version_no = None
252 for url in (
253 "%s_%s_%s?%s" % (CURRENT_VERSION_URL, platform_name, arch, XPRA_VERSION),
254 "%s_%s?%s" % (CURRENT_VERSION_URL, platform_name, XPRA_VERSION),
255 "%s?%s" % (CURRENT_VERSION_URL, XPRA_VERSION),
256 ):
257 latest_version_no = get_version_from_url(url)
258 if latest_version_no:
259 break
260 if latest_version_no is None:
261 log("version_update_check() failed to contact version server")
262 return None
263 if latest_version_no>our_version_no or FAKE_NEW_VERSION:
264 log("version_update_check() newer version found! local version is %s and the latest version available is %s",
265 our_version_no, latest_version_no)
266 #latest_version = ".".join([str(x) for x in latest_version_no])
267 return latest_version_no
268 return False