diff --git a/README.md b/README.md index d7789cd2..6332db37 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,32 @@ When possible, access your Qt directory through the `QT_ROOT_DIR` environment va Default: `$RUNNER_WORKSPACE` (this is one folder above the starting directory) +### `use-commercial` (since `v4.3.0`) +Whether or not to use `aqtinstall` to install Qt using its official online installer enabling the commercial versions for those owning a license. +For this to work, you need to also set `aqtsource` to `git+https://github.com/Kidev/aqtinstall.git@install_qt_commercial`. +The parameter `host` will then be ignored, as you can only install commercial Qt versions on the OS running the installer. +Example: +```yml + - name: Install Qt + uses: jurplel/install-qt-action@v4 + with: + version: '5.15.3' + target: 'desktop' + arch: 'win64_msvc2019_64' + aqtsource: 'git+https://github.com/Kidev/aqtinstall.git@install_qt_commercial' + use-commercial: true + user: '****@gmail.com' + password: '****' +``` + +Default: `false` + +#### `user` +If `use-commercial` is true, will use this username/email to authenticate with Qt servers + +#### `password` +If `use-commercial` is true, will use this password to authenticate with Qt servers + ### `install-deps` Whether or not to automatically install Qt dependencies on Linux through `apt`. diff --git a/action.yml b/action.yml index 9c4d9960..635aeded 100644 --- a/action.yml +++ b/action.yml @@ -58,7 +58,7 @@ inputs: default: ==3.2.* py7zrversion: description: Version of py7zr to use in case of issues - default: ==0.20.* + default: ==0.22.* extra: description: Any extra arguments to append to the back source: @@ -80,6 +80,15 @@ inputs: description: Space-separated list of .7z example archives to install. Used to reduce download/image sizes. example-modules: description: Space-separated list of additional example modules to install. + use-commercial: + default: false + description: Whether or not to use aqtinstall to install the commercial version of Qt + user: + default: 'username' + description: Your Qt username + password: + default: 'password' + description: Your Qt password runs: using: "composite" steps: @@ -87,7 +96,7 @@ runs: if: ${{ inputs.setup-python == 'true' }} uses: actions/setup-python@v5 with: - python-version: '3.6.x - 3.12.x' + python-version: '3.6.x - 3.13.x' - name: Setup and run aqtinstall uses: ./action @@ -119,3 +128,6 @@ runs: example-archives: ${{ inputs.example-archives }} example-modules: ${{ inputs.example-modules }} extra: ${{ inputs.extra }} + use-commercial: ${{ inputs.use-commercial }} + user: ${{ inputs.user }} + password: ${{ inputs.password }} diff --git a/action/action.yml b/action/action.yml index fca7d90a..ec481e73 100644 --- a/action/action.yml +++ b/action/action.yml @@ -55,7 +55,7 @@ inputs: default: ==3.2.* py7zrversion: description: Version of py7zr to use in case of issues - default: ==0.20.* + default: ==0.22.* extra: description: Any extra arguments to append to the back source: @@ -77,6 +77,15 @@ inputs: description: Space-separated list of .7z example archives to install. Used to reduce download/image sizes. example-modules: description: Space-separated list of additional example modules to install. + use-commercial: + default: false + description: Whether or not to use aqtinstall to install the commercial version of Qt + user: + default: 'username' + description: Your Qt username + password: + default: 'password' + description: Your Qt password runs: using: node20 main: lib/main.js diff --git a/action/src/main.ts b/action/src/main.ts index cb14bd26..f71aa647 100644 --- a/action/src/main.ts +++ b/action/src/main.ts @@ -56,6 +56,7 @@ const pythonCommand = (command: string, args: readonly string[]): string => { const python = process.platform === "win32" ? "python" : "python3"; return `${python} -m ${command} ${args.join(" ")}`; }; + const execPython = async (command: string, args: readonly string[]): Promise => { return exec(pythonCommand(command, args)); }; @@ -97,6 +98,55 @@ const locateQtArchDir = (installDir: string): string => { } }; +const locateQtWasmHostArchDir = ( + installDir: string, + hostType: "windows" | "mac" | "linux" | "all_os", + target: "desktop" | "android" | "ios" | "wasm", + version: string +): string => { + // For WASM in all_os mode, use the host builder directory + if (hostType === "all_os" && target === "wasm") { + const versionDir = path.join(installDir, version); + + switch (process.platform) { + case "win32": { + // Find mingw directories + const mingwPattern = /^win\d+_mingw\d+$/; + const mingwArches = glob + .sync(`${versionDir}/*/`) + .map((dir) => path.basename(dir)) + .filter((dir) => mingwPattern.test(dir)) + .sort((a, b) => { + const [aBits, aVer] = a + .match(/win(\d+)_mingw(\d+)/) + ?.slice(1) + .map(Number) ?? [0, 0]; + const [bBits, bVer] = b + .match(/win(\d+)_mingw(\d+)/) + ?.slice(1) + .map(Number) ?? [0, 0]; + if (aBits !== bBits) return bBits - aBits; + return bVer - aVer; + }); + + if (!mingwArches.length) { + throw Error(`Failed to locate a MinGW directory for WASM host in ${versionDir}`); + } + return path.join(versionDir, mingwArches[0]); + } + case "darwin": + return path.join(versionDir, "clang_64"); + default: + return path.join( + versionDir, + compareVersions(version, ">=", "6.7.0") ? "linux_gcc_64" : "gcc_64" + ); + } + } + + return locateQtArchDir(installDir); +}; + const isAutodesktopSupported = async (): Promise => { const rawOutput = await getPythonOutput("aqt", ["version"]); const match = rawOutput.match(/aqtinstall\(aqt\)\s+v(\d+\.\d+\.\d+)/); @@ -136,6 +186,10 @@ class Inputs { readonly aqtVersion: string; readonly py7zrVersion: string; + readonly useCommercial: boolean; + readonly user: string; + readonly password: string; + constructor() { const host = core.getInput("host"); // Set host automatically if omitted @@ -242,6 +296,10 @@ class Inputs { this.py7zrVersion = core.getInput("py7zrversion"); + this.useCommercial = Inputs.getBoolInput("use-commercial"); + this.user = core.getInput("user"); + this.password = core.getInput("password"); + this.src = Inputs.getBoolInput("source"); this.srcArchives = Inputs.getStringArrayInput("src-archives"); @@ -267,6 +325,7 @@ class Inputs { this.py7zrVersion, this.aqtSource, this.aqtVersion, + this.useCommercial ? "commercial" : "", ], this.modules, this.archives, @@ -386,19 +445,34 @@ const run = async (): Promise => { // Install Qt if (inputs.isInstallQtBinaries) { - const qtArgs = [ - inputs.host, - inputs.target, - inputs.version, - ...(inputs.arch ? [inputs.arch] : []), - ...autodesktop, - ...["--outputdir", inputs.dir], - ...flaggedList("--modules", inputs.modules), - ...flaggedList("--archives", inputs.archives), - ...inputs.extra, - ]; - - await execPython("aqt install-qt", qtArgs); + if (inputs.useCommercial && inputs.user && inputs.password) { + const qtArgs = [ + "install-qt-commercial", + inputs.target, + ...(inputs.arch ? [inputs.arch] : []), + inputs.version, + ...["--outputdir", inputs.dir], + ...["--user", inputs.user], + ...["--password", inputs.password], + ...flaggedList("--modules", inputs.modules), + ...inputs.extra, + ]; + await execPython("aqt", qtArgs); + } else { + const qtArgs = [ + "install-qt", + inputs.host, + inputs.target, + inputs.version, + ...(inputs.arch ? [inputs.arch] : []), + ...autodesktop, + ...["--outputdir", inputs.dir], + ...flaggedList("--modules", inputs.modules), + ...flaggedList("--archives", inputs.archives), + ...inputs.extra, + ]; + await execPython("aqt", qtArgs); + } } const installSrcDocExamples = async ( @@ -455,7 +529,7 @@ const run = async (): Promise => { } // Set environment variables/outputs for binaries if (inputs.isInstallQtBinaries) { - const qtPath = locateQtArchDir(inputs.dir); + const qtPath = locateQtWasmHostArchDir(inputs.dir, inputs.host, inputs.target, inputs.version); // Set outputs core.setOutput("qtPath", qtPath);