Codesign: Add codesign for macOS worker

Works similarly to Windows configuration where buildbot worker and
codesign machines are communicating with each other using network
drive.
This commit is contained in:
2020-02-03 17:03:51 +01:00
parent 59e1c2f629
commit 3125cfceec
15 changed files with 1223 additions and 28 deletions

View File

@@ -45,13 +45,16 @@
import abc
import logging
import shutil
import subprocess
import time
import zipfile
import tarfile
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Iterable, List
import codesign.util as util
from codesign.absolute_and_relative_filename import AbsoluteAndRelativeFileName
from codesign.archive_with_indicator import ArchiveWithIndicator
@@ -64,14 +67,14 @@ logger_server = logger.getChild('server')
def pack_files(files: Iterable[AbsoluteAndRelativeFileName],
archive_filepath: Path) -> None:
"""
Create zip archive from given files for the signing pipeline.
Create tar archive from given files for the signing pipeline.
Is used by buildbot worker to create an archive of files which are to be
signed, and by signing server to send signed files back to the worker.
"""
with zipfile.ZipFile(archive_filepath, 'w') as zip_file_handle:
with tarfile.TarFile.open(archive_filepath, 'w') as tar_file_handle:
for file_info in files:
zip_file_handle.write(file_info.absolute_filepath,
arcname=file_info.relative_filepath)
tar_file_handle.add(file_info.absolute_filepath,
arcname=file_info.relative_filepath)
def extract_files(archive_filepath: Path,
@@ -82,8 +85,8 @@ def extract_files(archive_filepath: Path,
# TODO(sergey): Verify files in the archive have relative path.
with zipfile.ZipFile(archive_filepath, mode='r') as zip_file_handle:
zip_file_handle.extractall(path=extraction_dir)
with tarfile.TarFile.open(archive_filepath, mode='r') as tar_file_handle:
tar_file_handle.extractall(path=extraction_dir)
class BaseCodeSigner(metaclass=abc.ABCMeta):
@@ -133,6 +136,9 @@ class BaseCodeSigner(metaclass=abc.ABCMeta):
# This archive is created by the code signing server.
signed_archive_info: ArchiveWithIndicator
# Platform the code is currently executing on.
platform: util.Platform
def __init__(self, config):
self.config = config
@@ -141,12 +147,14 @@ class BaseCodeSigner(metaclass=abc.ABCMeta):
# Unsigned (signing server input) configuration.
self.unsigned_storage_dir = absolute_shared_storage_dir / 'unsigned'
self.unsigned_archive_info = ArchiveWithIndicator(
self.unsigned_storage_dir, 'unsigned_files.zip', 'ready.stamp')
self.unsigned_storage_dir, 'unsigned_files.tar', 'ready.stamp')
# Signed (signing server output) configuration.
self.signed_storage_dir = absolute_shared_storage_dir / 'signed'
self.signed_archive_info = ArchiveWithIndicator(
self.signed_storage_dir, 'signed_files.zip', 'ready.stamp')
self.signed_storage_dir, 'signed_files.tar', 'ready.stamp')
self.platform = util.get_current_platform()
"""
General note on cleanup environment functions.
@@ -383,3 +391,61 @@ class BaseCodeSigner(metaclass=abc.ABCMeta):
logger_server.info(
'Got signing request, beging signign procedure.')
self.run_signing_pipeline()
############################################################################
# Command executing.
#
# Abstracted to a degree that allows to run commands from a foreign
# platform.
# The goal with this is to allow performing dry-run tests of code signer
# server from other platforms (for example, to test that macOS code signer
# does what it is supposed to after doing a refactor on Linux).
# TODO(sergey): What is the type annotation for the command?
def run_command_or_mock(self, command, platform: util.Platform) -> None:
"""
Run given command if current platform matches given one
If the platform is different then it will only be printed allowing
to verify logic of the code signing process.
"""
if platform != self.platform:
logger_server.info(
f'Will run command for {platform}: {command}')
return
logger_server.info(f'Running command: {command}')
subprocess.run(command)
# TODO(sergey): What is the type annotation for the command?
def check_output_or_mock(self, command,
platform: util.Platform,
allow_nonzero_exit_code=False) -> str:
"""
Run given command if current platform matches given one
If the platform is different then it will only be printed allowing
to verify logic of the code signing process.
If allow_nonzero_exit_code is truth then the output will be returned
even if application quit with non-zero exit code.
Otherwise an subprocess.CalledProcessError exception will be raised
in such case.
"""
if platform != self.platform:
logger_server.info(
f'Will run command for {platform}: {command}')
return
if allow_nonzero_exit_code:
process = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
output = process.communicate()[0]
return output.decode()
logger_server.info(f'Running command: {command}')
return subprocess.check_output(
command, stderr=subprocess.STDOUT).decode()