Re-implement packaging for GitHub workflows (Windows) (#7360)
* Add new version env vars to example * Remove test file * Move CMake packaging to separate module and configure OpenSSL path for Windows * Make VS Code CMake build task default * Generate Microsoft-friendly 4-digit version number * Update macOS bundle .plist with build year variable * Use correct OpenSSL path and fixed various MSI variables * Use correct rest/dist dir for MSI * Add version .rc file for Windows * Use macro instead of over-complicated version query command * Made cmd_utils more secure by defaulting to no-shell and no-print * Add certificate management module * Implement packaging script on Windows * Refactor Mac packaging script to use new cmd_utils args and new cert module * Update ChangeLog * Change PFX env vars and add to CI * Use import as instead of from lib to solve resolve issue * Allow custom certificate extensions * Check for package version when using gdrive * Make version number required * Add missing shell * Add missing gdrive value in test * Find OpenSSL dir based on openssl binary * Only use first OpenSSL entry * More verbose logging * Improve logging * Only use env var if not empty * Fixed wrong var * Fixed macOS GitHub artefact name * Change filename format to match new convention
This commit is contained in:
parent
05ed4ab757
commit
bec38ab47b
35 changed files with 746 additions and 370 deletions
|
|
@ -13,6 +13,12 @@
|
|||
# Packaging (optional)
|
||||
#
|
||||
|
||||
# [Windows] Base64 encoded PFX code signing certificate
|
||||
# WINDOWS_PFX_CERTIFICATE="very-long-base64-encoded-string"
|
||||
|
||||
# [Windows] Password for the PFX code signing certificate
|
||||
# WINDOWS_PFX_PASSWORD="super-secret-password"
|
||||
|
||||
# [macOS] Apple ID used to notarize the app
|
||||
# APPLE_NOTARY_USER="example@example.com"
|
||||
|
||||
|
|
|
|||
8
.github/actions/dist-upload/action.yml
vendored
8
.github/actions/dist-upload/action.yml
vendored
|
|
@ -26,6 +26,12 @@ runs:
|
|||
using: "composite"
|
||||
|
||||
steps:
|
||||
- if: ${{ inputs.use_gdrive == 'true' && !inputs.package-version }}
|
||||
run: |
|
||||
echo "Input 'package-version' is required when uploading to Google Drive"
|
||||
exit 1
|
||||
shell: bash
|
||||
|
||||
- if: ${{ inputs.use_gdrive == 'true' }}
|
||||
run: |
|
||||
SHORT_VERSION=$(echo "${{ inputs.package-version }}" | cut -d'-' -f1)
|
||||
|
|
@ -41,7 +47,7 @@ runs:
|
|||
retention-days: 3
|
||||
|
||||
# Upload to Google Drive
|
||||
- if: ${{ inputs.use_gdrive }}
|
||||
- if: ${{ inputs.use_gdrive == 'true' }}
|
||||
uses: symless/gdrive-upload@target-glob
|
||||
with:
|
||||
credentials: ${{ inputs.gdrive-secret-key }}
|
||||
|
|
|
|||
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
|
|
@ -5,6 +5,7 @@ on:
|
|||
inputs:
|
||||
version:
|
||||
description: Synergy version number
|
||||
required: true
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
|
|
@ -68,6 +69,21 @@ jobs:
|
|||
- name: Package
|
||||
if: ${{ !github.event.pull_request.draft }}
|
||||
run: python ./scripts/package.py
|
||||
env:
|
||||
WINDOWS_PFX_CERTIFICATE: ${{ secrets.WINDOWS_PFX }}
|
||||
WINDOWS_PFX_PASSWORD: ${{ secrets.WINDOWS_PFX_PASS }}
|
||||
|
||||
- name: Upload
|
||||
if:
|
||||
uses: ./.github/actions/dist-upload
|
||||
with:
|
||||
use_github: ${{ env.UPLOAD_TO_GITHUB }}
|
||||
use_gdrive: ${{ env.UPLOAD_TO_GDRIVE }}
|
||||
github-target-filename: "synergy-windows-x64"
|
||||
gdrive-target-base-dir: "synergy1/personal"
|
||||
gdrive-secret-key: ${{ secrets.GOOGLE_DRIVE_KEY }}
|
||||
gdrive-parent-folder-id: ${{ secrets.GOOGLE_DRIVE_TECH_DRIVE }}
|
||||
package-version: ${{ env.SYNERGY_VERSION }}
|
||||
|
||||
macos:
|
||||
runs-on: ${{ matrix.runtime.os }}
|
||||
|
|
@ -88,7 +104,7 @@ jobs:
|
|||
target: "10.14"
|
||||
shell: "bash"
|
||||
|
||||
- name: "macos-11-m1"
|
||||
- name: "macos-11-arm64"
|
||||
timeout: 10
|
||||
os: "macos-14"
|
||||
arch: arm64
|
||||
|
|
@ -132,7 +148,7 @@ jobs:
|
|||
with:
|
||||
use_github: ${{ env.UPLOAD_TO_GITHUB }}
|
||||
use_gdrive: ${{ env.UPLOAD_TO_GDRIVE }}
|
||||
github-target-filename: "synergy-macos-${{ matrix.runtime.target }}"
|
||||
github-target-filename: "synergy-${{ matrix.runtime.name }}"
|
||||
gdrive-target-base-dir: "synergy1/personal"
|
||||
gdrive-secret-key: ${{ secrets.GOOGLE_DRIVE_KEY }}
|
||||
gdrive-parent-folder-id: ${{ secrets.GOOGLE_DRIVE_TECH_DRIVE }}
|
||||
|
|
|
|||
5
.vscode/tasks.json
vendored
5
.vscode/tasks.json
vendored
|
|
@ -7,7 +7,10 @@
|
|||
"command": "build",
|
||||
"targets": ["all"],
|
||||
"preset": "${command:cmake.activeBuildPresetName}",
|
||||
"group": "build"
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "reinstall windows daemon",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2012-2016 Symless Ltd.
|
||||
# Copyright (C) 2009 Nick Bolton
|
||||
# Copyright (C) 2012-2024 Symless Ltd.
|
||||
# Copyright (C) 2009-2012 Nick Bolton
|
||||
#
|
||||
# This package is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
cmake_minimum_required (VERSION 3.5)
|
||||
project (synergy-core C CXX)
|
||||
|
||||
include (cmake/Version.cmake)
|
||||
set_version()
|
||||
|
||||
# use response files so that ninja can compile on windows,
|
||||
# otherwise you get an error when linking qt:
|
||||
|
|
@ -339,7 +341,7 @@ if (UNIX)
|
|||
add_definitions (-DWINAPI_XWINDOWS=1)
|
||||
endif()
|
||||
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
elseif (WIN32)
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2")
|
||||
|
|
@ -354,6 +356,11 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
|||
/D_XKEYCHECK_H
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/res/win/version.rc.in
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
@ONLY)
|
||||
|
||||
endif()
|
||||
|
||||
#
|
||||
|
|
@ -376,11 +383,12 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
|||
option(GIT_SUBMODULE "Check submodules during build" ON)
|
||||
if(GIT_SUBMODULE)
|
||||
message(STATUS "Submodule update")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SUBMOD_RESULT)
|
||||
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_SUBMODULE_RESULT)
|
||||
if(NOT GIT_SUBMODULE_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "Git submodule update failed: ${GIT_SUBMODULE_RESULT}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -389,78 +397,10 @@ endif()
|
|||
# Google Test
|
||||
#
|
||||
if(BUILD_TESTS AND NOT EXISTS "${PROJECT_SOURCE_DIR}/ext/googletest/CMakeLists.txt")
|
||||
message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
|
||||
message(FATAL_ERROR "Git submodule for Google Test is missing")
|
||||
endif()
|
||||
|
||||
|
||||
#
|
||||
# Same as the `configure_file` command but for directories recursively.
|
||||
#
|
||||
macro (configure_files srcDir destDir)
|
||||
message (STATUS "Configuring directory ${destDir}")
|
||||
make_directory (${destDir})
|
||||
|
||||
file (GLOB_RECURSE sourceFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||
file (GLOB_RECURSE templateFiles LIST_DIRECTORIES false RELATIVE ${srcDir} ${srcDir}/*.in)
|
||||
list (REMOVE_ITEM sourceFiles ${templateFiles})
|
||||
|
||||
foreach (sourceFile ${sourceFiles})
|
||||
set (sourceFilePath ${srcDir}/${sourceFile})
|
||||
if (IS_DIRECTORY ${sourceFilePath})
|
||||
message (STATUS "Copying directory ${sourceFile}")
|
||||
make_directory (${destDir}/${sourceFile})
|
||||
else()
|
||||
message (STATUS "Copying file ${sourceFile}")
|
||||
configure_file (${sourceFilePath} ${destDir}/${sourceFile} COPYONLY)
|
||||
endif()
|
||||
endforeach (sourceFile)
|
||||
|
||||
foreach (templateFile ${templateFiles})
|
||||
set (sourceTemplateFilePath ${srcDir}/${templateFile})
|
||||
string (REGEX REPLACE "\.in$" "" templateFile ${templateFile})
|
||||
message (STATUS "Configuring file ${templateFile}")
|
||||
configure_file (${sourceTemplateFilePath} ${destDir}/${templateFile} @ONLY)
|
||||
endforeach (templateFile)
|
||||
endmacro (configure_files)
|
||||
|
||||
if (${SYNERGY_BUILD_INSTALLER})
|
||||
|
||||
#
|
||||
# macOS app bundle
|
||||
#
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set (CMAKE_INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks")
|
||||
set (SYNERGY_BUNDLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/res/dist/macos/bundle)
|
||||
set (SYNERGY_BUNDLE_DIR ${CMAKE_BINARY_DIR}/bundle)
|
||||
set (SYNERGY_BUNDLE_APP_DIR ${SYNERGY_BUNDLE_DIR}/Synergy.app)
|
||||
set (SYNERGY_BUNDLE_BINARY_DIR ${SYNERGY_BUNDLE_APP_DIR}/Contents/MacOS)
|
||||
configure_files (${SYNERGY_BUNDLE_SOURCE_DIR} ${SYNERGY_BUNDLE_DIR})
|
||||
endif()
|
||||
|
||||
#
|
||||
# Windows installer
|
||||
#
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
message (STATUS "Configuring the v1 installer")
|
||||
set(QT_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/res/dist/wix ${CMAKE_BINARY_DIR}/installer)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Linux installation
|
||||
#
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux|.*BSD|DragonFly")
|
||||
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/res/dist/rpm ${CMAKE_BINARY_DIR}/rpm)
|
||||
install(FILES res/synergy.svg DESTINATION share/icons/hicolor/scalable/apps)
|
||||
if("${VERSION_MAJOR}" STREQUAL "2")
|
||||
install(FILES res/synergy2.desktop DESTINATION share/applications)
|
||||
else()
|
||||
install(FILES res/synergy.desktop DESTINATION share/applications)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
else()
|
||||
message (STATUS "NOT configuring the installer")
|
||||
endif()
|
||||
include(cmake/Packaging.cmake)
|
||||
configure_packaging()
|
||||
|
||||
add_subdirectory (src)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,9 @@ Enhancements:
|
|||
- #7336 Add C++ and LLDB to VS Code recommendations
|
||||
- #7351 Use deps script to make life easier for contribs
|
||||
- #7352 Combine GitHub workflows to reduce config duplication
|
||||
- #7353 Re-implement packaging for GitHub workflows (macOS)
|
||||
- #7354 Re-implement CI auto version increment for packaging
|
||||
- #7353 Re-implement packaging for GitHub workflows (macOS)
|
||||
- #7360 Re-implement packaging for GitHub workflows (Windows)
|
||||
|
||||
# 1.14.6
|
||||
|
||||
|
|
|
|||
120
cmake/Packaging.cmake
Normal file
120
cmake/Packaging.cmake
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2012-2024 Symless Ltd.
|
||||
# Copyright (C) 2009-2012 Nick Bolton
|
||||
#
|
||||
# This package is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# found in the file LICENSE that should have accompanied this file.
|
||||
#
|
||||
# This package is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# If enabled, configure packaging based on OS.
|
||||
#
|
||||
macro(configure_packaging)
|
||||
if (${SYNERGY_BUILD_INSTALLER})
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
configure_macos_packaging()
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
configure_windows_packaging()
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux|.*BSD|DragonFly")
|
||||
configure_linux_packaging()
|
||||
endif()
|
||||
else()
|
||||
message (STATUS "Not configuring installer")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# macOS app bundle
|
||||
#
|
||||
macro(configure_macos_packaging)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set (CMAKE_INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks")
|
||||
set (SYNERGY_BUNDLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/res/dist/macos/bundle)
|
||||
set (SYNERGY_BUNDLE_DIR ${CMAKE_BINARY_DIR}/bundle)
|
||||
set (SYNERGY_BUNDLE_APP_DIR ${SYNERGY_BUNDLE_DIR}/Synergy.app)
|
||||
set (SYNERGY_BUNDLE_BINARY_DIR ${SYNERGY_BUNDLE_APP_DIR}/Contents/MacOS)
|
||||
configure_files (${SYNERGY_BUNDLE_SOURCE_DIR} ${SYNERGY_BUNDLE_DIR})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(find_openssl_dir_win32 result)
|
||||
execute_process(
|
||||
COMMAND where openssl
|
||||
OUTPUT_VARIABLE OPENSSL_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# It's possible that there are multiple OpenSSL installations on the system,
|
||||
# which is the case on GitHub runners.
|
||||
# For now we'll pick the first one, but that's probably not very robust.
|
||||
# Maybe our choco config could install to a specific location?
|
||||
string(REGEX REPLACE "\r?\n" ";" OPENSSL_PATH_LIST ${OPENSSL_PATH})
|
||||
message(STATUS "Found OpenSSL binaries at: ${OPENSSL_PATH_LIST}")
|
||||
|
||||
list(GET OPENSSL_PATH_LIST 0 OPENSSL_FIRST_PATH)
|
||||
message(STATUS "First OpenSSL binary: ${OPENSSL_FIRST_PATH}")
|
||||
|
||||
get_filename_component(OPENSSL_BIN_DIR ${OPENSSL_FIRST_PATH} DIRECTORY)
|
||||
message(STATUS "OpenSSL bin dir: ${OPENSSL_BIN_DIR}")
|
||||
|
||||
get_filename_component(OPENSSL_DIR ${OPENSSL_BIN_DIR} DIRECTORY)
|
||||
message(STATUS "OpenSSL install root dir: ${OPENSSL_DIR}")
|
||||
|
||||
set(${result} ${OPENSSL_DIR} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
#
|
||||
# Windows installer
|
||||
#
|
||||
macro(configure_windows_packaging)
|
||||
find_openssl_dir_win32(OPENSSL_PATH)
|
||||
set(QT_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/res/dist/wix ${CMAKE_BINARY_DIR}/installer)
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# Linux packages (including BSD and DragonFly)
|
||||
#
|
||||
macro(configure_linux_packaging)
|
||||
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/res/dist/rpm ${CMAKE_BINARY_DIR}/rpm)
|
||||
install(FILES res/synergy.svg DESTINATION share/icons/hicolor/scalable/apps)
|
||||
install(FILES res/synergy.desktop DESTINATION share/applications)
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# Same as the `configure_file` command but for directories recursively.
|
||||
#
|
||||
macro (configure_files srcDir destDir)
|
||||
message (STATUS "Configuring directory ${destDir}")
|
||||
make_directory (${destDir})
|
||||
|
||||
file (GLOB_RECURSE sourceFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||
file (GLOB_RECURSE templateFiles LIST_DIRECTORIES false RELATIVE ${srcDir} ${srcDir}/*.in)
|
||||
list (REMOVE_ITEM sourceFiles ${templateFiles})
|
||||
|
||||
foreach (sourceFile ${sourceFiles})
|
||||
set (sourceFilePath ${srcDir}/${sourceFile})
|
||||
if (IS_DIRECTORY ${sourceFilePath})
|
||||
message (STATUS "Copying directory ${sourceFile}")
|
||||
make_directory (${destDir}/${sourceFile})
|
||||
else()
|
||||
message (STATUS "Copying file ${sourceFile}")
|
||||
configure_file (${sourceFilePath} ${destDir}/${sourceFile} COPYONLY)
|
||||
endif()
|
||||
endforeach (sourceFile)
|
||||
|
||||
foreach (templateFile ${templateFiles})
|
||||
set (sourceTemplateFilePath ${srcDir}/${templateFile})
|
||||
string (REGEX REPLACE "\.in$" "" templateFile ${templateFile})
|
||||
message (STATUS "Configuring file ${templateFile}")
|
||||
configure_file (${sourceTemplateFilePath} ${destDir}/${templateFile} @ONLY)
|
||||
endforeach (templateFile)
|
||||
endmacro (configure_files)
|
||||
|
|
@ -1,14 +1,58 @@
|
|||
# Synergy -- mouse and keyboard sharing utility
|
||||
# Copyright (C) 2012-2024 Symless Ltd.
|
||||
# Copyright (C) 2009-2012 Nick Bolton
|
||||
#
|
||||
# Gets the version number either from an env var or from the VERSION file.
|
||||
# This package is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# found in the file LICENSE that should have accompanied this file.
|
||||
#
|
||||
# This package is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set (VERSION $ENV{SYNERGY_VERSION})
|
||||
string(STRIP "${VERSION}" VERSION)
|
||||
# Either get the version number from the environment or from the VERSION file.
|
||||
# On Windows, we also set a special 4-digit MSI version number.
|
||||
macro(set_version)
|
||||
|
||||
if (NOT VERSION)
|
||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" VERSION)
|
||||
string(STRIP "${VERSION}" VERSION)
|
||||
endif()
|
||||
set (SYNERGY_VERSION $ENV{SYNERGY_VERSION})
|
||||
string(STRIP "${SYNERGY_VERSION}" SYNERGY_VERSION)
|
||||
|
||||
message (STATUS "Version number: " ${VERSION})
|
||||
add_definitions (-DSYNERGY_VERSION="${VERSION}")
|
||||
if (NOT SYNERGY_VERSION)
|
||||
file(READ "${CMAKE_SOURCE_DIR}/VERSION" SYNERGY_VERSION)
|
||||
string(STRIP "${SYNERGY_VERSION}" SYNERGY_VERSION)
|
||||
endif()
|
||||
|
||||
message (STATUS "Version number: " ${SYNERGY_VERSION})
|
||||
add_definitions (-DSYNERGY_VERSION="${SYNERGY_VERSION}")
|
||||
|
||||
# Useful for copyright (e.g. in macOS bundle .plist.in and Windows version .rc file)
|
||||
string(TIMESTAMP SYNERGY_BUILD_YEAR "%Y")
|
||||
|
||||
# MSI requires a 4-digit number and doesn't accept semver.
|
||||
if (WIN32)
|
||||
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ "${SYNERGY_VERSION}")
|
||||
set(VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
set(VERSION_MINOR "${CMAKE_MATCH_2}")
|
||||
set(VERSION_PATCH "${CMAKE_MATCH_3}")
|
||||
|
||||
# Find the revision number, which is the number after the 'r'.
|
||||
string(REGEX MATCH "r([0-9]+)$" _ "${SYNERGY_VERSION}")
|
||||
set(VERSION_REVISION "${CMAKE_MATCH_1}")
|
||||
if (NOT VERSION_REVISION)
|
||||
set(VERSION_REVISION "0")
|
||||
endif()
|
||||
|
||||
# Dot-separated version number for MSI and Windows version .rc file.
|
||||
set(SYNERGY_VERSION_MS "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_REVISION}")
|
||||
message (STATUS "Version number for Microsoft (dots): " ${SYNERGY_VERSION_MS})
|
||||
|
||||
# CSV version number for Windows version .rc file.
|
||||
set(SYNERGY_VERSION_MS_CSV "${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}")
|
||||
message (STATUS "Version number for Microsoft (CSV): " ${SYNERGY_VERSION_MS_CSV})
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
<string>Synergy.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>synergy</string>
|
||||
<!-- TODO: Fix this in v2.0 //-->
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
|
@ -25,7 +24,7 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>@SYNERGY_VERSION@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>© 2012-2016, Symless Ltd</string>
|
||||
<string>© 2012-@SYNERGY_BUILD_YEAR@ Symless Ltd</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.9.0</string>
|
||||
</dict>
|
||||
|
|
|
|||
43
res/dist/wix/Include.wxi.in
vendored
43
res/dist/wix/Include.wxi.in
vendored
|
|
@ -1,24 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Include>
|
||||
<?define Name="Synergy" ?>
|
||||
<?define Version="@SYNERGY_VERSION@" ?>
|
||||
<?define Author="Symless Ltd" ?>
|
||||
<?define BinPath="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(var.Configuration)" ?>
|
||||
<?define ResPath="@CMAKE_CURRENT_SOURCE_DIR@/res" ?>
|
||||
<?define ExtPath="@CMAKE_CURRENT_SOURCE_DIR@/ext" ?>
|
||||
<?define DisPath="@CMAKE_CURRENT_SOURCE_DIR@/dist" ?>
|
||||
<?if $(var.Platform) = "x64" ?>
|
||||
<?define ProgramFilesFolder="ProgramFiles64Folder" ?>
|
||||
<?define PlatformSimpleName="64-bit" ?>
|
||||
<?define UpgradeGuid="E8A4FA54-14B9-4FD1-8E00-7BC46555FDA0" ?>
|
||||
<?else ?>
|
||||
<?define ProgramFilesFolder="ProgramFilesFolder" ?>
|
||||
<?define PlatformSimpleName="32-bit" ?>
|
||||
<?define UpgradeGuid="BE0B9FD8-45E2-4A8E-A0D8-1F774D074A78" ?>
|
||||
<?endif ?>
|
||||
<?define QtPath="@QT_PATH@" ?>
|
||||
<?define QtBinPath="$(var.QtPath)\bin" ?>
|
||||
<?define QtPluginsPath="$(var.QtPath)\plugins" ?>
|
||||
<?define OpenSSLPath="$(var.ExtPath)\openssl\windows\$(var.Platform)" ?>
|
||||
<?define OpenSSLBinPath="$(var.OpenSSLPath)\bin" ?>
|
||||
</Include>
|
||||
<?define Name="Synergy"?>
|
||||
<?define Version="@SYNERGY_VERSION_MS@"?>
|
||||
<?define Author="Symless"?>
|
||||
<?define BinPath="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"?>
|
||||
<?define ResPath="@CMAKE_CURRENT_SOURCE_DIR@/res"?>
|
||||
<?define ExtPath="@CMAKE_CURRENT_SOURCE_DIR@/ext"?>
|
||||
<?if $(var.Platform) = "x64"?>
|
||||
<?define ProgramFilesFolder="ProgramFiles64Folder"?>
|
||||
<?define PlatformSimpleName="64-bit"?>
|
||||
<?define UpgradeGuid="E8A4FA54-14B9-4FD1-8E00-7BC46555FDA0"?>
|
||||
<?else?>
|
||||
<?define ProgramFilesFolder="ProgramFilesFolder"?>
|
||||
<?define PlatformSimpleName="32-bit"?>
|
||||
<?define UpgradeGuid="BE0B9FD8-45E2-4A8E-A0D8-1F774D074A78"?>
|
||||
<?endif?>
|
||||
<?define QtPath="@QT_PATH@"?>
|
||||
<?define QtBinPath="$(var.QtPath)\bin"?>
|
||||
<?define QtPluginsPath="$(var.QtPath)\plugins"?>
|
||||
<?define OpenSSLPath="@OPENSSL_PATH@"?>
|
||||
<?define OpenSSLBinPath="$(var.OpenSSLPath)\bin"?>
|
||||
</Include>
|
||||
22
res/dist/wix/Product.wxs
vendored
22
res/dist/wix/Product.wxs
vendored
|
|
@ -38,9 +38,9 @@
|
|||
<Condition><![CDATA[Installed OR (VersionNT >= 602)]]></Condition>
|
||||
</Component>
|
||||
<?if $(var.Platform) = x64 ?>
|
||||
<Merge Id="VC_Redist" SourceFile="$(var.DisPath)\wix\msm\Microsoft_VC142_CRT_x64.msm" DiskId="1" Language="0"/>
|
||||
<Merge Id="VC_Redist" SourceFile="$(var.ResPath)\dist\wix\msm\Microsoft_VC142_CRT_x64.msm" DiskId="1" Language="0"/>
|
||||
<?else ?>
|
||||
<Merge Id="VC_Redist" SourceFile="$(var.DisPath)\wix\msm\Microsoft_VC142_CRT_x86.msm" DiskId="1" Language="0"/>
|
||||
<Merge Id="VC_Redist" SourceFile="$(var.ResPath)\dist\wix\msm\Microsoft_VC142_CRT_x86.msm" DiskId="1" Language="0"/>
|
||||
<?endif ?>
|
||||
</DirectoryRef>
|
||||
<Property Id="SynergyCommonBackground">common_background</Property>
|
||||
|
|
@ -90,11 +90,11 @@
|
|||
</File>
|
||||
<File Source="$(var.BinPath)/syntool.exe"/>
|
||||
<?if $(var.Platform) = x64 ?>
|
||||
<File Source="$(var.OpenSSLBinPath)/libssl-1_1-x64.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libcrypto-1_1-x64.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libssl-3-x64.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libcrypto-3-x64.dll"/>
|
||||
<?else ?>
|
||||
<File Source="$(var.OpenSSLBinPath)/libssl-1_1.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libcrypto-1_1.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libssl-3.dll"/>
|
||||
<File Source="$(var.OpenSSLBinPath)/libcrypto-3.dll"/>
|
||||
<?endif ?>
|
||||
</Component>
|
||||
<Component Guid="BAC8149B-6287-45BF-9C27-43D71ED40214" Id="Gui">
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
<File Source="$(var.BinPath)\Qt5Widgetsd.dll"/>
|
||||
<File Source="$(var.BinPath)\libGLESv2d.dll"/>
|
||||
<File Source="$(var.BinPath)\libEGLd.dll"/>
|
||||
<!-- Hacky -->
|
||||
<!-- HACK: Normally the C++ redistributable solves this dependency, including it can cause problems -->
|
||||
<File Source="C:\Program Files (x86)\Windows Kits\10\bin\$(var.Platform)\ucrt\ucrtbased.dll"/>
|
||||
<?else ?>
|
||||
<File Source="$(var.BinPath)\Qt5Core.dll"/>
|
||||
|
|
@ -142,11 +142,11 @@
|
|||
<ComponentGroup Directory="OpenSSLDir" Id="OpenSSLComponents">
|
||||
<Component Guid="92648F77-65A6-4B16-AC59-A1F37BD341B1" Id="OpenSSL">
|
||||
<?if $(var.Platform) = x64 ?>
|
||||
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-1_1-x64.dll"/>
|
||||
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-1_1-x64.dll"/>
|
||||
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-3-x64.dll"/>
|
||||
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-3-x64.dll"/>
|
||||
<?else ?>
|
||||
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-1_1.dll"/>
|
||||
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-1_1.dll"/>
|
||||
<File Id="OpenSSLDll1" Source="$(var.OpenSSLBinPath)/libcrypto-3.dll"/>
|
||||
<File Id="OpenSSLDll2" Source="$(var.OpenSSLBinPath)/libssl-3.dll"/>
|
||||
<?endif ?>
|
||||
<File Source="$(var.OpenSSLBinPath)/openssl.exe"/>
|
||||
<File Source="$(var.ResPath)/openssl/synergy.conf"/>
|
||||
|
|
|
|||
54
res/win/version.rc.in
Normal file
54
res/win/version.rc.in
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Based on example from:
|
||||
https://learn.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource?redirectedfrom=MSDN
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <verrsrc.h>
|
||||
|
||||
#define VER_FILEVERSION @SYNERGY_VERSION_MS_CSV@
|
||||
#define VER_FILEVERSION_STR "@SYNERGY_VERSION_MS@\0"
|
||||
|
||||
#define VER_PRODUCTVERSION @SYNERGY_VERSION_MS_CSV@
|
||||
#define VER_PRODUCTVERSION_STR "@SYNERGY_VERSION_MS@\0"
|
||||
|
||||
#define VER_COMPANYNAME_STR "Symless\0"
|
||||
#define VER_FILEDESCRIPTION_STR "Synergy\0"
|
||||
#define VER_INTERNALNAME_STR "Synergy\0"
|
||||
#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Symless Ltd. @SYNERGY_BUILD_YEAR@\0"
|
||||
#define VER_LEGALTRADEMARKS1_STR "All Rights Reserved\0"
|
||||
#define VER_LEGALTRADEMARKS2_STR "\0"
|
||||
#define VER_ORIGINALFILENAME_STR "\0"
|
||||
#define VER_PRODUCTNAME_STR "Synergy\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS 0 // No flags
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", VER_COMPANYNAME_STR
|
||||
VALUE "FileDescription", VER_FILEDESCRIPTION_STR
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "InternalName", VER_INTERNALNAME_STR
|
||||
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
|
||||
VALUE "LegalTrademarks1", VER_LEGALTRADEMARKS1_STR
|
||||
VALUE "LegalTrademarks2", VER_LEGALTRADEMARKS2_STR
|
||||
VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
|
||||
VALUE "ProductName", VER_PRODUCTNAME_STR
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1252
|
||||
END
|
||||
END
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from lib import env, github
|
||||
import lib.env as env
|
||||
import lib.github as github
|
||||
from lib.config import Config
|
||||
|
||||
qt_version_key = "QT_VERSION"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os, sys, argparse, traceback
|
||||
from lib import env, cmd_utils
|
||||
import lib.env as env
|
||||
import lib.cmd_utils as cmd_utils
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -61,7 +62,7 @@ class Dependencies:
|
|||
|
||||
def windows(self):
|
||||
"""Installs dependencies on Windows."""
|
||||
from lib import windows
|
||||
import lib.windows as windows
|
||||
|
||||
if not windows.is_admin():
|
||||
windows.relaunch_as_admin(__file__)
|
||||
|
|
@ -95,10 +96,10 @@ class Dependencies:
|
|||
|
||||
def mac(self):
|
||||
"""Installs dependencies on macOS."""
|
||||
from lib import mac
|
||||
import lib.mac as mac
|
||||
|
||||
command = self.config.get_os_deps_value("command")
|
||||
cmd_utils.run(command)
|
||||
cmd_utils.run(command, shell=True, print_cmd=True)
|
||||
|
||||
if not self.ci_env:
|
||||
mac.set_cmake_prefix_env_var(self.config.get_os_value("qt-prefix-command"))
|
||||
|
|
@ -123,7 +124,7 @@ class Dependencies:
|
|||
|
||||
# don't check the return code, as some package managers return non-zero exit codes
|
||||
# under normal circumstances (e.g. dnf returns 100 when there are updates available).
|
||||
cmd_utils.run(command, check=False)
|
||||
cmd_utils.run(command, check=False, shell=True, print_cmd=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
40
scripts/lib/certificate.py
Normal file
40
scripts/lib/certificate.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import os, base64
|
||||
|
||||
temp_path = "tmp/certificate"
|
||||
|
||||
|
||||
class Certificate:
|
||||
"""
|
||||
Installs a certificate from a base64 string, and returns the path to the certificate.
|
||||
Once the context is exited, the certificate is removed from the filesystem.
|
||||
|
||||
Example usage:
|
||||
with Certificate(base64) as cert_path:
|
||||
print(f"Certificate path: {cert_path}")
|
||||
"""
|
||||
|
||||
def __init__(self, base64, file_ext):
|
||||
self.base64 = base64
|
||||
self.temp_filename = f"{temp_path}.{file_ext}"
|
||||
|
||||
def __enter__(self):
|
||||
print(f"Decoding certificate to temporary path: {self.temp_filename}")
|
||||
try:
|
||||
cert_bytes = base64.b64decode(self.base64)
|
||||
except Exception as e:
|
||||
raise ValueError("Failed to decode certificate base64") from e
|
||||
|
||||
os.makedirs(os.path.dirname(self.temp_filename), exist_ok=True)
|
||||
with open(self.temp_filename, "wb") as cert_file:
|
||||
cert_file.write(cert_bytes)
|
||||
|
||||
return self.temp_filename
|
||||
|
||||
def __exit__(self, _exc_type, _exc_value, _traceback):
|
||||
# not strictly necessary for ci, but when run on a dev machine, it reduces the risk
|
||||
# that private keys are left on the filesystem
|
||||
print(f"Removing temporary certificate file: {self.temp_filename}")
|
||||
os.remove(self.temp_filename)
|
||||
|
||||
# propagate exceptions
|
||||
return False
|
||||
|
|
@ -37,30 +37,28 @@ def strip_continuation_sequences(command):
|
|||
# TODO: fix bug: often when using this function, only the first arg element is sent to subprocess.run
|
||||
def run(
|
||||
command,
|
||||
check=True,
|
||||
shell=True,
|
||||
check=True, # true by default to fail fast
|
||||
shell=False, # false by default for security
|
||||
get_output=False,
|
||||
print_cmd=True,
|
||||
print_cmd=False, # false by default for security
|
||||
):
|
||||
"""
|
||||
Convenience wrapper around `subprocess.run` to:
|
||||
- print the command before running it
|
||||
- pipe/capture the output instead of printing it
|
||||
- print the command before running it (if `print_cmd` is True)
|
||||
|
||||
This differs to `subprocess.run` in that by default it:
|
||||
- checks the return code by default
|
||||
- uses a shell by default (sometimes a bad idea for security)
|
||||
- prints list commands as a readable string on failure
|
||||
|
||||
Warning: This code is used by CI and prints the command before running it;
|
||||
never use this function with sensitive information such as passwords,
|
||||
unless you want the world to know.
|
||||
This is the same as `subprocess.run` in that it:
|
||||
- does not use shell by default for security (shell is less secure)
|
||||
|
||||
Args:
|
||||
command (str or list): The command to run.
|
||||
check (bool): Raise an exception if the command fails.
|
||||
shell (bool): Run the command in a shell.
|
||||
shell (bool): Run the command in a shell (false by default for security)
|
||||
get_output (bool): Return the output of the command.
|
||||
print_cmd (bool): Print the command before running it.
|
||||
print_cmd (bool): Print the command before running it (false by default for security)
|
||||
"""
|
||||
|
||||
# create string version of list command, only for debugging purposes
|
||||
|
|
@ -70,23 +68,44 @@ def run(
|
|||
|
||||
if print_cmd:
|
||||
print(f"Running: {command_str}")
|
||||
sys.stdout.flush()
|
||||
|
||||
if get_output:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=shell,
|
||||
check=check,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
else:
|
||||
result = subprocess.run(command, check=check, shell=shell)
|
||||
print("Running command...")
|
||||
command_str = "***"
|
||||
|
||||
if print_cmd and result.returncode != 0:
|
||||
# Flush the output to ensure the command is printed before the output of the command,
|
||||
# which seems to happen in the GitHub runner logs.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
try:
|
||||
if get_output:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=shell,
|
||||
check=check,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
else:
|
||||
result = subprocess.run(command, check=check, shell=shell)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Take control of how failed commands are printed:
|
||||
# - if `print_cmd` is false, it will print `***` instead of the command
|
||||
# - if the command was a list, the command is printed as a readable string
|
||||
raise RuntimeError(
|
||||
f"Command exited with code {e.returncode}: {command_str}"
|
||||
) from None
|
||||
except Exception:
|
||||
# Take control of how failed commands are printed:
|
||||
# - if `print_cmd` is false, it will print `***` instead of the command
|
||||
# - if the command was a list, the command is printed as a readable string
|
||||
raise RuntimeError(f"Command failed: {command_str}") from None
|
||||
|
||||
if result.returncode != 0:
|
||||
print(
|
||||
f"Command exited with code {result.returncode}: {command_str}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from lib import env, cmd_utils
|
||||
import lib.env as env
|
||||
import lib.cmd_utils as cmd_utils
|
||||
|
||||
config_file = "config.yml"
|
||||
root_key = "config"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import os, sys, subprocess, platform
|
||||
from lib import env, cmd_utils
|
||||
import os, sys, subprocess
|
||||
import lib.cmd_utils as cmd_utils
|
||||
|
||||
venv_path = "build/python"
|
||||
version_file = "VERSION"
|
||||
|
|
@ -75,7 +75,7 @@ def in_venv():
|
|||
return sys.prefix != sys.base_prefix
|
||||
|
||||
|
||||
def ensure_in_venv(script):
|
||||
def ensure_in_venv(script_file):
|
||||
"""
|
||||
Ensures the script is running in a Python virtual environment (venv).
|
||||
If the script is not running in a venv, it will create one and re-run the script in the venv.
|
||||
|
|
@ -89,11 +89,9 @@ def ensure_in_venv(script):
|
|||
print(f"Creating virtual environment at {venv_path}")
|
||||
venv.create(venv_path, with_pip=True)
|
||||
|
||||
script_file = os.path.basename(script)
|
||||
print(f"Using virtual environment for {script_file}")
|
||||
sys.stdout.flush()
|
||||
print(f"Using virtual environment for {script_file}", flush=True)
|
||||
python_executable = get_python_executable()
|
||||
result = subprocess.run([python_executable, script] + sys.argv[1:])
|
||||
result = subprocess.run([python_executable, script_file] + sys.argv[1:])
|
||||
sys.exit(result.returncode)
|
||||
|
||||
|
||||
|
|
@ -109,7 +107,11 @@ def ensure_module(module, package):
|
|||
__import__(module)
|
||||
except ImportError:
|
||||
print(f"Python missing {module}, installing {package}...", file=sys.stderr)
|
||||
cmd_utils.run([sys.executable, "-m", "pip", "install", package], shell=False)
|
||||
cmd_utils.run(
|
||||
[sys.executable, "-m", "pip", "install", package],
|
||||
shell=False,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
|
||||
def assert_dependencies(raise_error=True):
|
||||
|
|
@ -150,11 +152,23 @@ def ensure_dependencies():
|
|||
|
||||
distro = get_linux_distro()
|
||||
if distro == "ubuntu" or distro == "debian":
|
||||
cmd_utils.run(f"{sudo} apt update".strip(), check=False)
|
||||
cmd_utils.run(f"{sudo} apt install -y python3-pip python3-venv".strip())
|
||||
cmd_utils.run(
|
||||
f"{sudo} apt update".strip(), check=False, shell=True, print_cmd=True
|
||||
)
|
||||
cmd_utils.run(
|
||||
f"{sudo} apt install -y python3-pip python3-venv".strip(),
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
elif distro == "fedora" or distro == "centos":
|
||||
cmd_utils.run(f"{sudo} dnf check-update".strip(), check=False)
|
||||
cmd_utils.run(f"{sudo} dnf install -y python3-pip python3-virtualenv".strip())
|
||||
cmd_utils.run(
|
||||
f"{sudo} dnf check-update".strip(), check=False, shell=True, print_cmd=True
|
||||
)
|
||||
cmd_utils.run(
|
||||
f"{sudo} dnf install -y python3-pip python3-virtualenv".strip(),
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
else:
|
||||
# arch, opensuse, etc, patches welcome! :)
|
||||
raise RuntimeError(f"Unable to install Python dependencies on {distro}")
|
||||
|
|
@ -165,7 +179,9 @@ def get_app_version():
|
|||
Returns the version either from the env var, or from the version file.
|
||||
"""
|
||||
if version_env_var in os.environ:
|
||||
return os.environ[version_env_var]
|
||||
version = os.environ[version_env_var].strip()
|
||||
if version:
|
||||
return version
|
||||
|
||||
with open(version_file, "r") as f:
|
||||
return f.read().strip()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import os, subprocess, base64, time, json, shutil, sys
|
||||
from lib import cmd_utils, env
|
||||
import os, time, json
|
||||
import lib.cmd_utils as cmd_utils
|
||||
import lib.env as env
|
||||
from lib.certificate import Certificate
|
||||
|
||||
cmake_env_var = "CMAKE_PREFIX_PATH"
|
||||
shell_rc = "~/.zshrc"
|
||||
cert_path = "tmp/codesign.p12"
|
||||
dist_dir = "dist"
|
||||
product_name = "Synergy"
|
||||
settings_file = "res/dist/macos/dmgbuild/settings.py"
|
||||
|
|
@ -30,18 +31,20 @@ def set_env_var(name, value):
|
|||
|
||||
|
||||
def set_cmake_prefix_env_var(cmake_prefix_command):
|
||||
result = cmd_utils.run(cmake_prefix_command, get_output=True)
|
||||
result = cmd_utils.run(
|
||||
cmake_prefix_command, get_output=True, shell=True, print_cmd=True
|
||||
)
|
||||
cmake_prefix = result.stdout.strip()
|
||||
set_env_var(cmake_env_var, cmake_prefix)
|
||||
|
||||
|
||||
def package(filename_base):
|
||||
codesign_id = env.get_env_var("APPLE_CODESIGN_ID")
|
||||
certificate = env.get_env_var("APPLE_P12_CERTIFICATE")
|
||||
password = env.get_env_var("APPLE_P12_PASSWORD")
|
||||
cert_base64 = env.get_env_var("APPLE_P12_CERTIFICATE")
|
||||
cert_password = env.get_env_var("APPLE_P12_PASSWORD")
|
||||
|
||||
build_bundle()
|
||||
install_certificate(certificate, password)
|
||||
install_certificate(cert_base64, cert_password)
|
||||
assert_certificate_installed(codesign_id)
|
||||
sign_bundle(codesign_id)
|
||||
dmg_path = build_dmg(filename_base)
|
||||
|
|
@ -51,13 +54,12 @@ def package(filename_base):
|
|||
def build_bundle():
|
||||
print("Building bundle...")
|
||||
# cmake build install target should run macdeployqt
|
||||
cmd_utils.run("cmake --build build --target install")
|
||||
cmd_utils.run("cmake --build build --target install", shell=True, print_cmd=True)
|
||||
|
||||
|
||||
def sign_bundle(codesign_id):
|
||||
print(f"Signing bundle {app_path}...")
|
||||
sys.stdout.flush()
|
||||
subprocess.run(
|
||||
cmd_utils.run(
|
||||
[
|
||||
codesign_path,
|
||||
"-f",
|
||||
|
|
@ -67,14 +69,16 @@ def sign_bundle(codesign_id):
|
|||
"-s",
|
||||
codesign_id,
|
||||
app_path,
|
||||
],
|
||||
check=True,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def assert_certificate_installed(codesign_id):
|
||||
installed = cmd_utils.run(
|
||||
"security find-identity -v -p codesigning", get_output=True
|
||||
"security find-identity -v -p codesigning",
|
||||
get_output=True,
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
if codesign_id not in installed.stdout:
|
||||
|
|
@ -122,18 +126,11 @@ def install_certificate(cert_base64, cert_password):
|
|||
if not cert_password:
|
||||
raise ValueError("Certificate password not provided")
|
||||
|
||||
print(f"Decoding certificate to: {cert_path}")
|
||||
cert_bytes = base64.b64decode(cert_base64)
|
||||
os.makedirs(os.path.dirname(cert_path), exist_ok=True)
|
||||
with open(cert_path, "wb") as cert_file:
|
||||
cert_file.write(cert_bytes)
|
||||
with Certificate(cert_base64, "p12") as cert_path:
|
||||
print(f"Installing certificate: {cert_path}")
|
||||
|
||||
print(f"Installing certificate: {cert_path}")
|
||||
sys.stdout.flush()
|
||||
|
||||
try:
|
||||
# warning: contains private key password, never print this command
|
||||
subprocess.run(
|
||||
# WARNING: contains private key password, never print this command
|
||||
cmd_utils.run(
|
||||
[
|
||||
sudo_path,
|
||||
security_path,
|
||||
|
|
@ -148,19 +145,7 @@ def install_certificate(cert_base64, cert_password):
|
|||
"-T",
|
||||
security_path,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# important: suppress the original args with `from None` to avoid leaking the password
|
||||
raise subprocess.CalledProcessError(e.returncode, security_path) from None
|
||||
except Exception as e:
|
||||
# important: suppress the original args with `from None` to avoid leaking the password
|
||||
raise RuntimeError(f"Command failed: {security_path}") from None
|
||||
finally:
|
||||
# not strictly necessary for ci, but when run on a dev machine, it reduces the risk
|
||||
# that private keys are left on the filesystem
|
||||
print(f"Removing temporary certificate file: {cert_path}")
|
||||
os.remove(cert_path)
|
||||
|
||||
|
||||
def notarize_package(dmg_path):
|
||||
|
|
@ -176,7 +161,9 @@ def notarize_package(dmg_path):
|
|||
|
||||
|
||||
def get_xcode_path():
|
||||
result = cmd_utils.run([xcode_select_path, "-p"], get_output=True, shell=False)
|
||||
result = cmd_utils.run(
|
||||
[xcode_select_path, "-p"], get_output=True, shell=False, print_cmd=True
|
||||
)
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
|
|
@ -193,31 +180,22 @@ class NotaryTool:
|
|||
|
||||
def store_credentials(self, user, password, team_id):
|
||||
print("Storing credentials for notary tool...")
|
||||
sys.stdout.flush()
|
||||
|
||||
notarytool_path = self.get_path()
|
||||
try:
|
||||
# warning: contains password, never print this command
|
||||
subprocess.run(
|
||||
[
|
||||
notarytool_path,
|
||||
"store-credentials",
|
||||
"notarytool-password",
|
||||
"--apple-id",
|
||||
user,
|
||||
"--team-id",
|
||||
team_id,
|
||||
"--password",
|
||||
password,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# important: suppress the original args with `from None` to avoid leaking the password
|
||||
raise subprocess.CalledProcessError(e.returncode, notarytool_path) from None
|
||||
except Exception as e:
|
||||
# important: suppress the original args with `from None` to avoid leaking the password
|
||||
raise RuntimeError(f"Command failed: {notarytool_path}") from None
|
||||
|
||||
# WARNING: contains password, never print this command
|
||||
cmd_utils.run(
|
||||
[
|
||||
notarytool_path,
|
||||
"store-credentials",
|
||||
"notarytool-password",
|
||||
"--apple-id",
|
||||
user,
|
||||
"--team-id",
|
||||
team_id,
|
||||
"--password",
|
||||
password,
|
||||
]
|
||||
)
|
||||
|
||||
def submit_and_wait(self, dmg_filename):
|
||||
print("Submitting notarization request...")
|
||||
|
|
@ -254,6 +232,7 @@ class NotaryTool:
|
|||
],
|
||||
get_output=True,
|
||||
shell=False,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
if result.stderr:
|
||||
|
|
@ -274,6 +253,7 @@ class NotaryTool:
|
|||
],
|
||||
get_output=True,
|
||||
shell=False,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
if result.stderr:
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
import ctypes
|
||||
import sys
|
||||
import os
|
||||
import ctypes, sys, os, shutil
|
||||
import xml.etree.ElementTree as ET
|
||||
from lib import cmd_utils
|
||||
import lib.cmd_utils as cmd_utils
|
||||
import lib.env as env
|
||||
from lib.certificate import Certificate
|
||||
|
||||
msbuild_cmd = "msbuild"
|
||||
signtool_cmd = "signtool"
|
||||
certutil_cmd = "certutil"
|
||||
cmake_env_var = "CMAKE_PREFIX_PATH"
|
||||
runner_temp_env_var = "RUNNER_TEMP"
|
||||
qt_base_dir_env_var = "QT_BASE_DIR"
|
||||
dist_dir = "dist"
|
||||
build_dir = "build"
|
||||
wix_solution_file = f"{build_dir}/installer/Synergy.sln"
|
||||
installer_file = f"{build_dir}/installer/bin/Release/Synergy.msi"
|
||||
|
||||
|
||||
def relaunch_as_admin(script):
|
||||
|
|
@ -39,7 +46,89 @@ def set_env_var(name, value):
|
|||
new_value = f"{current_value}{os.pathsep}{value}" if current_value else value
|
||||
os.environ[name] = new_value
|
||||
print(f"Setting environment variable: {name}={value}")
|
||||
cmd_utils.run(["setx", name, new_value], check=True)
|
||||
cmd_utils.run(["setx", name, new_value], check=True, shell=True, print_cmd=True)
|
||||
|
||||
|
||||
def package(filename_base):
|
||||
cert_base64 = env.get_env_var("WINDOWS_PFX_CERTIFICATE")
|
||||
cert_password = env.get_env_var("WINDOWS_PFX_PASSWORD")
|
||||
|
||||
sign_binaries(cert_base64, cert_password)
|
||||
build_msi(filename_base)
|
||||
sign_msi(filename_base, cert_base64, cert_password)
|
||||
|
||||
|
||||
def assert_vs_cmd(cmd):
|
||||
has_cmd = cmd_utils.has_command(cmd)
|
||||
if not has_cmd:
|
||||
raise RuntimeError(
|
||||
f"The '{cmd}' command was not found, "
|
||||
"re-run from 'Developer Command Prompt for VS'"
|
||||
)
|
||||
|
||||
|
||||
def build_msi(filename_base):
|
||||
print("Building MSI installer...")
|
||||
configuration = "Release"
|
||||
platform = "x64"
|
||||
|
||||
assert_vs_cmd(msbuild_cmd)
|
||||
cmd_utils.run(
|
||||
[
|
||||
msbuild_cmd,
|
||||
wix_solution_file,
|
||||
f"/p:Configuration={configuration}",
|
||||
f"/p:Platform={platform}",
|
||||
],
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
path = get_package_path(filename_base)
|
||||
print(f"Copying MSI installer to {dist_dir}")
|
||||
os.makedirs(dist_dir, exist_ok=True)
|
||||
shutil.copy(installer_file, path)
|
||||
|
||||
|
||||
def get_package_path(filename_base):
|
||||
return f"{dist_dir}/{filename_base}.msi"
|
||||
|
||||
|
||||
def sign_binaries(cert_base64, cert_password):
|
||||
exe_pattern = f"{build_dir}/bin/*.exe"
|
||||
run_codesign(exe_pattern, cert_base64, cert_password)
|
||||
|
||||
|
||||
def sign_msi(filename_base, cert_base64, cert_password):
|
||||
path = get_package_path(filename_base)
|
||||
run_codesign(path, cert_base64, cert_password)
|
||||
|
||||
|
||||
def run_codesign(path, cert_base64, cert_password):
|
||||
time_server = "http://timestamp.digicert.com"
|
||||
hashing_algorithm = "SHA256"
|
||||
|
||||
with Certificate(cert_base64, "pfx") as cert_path:
|
||||
print("Signing MSI installer...")
|
||||
assert_vs_cmd(signtool_cmd)
|
||||
|
||||
# WARNING: contains private key password, never print this command
|
||||
cmd_utils.run(
|
||||
[
|
||||
signtool_cmd,
|
||||
"sign",
|
||||
"/f",
|
||||
cert_path,
|
||||
"/p",
|
||||
cert_password,
|
||||
"/t",
|
||||
time_server,
|
||||
"/fd",
|
||||
hashing_algorithm,
|
||||
path,
|
||||
],
|
||||
shell=True,
|
||||
)
|
||||
|
||||
|
||||
class WindowsChoco:
|
||||
|
|
@ -49,10 +138,23 @@ class WindowsChoco:
|
|||
"""Installs packages using Chocolatey."""
|
||||
if ci_env:
|
||||
# don't show noisy choco progress bars in ci env
|
||||
cmd_utils.run(f"{command} --no-progress")
|
||||
cmd_utils.run(
|
||||
f"{command} --no-progress",
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
else:
|
||||
cmd_utils.run("winget install chocolatey", check=False)
|
||||
cmd_utils.run(command)
|
||||
cmd_utils.run(
|
||||
"winget install chocolatey",
|
||||
check=False,
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
cmd_utils.run(
|
||||
command,
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
def config_ci_cache(self):
|
||||
"""Configures Chocolatey cache for CI."""
|
||||
|
|
@ -62,7 +164,11 @@ class WindowsChoco:
|
|||
# sets the choco cache dir, which should match the dir in the ci cache action.
|
||||
key_arg = '--name="cacheLocation"'
|
||||
value_arg = f'--value="{runner_temp}/choco"'
|
||||
cmd_utils.run(["choco", "config", "set", key_arg, value_arg])
|
||||
cmd_utils.run(
|
||||
["choco", "config", "set", key_arg, value_arg],
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
else:
|
||||
print(f"Warning: CI environment variable {runner_temp_env_var} not set")
|
||||
|
||||
|
|
@ -102,13 +208,21 @@ class WindowsQt:
|
|||
def install(self):
|
||||
"""Installs Qt on Windows."""
|
||||
|
||||
cmd_utils.run(["pip", "install", "aqtinstall"])
|
||||
cmd_utils.run(
|
||||
["pip", "install", "aqtinstall"],
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
args = ["python", "-m", "aqt", "install-qt"]
|
||||
args.extend(["--outputdir", self.base_dir])
|
||||
args.extend(["--base", self.mirror_url])
|
||||
args.extend(["windows", "desktop", self.version, "win64_msvc2019_64"])
|
||||
cmd_utils.run(args)
|
||||
cmd_utils.run(
|
||||
args,
|
||||
shell=True,
|
||||
print_cmd=True,
|
||||
)
|
||||
|
||||
install_dir = self.get_install_dir()
|
||||
if not install_dir:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import platform
|
||||
from lib import env
|
||||
import lib.env as env
|
||||
|
||||
env_file = ".env"
|
||||
package_filename_product = "synergy"
|
||||
|
|
@ -33,16 +33,17 @@ def main():
|
|||
def get_filename_base(version):
|
||||
os = env.get_os()
|
||||
machine = platform.machine().lower()
|
||||
return f"{package_filename_product}-{version}-{os}-{machine}"
|
||||
return f"{package_filename_product}-{os}-{machine}-{version}"
|
||||
|
||||
|
||||
def windows_package(filename_base):
|
||||
"""TODO: Windows packaging"""
|
||||
pass
|
||||
import lib.windows as windows
|
||||
|
||||
windows.package(filename_base)
|
||||
|
||||
|
||||
def mac_package(filename_base):
|
||||
from lib import mac
|
||||
import lib.mac as mac
|
||||
|
||||
mac.package(filename_base)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import subprocess
|
|||
import sys
|
||||
import argparse
|
||||
import glob
|
||||
from lib import windows
|
||||
import lib.windows as windows
|
||||
|
||||
BIN_NAME = "synergyd"
|
||||
SOURCE_BIN_DIR = os.path.join("build", "bin")
|
||||
|
|
|
|||
|
|
@ -14,21 +14,26 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target synergy-core)
|
||||
|
||||
set(sources
|
||||
synergy-core.cpp
|
||||
${target}.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND sources synergy-core.exe.manifest)
|
||||
list(APPEND sources
|
||||
${target}.exe.manifest
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable(synergy-core ${sources})
|
||||
target_link_libraries(synergy-core
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target}
|
||||
arch base client common io mt net ipc platform server synlib ${libs})
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
install (TARGETS synergy-core DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
install (TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
install (TARGETS synergy-core DESTINATION bin)
|
||||
install (TARGETS ${target} DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target synergyc)
|
||||
|
||||
set(sources
|
||||
synergyc.cpp
|
||||
${target}.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
@ -23,13 +25,14 @@ if (WIN32)
|
|||
file(GLOB arch_sources "MSWindows*.cpp")
|
||||
list(APPEND sources
|
||||
resource.h
|
||||
synergyc.ico
|
||||
synergyc.rc
|
||||
${target}.ico
|
||||
${target}.rc
|
||||
tb_error.ico
|
||||
tb_idle.ico
|
||||
tb_run.ico
|
||||
tb_wait.ico
|
||||
synergyc.exe.manifest
|
||||
${target}.exe.manifest
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
)
|
||||
elseif (APPLE)
|
||||
file(GLOB arch_headers "OSX*.h")
|
||||
|
|
@ -46,13 +49,13 @@ if (SYNERGY_ADD_HEADERS)
|
|||
list(APPEND sources ${headers})
|
||||
endif()
|
||||
|
||||
add_executable(synergyc ${sources})
|
||||
target_link_libraries(synergyc
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target}
|
||||
arch base client common io mt net ipc platform server synlib ${libs})
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
install (TARGETS synergyc DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
install (TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
install (TARGETS synergyc DESTINATION bin)
|
||||
install (TARGETS ${target} DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,14 +14,21 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target synergyd)
|
||||
|
||||
file(GLOB headers "*.h")
|
||||
file(GLOB sources "*.cpp")
|
||||
|
||||
if (WIN32)
|
||||
add_executable (synergyd WIN32 ${sources})
|
||||
add_executable (
|
||||
${target}
|
||||
WIN32
|
||||
${sources}
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
)
|
||||
else()
|
||||
add_executable (synergyd ${sources})
|
||||
add_executable (${target} ${sources})
|
||||
endif()
|
||||
|
||||
target_link_libraries (synergyd
|
||||
target_link_libraries (${target}
|
||||
arch base common io ipc mt net platform synlib shared ${libs})
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target synergys)
|
||||
|
||||
set(sources
|
||||
synergys.cpp
|
||||
${target}.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
@ -23,13 +25,14 @@ if (WIN32)
|
|||
file(GLOB arch_sources "MSWindows*.cpp")
|
||||
list(APPEND sources
|
||||
resource.h
|
||||
synergys.ico
|
||||
synergys.rc
|
||||
${target}.ico
|
||||
${target}.rc
|
||||
tb_error.ico
|
||||
tb_idle.ico
|
||||
tb_run.ico
|
||||
tb_wait.ico
|
||||
synergys.exe.manifest
|
||||
${target}.exe.manifest
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
)
|
||||
elseif (APPLE)
|
||||
file(GLOB arch_headers "OSX*.h")
|
||||
|
|
@ -46,14 +49,14 @@ if (SYNERGY_ADD_HEADERS)
|
|||
list(APPEND sources ${headers})
|
||||
endif()
|
||||
|
||||
add_executable(synergys ${sources})
|
||||
target_link_libraries(synergys
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target}
|
||||
arch base client common io mt net ipc platform server synlib ${libs})
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
install (TARGETS synergys DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
install (TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
install (TARGETS synergys DESTINATION bin)
|
||||
install (TARGETS ${target} DESTINATION bin)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,21 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target syntool)
|
||||
|
||||
file(GLOB headers "*.h")
|
||||
file(GLOB sources "*.cpp")
|
||||
|
||||
add_executable(syntool ${sources})
|
||||
target_link_libraries(syntool
|
||||
if (WIN32)
|
||||
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
||||
endif()
|
||||
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target}
|
||||
synlib arch base client common io ipc mt net platform server ${libs})
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
install (TARGETS syntool DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
install (TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
install (TARGETS syntool DESTINATION bin)
|
||||
install (TARGETS ${target} DESTINATION bin)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -4,28 +4,28 @@ set (CMAKE_AUTORCC ON)
|
|||
set (CMAKE_AUTOUIC ON)
|
||||
set (CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
file (GLOB LEGACY_GUI_SOURCE_FILES
|
||||
file (GLOB GUI_SOURCE_FILES
|
||||
src/*.cpp
|
||||
src/*.h
|
||||
src/validators/*
|
||||
src/widgets/*
|
||||
)
|
||||
file (GLOB LEGACY_GUI_UI_FILES src/*.ui)
|
||||
file (GLOB LEGACY_ACTIVATION_FILES src/*Activation* src/*License*)
|
||||
file (GLOB LEGACY_ZEROCONF_FILES src/Zeroconf*)
|
||||
file (GLOB LEGACY_LANGUAGE_FILES res/lang/*.ts)
|
||||
file (GLOB GUI_UI_FILES src/*.ui)
|
||||
file (GLOB ACTIVATION_FILES src/*Activation* src/*License*)
|
||||
file (GLOB ZEROCONF_FILES src/Zeroconf*)
|
||||
file (GLOB LANGUAGE_FILES res/lang/*.ts)
|
||||
|
||||
configure_file(res/Languages.qrc res/Languages.qrc)
|
||||
|
||||
set_source_files_properties(${LEGACY_LANGUAGE_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/res/lang")
|
||||
set_source_files_properties(${LANGUAGE_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/res/lang")
|
||||
|
||||
qt5_add_translation(QM_FILES ${LEGACY_LANGUAGE_FILES})
|
||||
qt5_add_translation(QM_FILES ${LANGUAGE_FILES})
|
||||
|
||||
add_custom_target(translations ALL DEPENDS ${QM_FILES})
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
file (GLOB LEGACY_GUI_MAC_SOURCE_FILES src/*.mm)
|
||||
list (APPEND LEGACY_GUI_SOURCE_FILES ${LEGACY_GUI_MAC_SOURCE_FILES})
|
||||
file (GLOB GUI_MAC_SOURCE_FILES src/*.mm)
|
||||
list (APPEND GUI_SOURCE_FILES ${GUI_MAC_SOURCE_FILES})
|
||||
endif()
|
||||
|
||||
# Retrieve the absolute path to qmake and then use that path to find
|
||||
|
|
@ -36,21 +36,24 @@ find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
|
|||
find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS "${_qt_bin_dir}")
|
||||
|
||||
if (SYNERGY_ENTERPRISE)
|
||||
list (REMOVE_ITEM LEGACY_GUI_SOURCE_FILES ${LEGACY_ACTIVATION_FILES})
|
||||
list (REMOVE_ITEM LEGACY_GUI_UI_FILES ${LEGACY_ACTIVATION_FILES})
|
||||
list (REMOVE_ITEM GUI_SOURCE_FILES ${ACTIVATION_FILES})
|
||||
list (REMOVE_ITEM GUI_UI_FILES ${ACTIVATION_FILES})
|
||||
endif ()
|
||||
|
||||
list (REMOVE_ITEM LEGACY_GUI_SOURCE_FILES ${LEGACY_ZEROCONF_FILES})
|
||||
list (REMOVE_ITEM GUI_SOURCE_FILES ${ZEROCONF_FILES})
|
||||
|
||||
|
||||
if (WIN32)
|
||||
set (LEGACY_GUI_RC_FILES res/win/Synergy.rc)
|
||||
set (GUI_RC_FILES
|
||||
res/win/Synergy.rc
|
||||
${CMAKE_BINARY_DIR}/src/version.rc
|
||||
)
|
||||
endif()
|
||||
|
||||
add_executable (synergy WIN32
|
||||
${LEGACY_GUI_SOURCE_FILES}
|
||||
${LEGACY_GUI_UI_FILES}
|
||||
${LEGACY_GUI_RC_FILES}
|
||||
${GUI_SOURCE_FILES}
|
||||
${GUI_UI_FILES}
|
||||
${GUI_RC_FILES}
|
||||
res/Synergy.qrc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/res/Languages.qrc
|
||||
${QM_FILES}
|
||||
|
|
@ -59,7 +62,7 @@ add_executable (synergy WIN32
|
|||
include_directories (./src)
|
||||
target_link_libraries (synergy shared)
|
||||
|
||||
qt5_use_modules (synergy Core Widgets Network)
|
||||
target_link_libraries(synergy Qt5::Core Qt5::Widgets Qt5::Network)
|
||||
target_compile_definitions (synergy PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
|
||||
target_compile_definitions (synergy PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}")
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ AboutDialog::AboutDialog(MainWindow* parent, const AppConfig& config) :
|
|||
setupUi(this);
|
||||
|
||||
m_versionChecker.setApp(parent->appPath(config.synergycName()));
|
||||
QString version = m_versionChecker.getVersion();
|
||||
m_pLabelSynergyVersion->setText(version);
|
||||
m_pLabelSynergyVersion->setText(SYNERGY_VERSION);
|
||||
|
||||
QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified();
|
||||
QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy");
|
||||
|
|
|
|||
|
|
@ -188,11 +188,10 @@ MainWindow::MainWindow (AppConfig& appConfig,
|
|||
updateWindowTitle();
|
||||
|
||||
QString lastVersion = m_AppConfig->lastVersion();
|
||||
QString currentVersion = m_VersionChecker.getVersion();
|
||||
if (lastVersion != currentVersion) {
|
||||
m_AppConfig->setLastVersion (currentVersion);
|
||||
if (lastVersion != SYNERGY_VERSION) {
|
||||
m_AppConfig->setLastVersion (SYNERGY_VERSION);
|
||||
#ifndef SYNERGY_ENTERPRISE
|
||||
m_LicenseManager->notifyUpdate (lastVersion, currentVersion);
|
||||
m_LicenseManager->notifyUpdate (lastVersion, SYNERGY_VERSION);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,12 +24,8 @@
|
|||
#include <QProcess>
|
||||
#include <QLocale>
|
||||
|
||||
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+-[a-z1-9]*)"
|
||||
#define VERSION_REGEX_SECTIONED "(\\d+)\\.(\\d+)\\.(\\d+)-([a-z1-9]*)"
|
||||
#define VERSION_SEGMENT_COUNT 4
|
||||
#define VERSION_URL "https://api.symless.com/version"
|
||||
|
||||
|
||||
VersionChecker::VersionChecker()
|
||||
{
|
||||
m_manager = new QNetworkAccessManager(this);
|
||||
|
|
@ -46,53 +42,52 @@ VersionChecker::~VersionChecker()
|
|||
void VersionChecker::checkLatest()
|
||||
{
|
||||
auto request = QNetworkRequest(QUrl(VERSION_URL));
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Synergy (") + getVersion() + ") " + QSysInfo::prettyProductName());
|
||||
request.setRawHeader("X-Synergy-Version", getVersion().toStdString().c_str() );
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Synergy (") + SYNERGY_VERSION + ") " + QSysInfo::prettyProductName());
|
||||
request.setRawHeader("X-Synergy-Version", SYNERGY_VERSION );
|
||||
request.setRawHeader("X-Synergy-Language", QLocale::system().name().toStdString().c_str() );
|
||||
m_manager->get(request);
|
||||
}
|
||||
|
||||
void VersionChecker::replyFinished(QNetworkReply* reply)
|
||||
{
|
||||
QString newestVersion = QString(reply->readAll());
|
||||
if (!newestVersion.isEmpty())
|
||||
{
|
||||
QString currentVersion = getVersion();
|
||||
if (currentVersion != "Unknown") {
|
||||
if (compareVersions(currentVersion, newestVersion) > 0)
|
||||
emit updateFound(newestVersion);
|
||||
}
|
||||
auto newestVersion = QString(reply->readAll());
|
||||
if (!newestVersion.isEmpty() && compareVersions(SYNERGY_VERSION, newestVersion) > 0) {
|
||||
emit updateFound(newestVersion);
|
||||
}
|
||||
}
|
||||
|
||||
int VersionChecker::getStageVersion(QString stage)
|
||||
int VersionChecker::getStageVersion(QString stage) const
|
||||
{
|
||||
const int valueStable = INT_MAX; //Stable will always be considered the highest value
|
||||
const int valueRC = 2;
|
||||
const int valueSnapshot = 1;
|
||||
const int valueOther = 0;
|
||||
const char* stableName = "stable";
|
||||
const char* rcName = "rc";
|
||||
const char* betaName = "beta";
|
||||
|
||||
//Stable should always be considered highest, followed by rc[0-9] then snapshots with everything else at the end
|
||||
//HACK There is probably a much better way of doing this
|
||||
if (stage == "stable")
|
||||
// use max int for stable so it's always the highest value.
|
||||
const int stableValue = INT_MAX;
|
||||
const int rcValue = 2;
|
||||
const int betaValue = 1;
|
||||
const int otherValue = 0;
|
||||
|
||||
if (stage == stableName)
|
||||
{
|
||||
return valueStable;
|
||||
return stableValue;
|
||||
}
|
||||
else if (stage.startsWith("rc") || stage.startsWith("RC"))
|
||||
else if (stage.toLower().startsWith(rcName))
|
||||
{
|
||||
QRegExp rx("\\d*", Qt::CaseInsensitive);
|
||||
if (rx.indexIn(stage) != -1)
|
||||
{
|
||||
//Return the RC value plus the RC version as in int
|
||||
return valueRC + rx.cap(1).toInt();
|
||||
// return the rc value plus the rc number (e.g. 2 + 1)
|
||||
// this should be ok since stable is max int.
|
||||
return rcValue + rx.cap(1).toInt();
|
||||
}
|
||||
}
|
||||
else if (stage == "snapshot")
|
||||
else if (stage == betaName)
|
||||
{
|
||||
return valueSnapshot;
|
||||
return betaValue;
|
||||
}
|
||||
|
||||
return valueOther;
|
||||
|
||||
return otherValue;
|
||||
}
|
||||
|
||||
int VersionChecker::compareVersions(const QString& left, const QString& right)
|
||||
|
|
@ -100,48 +95,34 @@ int VersionChecker::compareVersions(const QString& left, const QString& right)
|
|||
if (left.compare(right) == 0)
|
||||
return 0; // versions are same.
|
||||
|
||||
QStringList leftSplit = left.split(QRegExp("[\\.-]"));
|
||||
if (leftSplit.size() != VERSION_SEGMENT_COUNT)
|
||||
return 1; // assume right wins.
|
||||
QStringList leftParts = left.split("-");
|
||||
QStringList rightParts = right.split("-");
|
||||
|
||||
QStringList rightSplit = right.split(QRegExp("[\\.-]"));
|
||||
if (rightSplit.size() != VERSION_SEGMENT_COUNT)
|
||||
return -1; // assume left wins.
|
||||
if (leftParts.size() < 1 || rightParts.size() < 1)
|
||||
return 0; // versions are same.
|
||||
|
||||
const int leftMajor = leftSplit.at(0).toInt();
|
||||
const int leftMinor = leftSplit.at(1).toInt();
|
||||
const int leftRev = leftSplit.at(2).toInt();
|
||||
const int leftStage = getStageVersion(leftSplit.at(3));
|
||||
QString leftNumber = leftParts.at(0);
|
||||
QString rightNumber = rightParts.at(0);
|
||||
|
||||
const int rightMajor = rightSplit.at(0).toInt();
|
||||
const int rightMinor = rightSplit.at(1).toInt();
|
||||
const int rightRev = rightSplit.at(2).toInt();
|
||||
const int rightStage = getStageVersion(rightSplit.at(3));
|
||||
QStringList leftNumberParts = left.split(".");
|
||||
QStringList rightNumberParts = right.split(".");
|
||||
|
||||
const int leftMajor = leftNumberParts.at(0).toInt();
|
||||
const int leftMinor = leftNumberParts.at(1).toInt();
|
||||
const int leftPatch = leftNumberParts.at(2).toInt();
|
||||
const int leftStage = leftParts.size() > 1 ? getStageVersion(leftParts.at(1)) : 0;
|
||||
|
||||
const int rightMajor = rightNumberParts.at(0).toInt();
|
||||
const int rightMinor = rightNumberParts.at(1).toInt();
|
||||
const int rightPatch = rightNumberParts.at(2).toInt();
|
||||
const int rightStage = rightParts.size() > 1 ? getStageVersion(rightParts.at(1)) : 0;
|
||||
|
||||
const bool rightWins =
|
||||
( rightMajor > leftMajor) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor > leftMinor)) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev)) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev >= leftRev) && (rightStage > leftStage));
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightPatch > leftPatch)) ||
|
||||
((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightPatch >= leftPatch) && (rightStage > leftStage));
|
||||
|
||||
return rightWins ? 1 : -1;
|
||||
}
|
||||
|
||||
QString VersionChecker::getVersion()
|
||||
{
|
||||
QProcess process;
|
||||
process.start(m_app, QStringList() << "--version");
|
||||
|
||||
process.setReadChannel(QProcess::StandardOutput);
|
||||
if (process.waitForStarted() && process.waitForFinished())
|
||||
{
|
||||
QRegExp rx(VERSION_REGEX,Qt::CaseInsensitive);
|
||||
QString text = process.readLine();
|
||||
if (rx.indexIn(text) != -1)
|
||||
{
|
||||
return rx.cap(1);
|
||||
}
|
||||
}
|
||||
|
||||
return tr("Unknown");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ public:
|
|||
VersionChecker();
|
||||
virtual ~VersionChecker();
|
||||
void checkLatest();
|
||||
QString getVersion();
|
||||
void setApp(const QString& app) { m_app = app; }
|
||||
int compareVersions(const QString& left, const QString& right);
|
||||
public slots:
|
||||
|
|
@ -47,5 +46,5 @@ private:
|
|||
* \param stage The string containing the stage version
|
||||
* \return An integer representation of the stage, the higher the number the more recent the version
|
||||
*/
|
||||
int getStageVersion(QString stage);
|
||||
int getStageVersion(QString stage) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,6 +53,10 @@ if (SYNERGY_ADD_HEADERS)
|
|||
list(APPEND sources ${headers})
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
../../
|
||||
../../lib/
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(target unittests)
|
||||
|
||||
file(GLOB_RECURSE headers "*.h" "languages/*.h")
|
||||
file(GLOB_RECURSE sources "*.cpp" "languages/*.cpp")
|
||||
|
||||
|
|
@ -60,6 +62,10 @@ if (SYNERGY_ADD_HEADERS)
|
|||
list(APPEND sources ${headers})
|
||||
endif()
|
||||
|
||||
add_executable(unittests ${sources})
|
||||
target_link_libraries(unittests
|
||||
if (WIN32)
|
||||
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
||||
endif()
|
||||
|
||||
add_executable(${target} ${sources})
|
||||
target_link_libraries(${target}
|
||||
arch base client server common io net platform server synlib mt ipc gtest gmock shared ${libs})
|
||||
|
|
|
|||
0
test
0
test
Loading…
Reference in a new issue