Skip to content

Commit

Permalink
build: include windows toolchain profiler (#20949)
Browse files Browse the repository at this point in the history
This commit allows any electron user to compile electron
artifacts by themselves in production mode. When the source code
is reproducibly buildable with a given toolchain this change
allows them to verify the hash of their build, with the same
windows toolchain agains the CI version.

This change was tested on top of version https://chromium.googlesource.com/chromium/src/+/fb9837799bb6388ecaee010fc80cc1438e6bb134
which was buildable and reproducible for chromium and electron as well.

Further tests may be introduced to allows checking for local reproducibility.
EG: building twice an artifact on the same machine, with different time
and output directory should yield similar hashes.
  • Loading branch information
thypon authored and zcbenz committed Nov 13, 2019
1 parent b8ee8c4 commit 97959b5
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 0 deletions.
2 changes: 2 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ build_script:
- ninja -C out/Default electron:electron_chromedriver_zip
- ninja -C out/Default third_party/electron_node:headers
- cmd /C %SCCACHE_PATH% --show-stats
- python electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
- appveyor PushArtifact out/Default/windows_toolchain_profile.json
- appveyor PushArtifact out/Default/dist.zip
- appveyor PushArtifact out/Default/shell_browser_ui_unittests.exe
- appveyor PushArtifact out/Default/chromedriver.zip
Expand Down
98 changes: 98 additions & 0 deletions build/profile_toolchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from __future__ import with_statement
import contextlib
import sys
import os
import optparse
import json

sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__)))

import find_depot_tools
from vs_toolchain import \
SetEnvironmentAndGetRuntimeDllDirs, \
SetEnvironmentAndGetSDKDir, \
GetVisualStudioVersion, \
NormalizePath

sys.path.append("%s/win_toolchain" % find_depot_tools.add_depot_tools_to_path())

from get_toolchain_if_necessary import CalculateHash


@contextlib.contextmanager
def cwd(dir):
curdir = os.getcwd()
try:
os.chdir(dir)
yield
finally:
os.chdir(curdir)


def calculate_hash(root):
with cwd(root):
return CalculateHash('.', None)

def windows_installed_software():
import win32com.client
strComputer = "."
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator")
objSWbemServices = objWMIService.ConnectServer(strComputer, "root\cimv2")
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product")
items = []

for objItem in colItems:
item = {}
if objItem.Caption:
item['caption'] = objItem.Caption
if objItem.Caption:
item['description'] = objItem.Description
if objItem.InstallDate:
item['install_date'] = objItem.InstallDate
if objItem.InstallDate2:
item['install_date_2'] = objItem.InstallDate2
if objItem.InstallLocation:
item['install_location'] = objItem.InstallLocation
if objItem.Name:
item['name'] = objItem.Name
if objItem.SKUNumber:
item['sku_number'] = objItem.SKUNumber
if objItem.Vendor:
item['vendor'] = objItem.Vendor
if objItem.Version:
item['version'] = objItem.Version
items.append(item)

return items


def windows_profile():
runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
win_sdk_dir = SetEnvironmentAndGetSDKDir()
path = NormalizePath(os.environ['GYP_MSVS_OVERRIDE_PATH'])

return {
'pwd': os.getcwd(), # since current windows executable are symbols path dependant, profile the current directory too
'installed_software': windows_installed_software(),
'sdks': [
{'name': 'vs', 'path': path, 'hash': calculate_hash(path)},
{'name': 'wsdk', 'path': win_sdk_dir, 'hash': calculate_hash(win_sdk_dir)}
],
'runtime_lib_dirs': runtime_dll_dirs,
}


def main(options):
if sys.platform == 'win32':
with open(options.output_json, 'wb') as f:
json.dump(windows_profile(), f)
else:
raise OSError("Unsupported OS")


if __name__ == '__main__':
parser = optparse.OptionParser()
parser.add_option('--output-json', metavar='FILE', default='profile.json',
help='write information about toolchain to FILE')
options, args = parser.parse_args()
sys.exit(main(options))

0 comments on commit 97959b5

Please sign in to comment.