22"""
33This script is for generating MSI packages
44for Windows users.
5+
6+ To generate a self-signed certificate for code signing:
7+
8+ openssl genrsa -out code-signing.key 2048
9+ openssl req -new -key code-signing.key -out code-signing.csr
10+ openssl x509 -req -days 365 -in code-signing.csr -signkey code-signing.key -out code-signing.crt
11+ openssl pkcs12 -export -out code-signing.pfx -inkey code-signing.key -in code-signing.crt -name "ABCodeSigningCert"
512"""
13+ import logging
614import os
715import shutil
816import subprocess
1321
1422sys .path .append (os .getcwd ())
1523
24+ # sometimes the signing tool exe is not on PATH, so allow user to set env to it
25+ WINDOWS_SDK_BIN = os .environ .get ("WINDOWS_SDK_BIN" , "" )
1626# Elementtree does not support CDATA. So hack it.
1727WINVER_CHECK = "Installed OR (VersionNT64 > 602)>"
28+ logger = logging .getLogger (__name__ )
1829
1930
2031def gen_guid ():
@@ -55,17 +66,17 @@ class PackageGenerator:
5566 Package generator for MSI packages
5667 """
5768
58- def __init__ (self ):
69+ def __init__ (self , signing_certificate = None , version = None ):
5970 self .product_name = "Activity Browser"
6071 self .manufacturer = "The Activity Browser Team"
61- self .version = os .environ .get ("VERSION" , "0.0.0" )
72+ self .version = version or os .environ .get ("VERSION" , "0.0.0" )
6273 if "-" in self .version :
63- versions = self .version .split ("-" )
74+ versions = self .version .split ("-" )
6475 self .version = "{}.{}" .format (versions [0 ], versions [1 ])
6576 print ("Using version {} instead" .format (self .version ))
6677 self .root = None
6778 self .guid = "*"
68- self .update_guid = "141527EE-E28A-4D14-97A4-92E6075D28B2 "
79+ self .update_guid = "728A617A-4F3F-49BB-B9E5-5D02F037B67B "
6980 self .main_xml = "activitybrowser.wxs"
7081 self .main_o = "activitybrowser.wixobj"
7182 self .final_output = "activitybrowser-{}-64.msi" .format (self .version )
@@ -100,6 +111,7 @@ def __init__(self):
100111 self .feature_components = {}
101112 for s_d in self .staging_dirs :
102113 self .feature_components [s_d ] = []
114+ self .signing_certificate = signing_certificate
103115
104116 def build_dist (self ):
105117 """
@@ -121,7 +133,7 @@ def build_dist(self):
121133 pyinst_cmd = [
122134 pyinstaller ,
123135 "activity-browser.spec" ,
124- # "--clean",
136+ "--clean" ,
125137 "--distpath" ,
126138 pyinstaller_tmpdir ,
127139 ]
@@ -131,6 +143,25 @@ def build_dist(self):
131143 if not os .path .exists (os .path .join (main_stage , "activity-browser.exe" )):
132144 sys .exit ("activity-browser exe missing from staging dir." )
133145
146+ self .sign_files (os .path .join (main_stage , "*.exe" ))
147+
148+ def sign_files (self , pattern : str ):
149+ if self .signing_certificate is None :
150+ return
151+ for file in glob (pattern ):
152+ logger .info ("Signing file: %s" , file )
153+ subprocess .check_call ([
154+ os .path .join (WINDOWS_SDK_BIN , 'signtool' ),
155+ 'sign' ,
156+ '/fd' ,
157+ 'SHA256' ,
158+ '/t' ,
159+ 'http://timestamp.digicert.com' ,
160+ '/f' ,
161+ self .signing_certificate ,
162+ file
163+ ])
164+
134165 def del_infodirs (self , dirname ):
135166 # Starting with 3.9.something there are some
136167 # extra metadatadirs that have a hyphen in their
@@ -452,6 +483,7 @@ def build_package(self):
452483 self .main_xml ,
453484 ]
454485 )
486+ self .sign_files ("*.msi" )
455487
456488
457489def install_wix ():
@@ -475,14 +507,21 @@ def install_wix():
475507
476508
477509if __name__ == "__main__" :
510+ import argparse
511+
512+ parser = argparse .ArgumentParser ()
513+ parser .add_argument ("--signing-certificate" , help = "local signing certificate (pfx format)" )
514+ parser .add_argument ("--version" , help = "version that the msi will be" )
515+ options = parser .parse_args ()
516+
478517 if not os .path .exists ("activity-browser.spec" ):
479518 sys .exit (print ("Run me in the top level source dir." ))
480519 if not shutil .which ("wix" ):
481520 install_wix ()
482521 if not shutil .which ("pyinstaller" ):
483522 subprocess .check_call (["pip" , "install" , "--upgrade" , "pyinstaller" ])
484523
485- p = PackageGenerator ()
524+ p = PackageGenerator (** options . __dict__ )
486525 p .build_dist ()
487526 p .generate_files ()
488527 p .build_package ()
0 commit comments