diff options
author | Calum Lind <calumlind+deluge@gmail.com> | 2015-08-23 19:28:17 +0100 |
---|---|---|
committer | Calum Lind <calumlind+deluge@gmail.com> | 2015-08-24 14:56:53 +0100 |
commit | 0ee8c7d70f54af976bac772eba937c83a2968718 (patch) | |
tree | f7eb9baf0a59c5a96379e48ae8d95f57c0fc86e4 /packaging | |
parent | c55a601db9cb34be05116180a459044f984c5682 (diff) | |
download | deluge-0ee8c7d70f54af976bac772eba937c83a2968718.tar.gz deluge-0ee8c7d70f54af976bac772eba937c83a2968718.tar.bz2 deluge-0ee8c7d70f54af976bac772eba937c83a2968718.zip |
[#2736] [Win32] Add version info to exe files
Diffstat (limited to 'packaging')
-rw-r--r-- | packaging/win32/VersionInfo.py | 292 | ||||
-rw-r--r-- | packaging/win32/deluge-bbfreeze.py | 17 |
2 files changed, 309 insertions, 0 deletions
diff --git a/packaging/win32/VersionInfo.py b/packaging/win32/VersionInfo.py new file mode 100644 index 000000000..fbbc9eb91 --- /dev/null +++ b/packaging/win32/VersionInfo.py @@ -0,0 +1,292 @@ +# -*- coding: latin-1 -*- +## +## Copyright (c) 2000-2013 Thomas Heller +## +## Permission is hereby granted, free of charge, to any person obtaining +## a copy of this software and associated documentation files (the +## "Software"), to deal in the Software without restriction, including +## without limitation the rights to use, copy, modify, merge, publish, +## distribute, sublicense, and/or sell copies of the Software, and to +## permit persons to whom the Software is furnished to do so, subject to +## the following conditions: +## +## The above copyright notice and this permission notice shall be +## included in all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +## LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +## OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +## WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +## + +# +# $Id: VersionInfo.py 738 2013-09-07 10:11:45Z theller $ +# +# $Log$ +# Revision 1.3 2004/01/16 10:45:31 theller +# Move py2exe from the sandbox directory up to the root dir. +# +# Revision 1.3 2003/12/29 13:44:57 theller +# Adapt for Python 2.3. +# +# Revision 1.2 2003/09/18 20:19:57 theller +# Remove a 2.3 warning, but mostly this checkin is to test the brand new +# py2exe-checkins mailing list. +# +# Revision 1.1 2003/08/29 12:30:52 mhammond +# New py2exe now uses the old resource functions :) +# +# Revision 1.1 2002/01/29 09:30:55 theller +# version 0.3.0 +# +# Revision 1.2 2002/01/14 19:08:05 theller +# Better (?) Unicode handling. +# +# Revision 1.1 2002/01/07 10:30:32 theller +# Create a version resource. +# +# +import struct + +VOS_NT_WINDOWS32 = 0x00040004 +VFT_APP = 0x00000001 + +RT_VERSION = 16 + +class VersionError(Exception): + pass + +def w32_uc(text): + """convert a string into unicode, then encode it into UTF-16 + little endian, ready to use for win32 apis""" + if type(text) is str: + return unicode(text, "unicode-escape").encode("utf-16-le") + return unicode(text).encode("utf-16-le") + +class VS_FIXEDFILEINFO: + dwSignature = 0xFEEF04BDL + dwStrucVersion = 0x00010000 + dwFileVersionMS = 0x00010000 + dwFileVersionLS = 0x00000001 + dwProductVersionMS = 0x00010000 + dwProductVersionLS = 0x00000001 + dwFileFlagsMask = 0x3F + dwFileFlags = 0 + dwFileOS = VOS_NT_WINDOWS32 + dwFileType = VFT_APP + dwFileSubtype = 0 + dwFileDateMS = 0 + dwFileDateLS = 0 + + fmt = "13L" + + def __init__(self, version): + import string + version = string.replace(version, ",", ".") + fields = string.split(version + '.0.0.0.0', ".")[:4] + fields = map(string.strip, fields) + try: + self.dwFileVersionMS = int(fields[0]) * 65536 + int(fields[1]) + self.dwFileVersionLS = int(fields[2]) * 65536 + int(fields[3]) + except ValueError: + raise VersionError("could not parse version number '%s'" % version) + + def __str__(self): + return struct.pack(self.fmt, + self.dwSignature, + self.dwStrucVersion, + self.dwFileVersionMS, + self.dwFileVersionLS, + self.dwProductVersionMS, + self.dwProductVersionLS, + self.dwFileFlagsMask, + self.dwFileFlags, + self.dwFileOS, + self.dwFileType, + self.dwFileSubtype, + self.dwFileDateMS, + self.dwFileDateLS) + +def align(data): + pad = - len(data) % 4 + return data + '\000' * pad + +class VS_STRUCT: + items = () + + def __str__(self): + szKey = w32_uc(self.name) + ulen = len(szKey)+2 + + value = self.get_value() + data = struct.pack("h%ss0i" % ulen, self.wType, szKey) + value + + data = align(data) + + for item in self.items: + data = data + str(item) + + wLength = len(data) + 4 # 4 bytes for wLength and wValueLength + wValueLength = len(value) + + return self.pack("hh", wLength, wValueLength, data) + + def pack(self, fmt, len, vlen, data): + return struct.pack(fmt, len, vlen) + data + + def get_value(self): + return "" + + +class String(VS_STRUCT): + wType = 1 + items = () + + def __init__(self, name_value): + (name, value) = name_value + self.name = name + if value: + self.value = value + '\000' # strings must be zero terminated + else: + self.value = value + + def pack(self, fmt, len, vlen, data): + # ValueLength is measured in WORDS, not in BYTES! + return struct.pack(fmt, len, vlen/2) + data + + def get_value(self): + return w32_uc(self.value) + + +class StringTable(VS_STRUCT): + wType = 1 + + def __init__(self, name, strings): + self.name = name + self.items = map(String, strings) + + +class StringFileInfo(VS_STRUCT): + wType = 1 + name = "StringFileInfo" + + def __init__(self, name, strings): + self.items = [StringTable(name, strings)] + +class Var(VS_STRUCT): + # MSDN says: + # If you use the Var structure to list the languages your + # application or DLL supports instead of using multiple version + # resources, use the Value member to contain an array of DWORD + # values indicating the language and code page combinations + # supported by this file. The low-order word of each DWORD must + # contain a Microsoft language identifier, and the high-order word + # must contain the IBM® code page number. Either high-order or + # low-order word can be zero, indicating that the file is language + # or code page independent. If the Var structure is omitted, the + # file will be interpreted as both language and code page + # independent. + wType = 0 + name = "Translation" + + def __init__(self, value): + self.value = value + + def get_value(self): + return struct.pack("l", self.value) + +class VarFileInfo(VS_STRUCT): + wType = 1 + name = "VarFileInfo" + + def __init__(self, *names): + self.items = map(Var, names) + + def get_value(self): + return "" + +class VS_VERSIONINFO(VS_STRUCT): + wType = 0 # 0: binary data, 1: text data + name = "VS_VERSION_INFO" + + def __init__(self, version, items): + self.value = VS_FIXEDFILEINFO(version) + self.items = items + + def get_value(self): + return str(self.value) + +class Version(object): + def __init__(self, + version, + comments = None, + company_name = None, + file_description = None, + internal_name = None, + legal_copyright = None, + legal_trademarks = None, + original_filename = None, + private_build = None, + product_name = None, + product_version = None, + special_build = None): + self.version = version + strings = [] + if comments is not None: + strings.append(("Comments", comments)) + if company_name is not None: + strings.append(("CompanyName", company_name)) + if file_description is not None: + strings.append(("FileDescription", file_description)) + strings.append(("FileVersion", version)) + if internal_name is not None: + strings.append(("InternalName", internal_name)) + if legal_copyright is not None: + strings.append(("LegalCopyright", legal_copyright)) + if legal_trademarks is not None: + strings.append(("LegalTrademarks", legal_trademarks)) + if original_filename is not None: + strings.append(("OriginalFilename", original_filename)) + if private_build is not None: + strings.append(("PrivateBuild", private_build)) + if product_name is not None: + strings.append(("ProductName", product_name)) + strings.append(("ProductVersion", product_version or version)) + if special_build is not None: + strings.append(("SpecialBuild", special_build)) + self.strings = strings + + def resource_bytes(self): + vs = VS_VERSIONINFO(self.version, + [StringFileInfo("040904B0", + self.strings), + VarFileInfo(0x04B00409)]) + return str(vs) + +def test(): + import sys + sys.path.append("c:/tmp") + from hexdump import hexdump + version = Version("1, 0, 0, 1", + comments = "ümläut comments", + company_name = "No Company", + file_description = "silly application", + internal_name = "silly", + legal_copyright = u"Copyright © 2003", +## legal_trademark = "", + original_filename = "silly.exe", + private_build = "test build", + product_name = "silly product", + product_version = None, +## special_build = "" + ) + hexdump(version.resource_bytes()) + +if __name__ == '__main__': + import sys + sys.path.append("d:/nbalt/tmp") + from hexdump import hexdump + test() diff --git a/packaging/win32/deluge-bbfreeze.py b/packaging/win32/deluge-bbfreeze.py index 8d8e1829f..7b2d2f0e3 100644 --- a/packaging/win32/deluge-bbfreeze.py +++ b/packaging/win32/deluge-bbfreeze.py @@ -6,7 +6,9 @@ import sys import bbfreeze.recipes import gtk import icon +import win32api from bbfreeze import Freezer +from VersionInfo import Version import deluge.common @@ -61,6 +63,21 @@ icon_path = os.path.join(os.path.dirname(__file__), "deluge.ico") for script in console_scripts + gui_scripts: icon.CopyIcons(dst + script + ".exe", icon_path) +# Add version information to exe files. +for script in console_scripts + gui_scripts: + script_exe = script + ".exe" + version = Version(build_version, + file_description="Deluge Bittorrent Client", + company_name="Deluge Team", + legal_copyright="GPLv3", + original_filename=script_exe, + product_name="Deluge", + product_version=build_version) + + pyhandle = win32api.BeginUpdateResource(os.path.join(dst, script_exe), 0) + win32api.UpdateResource(pyhandle, 16, 1, version.resource_bytes()) + win32api.EndUpdateResource(pyhandle, 0) + # exclude files which are already included in GTK or Windows excludeDlls = ("MSIMG32.dll", "MSVCR90.dll", "MSVCP90.dll", "POWRPROF.dll", "DNSAPI.dll", "USP10.dll") for file in excludeDlls: |