Hide keyboard shortcuts

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. 

6 

7import sys 

8import os 

9import socket 

10import platform 

11 

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 

16 

17XPRA_VERSION = xpra.__version__ #@UndefinedVariable 

18 

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) 

28 

29 

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) 

34 

35 

36def full_version_str() -> str: 

37 rstr = revision_str() 

38 return XPRA_VERSION if not rstr else XPRA_VERSION+"-"+rstr 

39 

40def caps_to_version(caps : typedict) -> str: 

41 return caps.strget("version")+"-"+caps_to_revision(caps) 

42 

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) 

49 

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 "" 

58 

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 

70 

71 

72 

73def version_as_numbers(version : str): 

74 return [int(x) for x in version.split(".")] 

75 

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 

96 

97 

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 

127 

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 

143 

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 

170 

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 

217 

218 

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 

239 

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