├── src ├── react-app-env.d.ts ├── config.json ├── aqt-list-qt-ts │ ├── test_data │ │ ├── official_releases.json │ │ ├── windows-59-expect.json │ │ ├── windows-620-expect.json │ │ ├── windows-desktop-expect.json │ │ ├── windows-desktop-directory.json │ │ ├── windows-desktop-tools_vcredist-update.json │ │ ├── windows-desktop-tools_vcredist-expect.json │ │ ├── windows-620-wasm-update.json │ │ └── windows-59-update.json │ ├── list-qt.test.ts │ ├── list-qt.ts │ ├── functional.test.ts │ ├── list-qt-impl.ts │ └── list-qt-impl.test.ts ├── index.tsx ├── Components │ ├── CheckBox.test.tsx │ ├── CommandPanel.tsx │ ├── PackageDetailPanel.tsx │ ├── CheckBox.tsx │ ├── SelectMany.tsx │ ├── QtSelectorPanel.tsx │ ├── ToolSelectPanel.tsx │ └── ComboBox.tsx ├── app.scss ├── lib │ ├── Result.ts │ ├── Result.test.ts │ ├── utils.ts │ ├── Actions.ts │ └── types.ts ├── App.tsx ├── State.test.ts └── State.ts ├── setupJest.ts ├── .gitignore ├── .eslintrc.js ├── .vscode └── launch.json ├── tsconfig.json ├── LICENSE ├── CHANGELOG.md ├── .github └── workflows │ └── deploy.yml ├── package.json ├── public └── index.html └── README.md /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /setupJest.ts: -------------------------------------------------------------------------------- 1 | import fetchMock from "jest-fetch-mock"; 2 | fetchMock.enableMocks(); 3 | -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "QT_JSON_CACHE_BASE_URL": "https://ddalcino.github.io/qt-repo-cache/public", 3 | "RECOMMEND_AQT_VERSION": "3.1.*", 4 | "REQUIRED_PY7ZR": null, 5 | "POSTSCRIPT": null 6 | } -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/official_releases.json: -------------------------------------------------------------------------------- 1 | { 2 | "online_installers/": { 3 | "qt-unified-windows-x64-online.exe": "41M", 4 | "qt-unified-mac-x64-online.dmg": "18M", 5 | "qt-unified-linux-x64-online.run": "55M" 6 | } 7 | } -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById("root") 10 | ); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /venv 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | *.log 22 | 23 | /**/__pycache__ 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # IDE 30 | /.idea 31 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: "@typescript-eslint/parser", 4 | plugins: ["@typescript-eslint", "prettier"], 5 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 6 | ignorePatterns: ["old/**/*", "temp.js", "**/vendor/*.js"], 7 | rules: { 8 | "prettier/prettier": "error", 9 | '@typescript-eslint/no-unused-vars': [ 10 | 'warn', 11 | { 12 | argsIgnorePattern: '^_', 13 | varsIgnorePattern: '^_', 14 | }, 15 | ], 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:8080", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/Components/CheckBox.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "@testing-library/react"; 3 | import CheckBox from "./CheckBox"; 4 | 5 | test.skip("renders a checkbox", () => { 6 | const [id, name, isChecked] = ["myId", "This_is_ok", true]; 7 | let hasFiredCallback = false; 8 | const { getByText } = render( 9 | { 16 | hasFiredCallback = true; 17 | }} 18 | /> 19 | ); 20 | const linkElement = getByText(/something/i); 21 | expect(linkElement).toBeInTheDocument(); 22 | }); 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "downlevelIteration": true 23 | }, 24 | "include": [ 25 | "src" 26 | ] 27 | } -------------------------------------------------------------------------------- /src/app.scss: -------------------------------------------------------------------------------- 1 | 2 | .horizontal-flow { 3 | display: flex; 4 | flex-direction: row; 5 | 6 | > div { 7 | flex-grow: 1; 8 | margin: 1em; 9 | } 10 | } 11 | 12 | .vertical-flow { 13 | display: flex; 14 | flex-direction: column; 15 | 16 | > div { 17 | margin: 1em; 18 | } 19 | } 20 | 21 | body { 22 | font-family: SansSerif, sans-serif; 23 | } 24 | 25 | pre { 26 | padding: 1em; 27 | overflow-x: auto; 28 | border-left: 0.2em solid blue; 29 | background-color: lightgrey; 30 | } 31 | pre code { 32 | white-space: pre-wrap; 33 | } 34 | 35 | .clipboard-copy-btn { 36 | cursor: pointer; 37 | } 38 | 39 | .clipboard-copy-btn:disabled { 40 | cursor: not-allowed; 41 | } 42 | 43 | select:disabled { 44 | cursor: not-allowed; 45 | } 46 | 47 | select.loading { 48 | cursor: wait; 49 | } 50 | 51 | .top-right { 52 | position: absolute; 53 | top: 0; 54 | right: 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/Components/CommandPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface Props { 4 | id: string; 5 | label: JSX.Element; 6 | command: string; 7 | children?: JSX.Element; 8 | isDisabled: boolean; 9 | } 10 | 11 | const copyToClipboard = async (text: string) => { 12 | await navigator.clipboard.writeText(text); 13 | }; 14 | 15 | const CommandPanel = (props: Props): JSX.Element => { 16 | const { id, label, command, children, isDisabled } = props; 17 | return ( 18 |
19 | {label} 20 |
21 |         {command}
22 |       
23 | copyToClipboard(command)} 29 | disabled={isDisabled} 30 | /> 31 | {children} 32 |
33 | ); 34 | }; 35 | export default CommandPanel; 36 | -------------------------------------------------------------------------------- /src/Components/PackageDetailPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { packageNameToModuleName, PackageUpdate } from "../lib/types"; 3 | 4 | interface Props { 5 | pkg: PackageUpdate; 6 | } 7 | 8 | const PackageDetailPanel = ({ pkg }: Props): JSX.Element => ( 9 |
10 | 11 | {packageNameToModuleName(pkg.Name)}: {pkg.DisplayName} 12 | 13 | {pkg.Description ? ( 14 |
15 | Description: {pkg.Description} 16 |
17 | ) : null} 18 |
19 | Fully Qualified Name {pkg.Name} 20 |
21 |
22 | Release Date: {pkg.ReleaseDate} 23 |
24 |
25 | Version: {pkg.Version} 26 |
27 |
28 | Download Size: {pkg.CompressedSize} 29 |
30 |
31 | Installed Size: {pkg.UncompressedSize} 32 |
33 |
34 | ); 35 | 36 | export default PackageDetailPanel; 37 | -------------------------------------------------------------------------------- /src/lib/Result.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * oops I got a Rust concept in my Typescript! 3 | * https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html 4 | */ 5 | 6 | const enum Status { 7 | Ok, 8 | Err, 9 | } 10 | class Result { 11 | private constructor(private status: Status, private content: Ok | Err) {} 12 | 13 | public match( 14 | ok: (content: Ok) => OkOut, 15 | err: (content: Err) => ErrOut 16 | ): OkOut | ErrOut { 17 | switch (this.status) { 18 | case Status.Ok: 19 | return ok(this.content as Ok); 20 | case Status.Err: 21 | return err(this.content as Err); 22 | } 23 | } 24 | public unwrap(): Ok { 25 | return this.match( 26 | (res) => res, 27 | (err) => { 28 | throw err; 29 | } 30 | ); 31 | } 32 | public static Ok(content: Ok): Result { 33 | return new Result(Status.Ok, content); 34 | } 35 | public static Err(content: Err): Result { 36 | return new Result(Status.Err, content); 37 | } 38 | } 39 | 40 | export default Result; 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 David Dalcino 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Components/CheckBox.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { PackageUpdate } from "../lib/types"; 3 | import PackageDetailPanel from "./PackageDetailPanel"; 4 | 5 | interface Props { 6 | id: string; 7 | name: string; 8 | pkg: PackageUpdate | null; 9 | size: string | null; 10 | isChecked: boolean; 11 | onChange: (event: React.ChangeEvent) => void; 12 | } 13 | 14 | const CheckBox = ({ 15 | id, 16 | name, 17 | pkg, 18 | size, 19 | isChecked, 20 | onChange, 21 | }: Props): JSX.Element => ( 22 |
23 | ) => onChange(event)}//onChange} 28 | onChange={onChange} 29 | style={{ display: "inline-block" }} 30 | /> 31 | 40 | {/**/} 41 | {/*{pkg !== null ? : ""}*/} 42 |
43 | ); 44 | 45 | export default CheckBox; 46 | -------------------------------------------------------------------------------- /src/lib/Result.test.ts: -------------------------------------------------------------------------------- 1 | import Result from "./Result"; 2 | 3 | test("Result matches on ok or error", () => { 4 | type OkType = { textContent: string }; 5 | type ErrType = { errMsg: string }; 6 | const ok: OkType = { textContent: "I am ok" }; 7 | const err: ErrType = { errMsg: "I am not ok" }; 8 | const matcher = (result: Result): string => 9 | result.match( 10 | (ok_res) => ok_res.textContent, 11 | (err_res) => err_res.errMsg 12 | ); 13 | 14 | const err_content = matcher(Result.Err(err)); 15 | expect(err_content).toEqual(err.errMsg); 16 | const ok_content = matcher(Result.Ok(ok)); 17 | expect(ok_content).toEqual(ok.textContent); 18 | }); 19 | 20 | test("Result unwraps ok", () => { 21 | type OkType = { textContent: string }; 22 | type ErrType = { errMsg: string }; 23 | const ok: OkType = { textContent: "I am ok" }; 24 | 25 | expect(Result.Ok(ok).unwrap().textContent).toEqual( 26 | ok.textContent 27 | ); 28 | }); 29 | test("Error throws on unwrap", () => { 30 | type OkType = { textContent: string }; 31 | type ErrType = { name: string; message: string }; 32 | const err: ErrType = { name: "ErrType", message: "I am not ok" }; 33 | 34 | expect( 35 | () => Result.Err(err).unwrap().textContent 36 | ).toThrowError(err); 37 | }); 38 | -------------------------------------------------------------------------------- /src/Components/SelectMany.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import CheckBox from "./CheckBox"; 3 | import { SelectableElement } from "../lib/types"; 4 | 5 | type ToggleMany = Map; 6 | interface Props { 7 | id: string; 8 | type: string; 9 | label: JSX.Element; 10 | options: ToggleMany; 11 | toggleAll: (on: boolean) => void; 12 | toggleOne: (on: boolean, name: string) => void; 13 | } 14 | 15 | const SelectMany = (props: Props): JSX.Element => { 16 | const { label, id, options, toggleAll, toggleOne, type } = props; 17 | const hasAllOn = 18 | options.size > 0 && 19 | [...options.values()].every( 20 | (element: SelectableElement) => element.selected 21 | ); 22 | 23 | return ( 24 |
25 | {label} 26 | toggleAll(event.target.checked)} 33 | /> 34 |
35 | {[...options.entries()].map(([name, element], index) => ( 36 | toggleOne(event.target.checked, name)} 44 | /> 45 | ))} 46 |
47 | ); 48 | }; 49 | 50 | export default SelectMany; 51 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/list-qt.test.ts: -------------------------------------------------------------------------------- 1 | import fetchMock from "jest-fetch-mock"; 2 | import { Host, Target } from "../lib/types"; 3 | import { SemVer } from "semver"; 4 | import { fetch_arches, fetch_versions } from "./list-qt"; 5 | import expect_win_620 from "./test_data/windows-620-expect.json"; 6 | import expect_win_desktop from "./test_data/windows-desktop-expect.json"; 7 | import fsPromises from "fs"; 8 | 9 | const [win_desktop_dir_json] = ["windows-desktop-directory.json"].map( 10 | (filename: string) => 11 | fsPromises 12 | .readFileSync(`src/aqt-list-qt-ts/test_data/${filename}`) 13 | .toString() 14 | ); 15 | 16 | beforeEach(() => { 17 | fetchMock.resetMocks(); 18 | // fetch.resetMocks(); 19 | }); 20 | 21 | test.skip("fetch versions via HTTP", async () => { 22 | fetchMock.mockResponse(win_desktop_dir_json, { status: 200 }); 23 | 24 | const [host, target] = [Host.windows, Target.desktop]; 25 | const actual = await fetch_versions(host, target); 26 | const expected = expect_win_desktop.qt.qt.map((major_minor_row: string) => 27 | major_minor_row.split(" ") 28 | ); 29 | expect(actual).toEqual(expected); 30 | }); 31 | 32 | test.skip("fetch arches via HTTP", async () => { 33 | // fetchMock.mockResponseOnce() 34 | 35 | const [host, target] = [Host.windows, Target.desktop]; 36 | const version = new SemVer("6.2.0"); 37 | const actual = await fetch_arches(host, target, version); 38 | const expected = [...expect_win_620.architectures, "wasm_32"]; 39 | expect(actual).toEqual(expected); 40 | }); 41 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-59-expect.json: -------------------------------------------------------------------------------- 1 | { 2 | "architectures": [ 3 | "win32_mingw53", 4 | "win32_msvc2015", 5 | "win64_msvc2013_64", 6 | "win64_msvc2015_64", 7 | "win64_msvc2017_64" 8 | ], 9 | "modules_by_arch": { 10 | "win32_mingw53": [ 11 | "qtcharts", 12 | "qtdatavis3d", 13 | "qtnetworkauth", 14 | "qtpurchasing", 15 | "qtremoteobjects", 16 | "qtscript", 17 | "qtspeech", 18 | "qtvirtualkeyboard" 19 | ], 20 | "win32_msvc2015": [ 21 | "qtcharts", 22 | "qtdatavis3d", 23 | "qtnetworkauth", 24 | "qtpurchasing", 25 | "qtremoteobjects", 26 | "qtscript", 27 | "qtspeech", 28 | "qtvirtualkeyboard", 29 | "qtwebengine" 30 | ], 31 | "win64_msvc2013_64": [ 32 | "qtcharts", 33 | "qtdatavis3d", 34 | "qtnetworkauth", 35 | "qtpurchasing", 36 | "qtremoteobjects", 37 | "qtscript", 38 | "qtspeech", 39 | "qtvirtualkeyboard" 40 | ], 41 | "win64_msvc2015_64": [ 42 | "qtcharts", 43 | "qtdatavis3d", 44 | "qtnetworkauth", 45 | "qtpurchasing", 46 | "qtremoteobjects", 47 | "qtscript", 48 | "qtspeech", 49 | "qtvirtualkeyboard", 50 | "qtwebengine" 51 | ], 52 | "win64_msvc2017_64": [ 53 | "qtcharts", 54 | "qtdatavis3d", 55 | "qtnetworkauth", 56 | "qtpurchasing", 57 | "qtremoteobjects", 58 | "qtscript", 59 | "qtspeech", 60 | "qtvirtualkeyboard", 61 | "qtwebengine" 62 | ] 63 | } 64 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | ### Housekeeping 6 | * Update changelog (forgot to do this before release 0.1.2) 7 | 8 | ## v0.1.2 9 | 10 | ### Bug fixes 11 | * Show the new architectures `wasm_singlethread` and `wasm_multithread` for Qt 6.5.0, 12 | to bring the output in-line with what `aqtinstall` v3.1.2 can actually install (#15) 13 | * Dependency updates (thanks @dependabot!) (#22, #23, #24, #27, #28, #29, #30, #31, #32, #35, #39, #47) 14 | * Updates for functional/integration tests (#25, #49) 15 | * Fix display of: 16 | * Qt 6.8.0 17 | * Android versions of Qt >= 6.7.0 18 | * Module names for Qt >= 6.7.0 19 | 20 | ### Features 21 | * Add CLI commands for official Qt installers (#20) 22 | * Add Changelog (#16) 23 | * Add configurable settings for recommending a py7zr version (#19, #21) 24 | * Add CLI commands for official installers (#20, #41) 25 | * Show `sdktool` in list of supported tools 26 | * Add arm64 hosts for Windows and Linux 27 | 28 | ## v0.1.1 29 | 30 | ### Bug fixes 31 | * Fix bug where "Check all modules" breaks the modules list (#11) 32 | * Fix bug where "Check all archives" breaks the archives list (#12) 33 | 34 | ### Features 35 | * Show module details for all Qt modules and tools 36 | * Show archive sizes (#6) 37 | * Show action yml for install-qt-action versions 2 and 3 (#4) 38 | 39 | ### Housekeeping 40 | * Only deploy on main branch for repository owner (#2) 41 | * Upgrade dependencies (#1, #3, #6, #7, #9) 42 | * Recommend use of the newest version of `aqtinstall` (#13) 43 | 44 | 45 | ## v0.1.0 46 | 47 | Initial release 48 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build, Test, and (maybe) Deploy React Application 2 | 3 | on: 4 | # Triggers the workflow on push or pull request events but only for the main branch 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | workflow_dispatch: 10 | 11 | 12 | jobs: 13 | build_test: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [20.x] 19 | python-version: [3.9] 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | - name: Set up Python ${{ matrix.python-version }} 29 | uses: actions/setup-python@v5 30 | with: 31 | python-version: ${{ matrix.python-version }} 32 | - name: Install aqtinstall - requirement for functional tests 33 | run: pip install aqtinstall==3.1.* 34 | - name: yarn install, build and test 35 | run: | 36 | yarn install --immutable --immutable-cache --check-cache 37 | yarn run build --if-present 38 | yarn test --coverage 39 | - name: Upload coverage to Codecov 40 | uses: codecov/codecov-action@v4 41 | env: 42 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 43 | - name: deploy to gh-pages 44 | if: github.ref == 'refs/heads/main' && github.actor == github.repository_owner 45 | uses: peaceiris/actions-gh-pages@v3 46 | with: 47 | github_token: ${{ secrets.GITHUB_TOKEN }} 48 | publish_dir: ./build 49 | -------------------------------------------------------------------------------- /src/Components/QtSelectorPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ComboBox, { options, optionsQtVersions } from "./ComboBox"; 3 | import { SelectOne, Versions } from "../State"; 4 | 5 | type ChangeValue = (str: string) => Promise; 6 | 7 | interface Props { 8 | host: SelectOne; 9 | target: SelectOne; 10 | version: Versions; 11 | arch: SelectOne; 12 | changeHost: ChangeValue; 13 | changeTarget: ChangeValue; 14 | changeVersion: ChangeValue; 15 | changeArch: ChangeValue; 16 | } 17 | 18 | const QtSelectorPanel = (props: Props): JSX.Element => { 19 | return ( 20 |
21 | 29 | {options(props.host, "host")} 30 | 31 | 38 | {options(props.target, "target")} 39 | 40 | 47 | {optionsQtVersions(props.version, "version")} 48 | 49 | 56 | {options(props.arch, "arch")} 57 | 58 |
59 | ); 60 | }; 61 | 62 | export default QtSelectorPanel; 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aqt-list-app", 3 | "version": "0.1.2", 4 | "private": true, 5 | "description": "Web application to emulate aqt list-qt and list-tool in the browser, without a backend", 6 | "homepage": "https://ddalcino.github.io/aqt-list-server", 7 | "license": "MIT", 8 | "author": "David Dalcino ", 9 | "scripts": { 10 | "build": "react-scripts build", 11 | "eject": "react-scripts eject", 12 | "lint": "eslint --fix src/ --ext .js,.jsx,.ts,.tsx", 13 | "start": "react-scripts start", 14 | "test": "react-scripts test", 15 | "test:nowatch": "react-scripts test --watchAll=false" 16 | }, 17 | "browserslist": { 18 | "production": [ 19 | ">0.2%", 20 | "not dead", 21 | "not op_mini all" 22 | ], 23 | "development": [ 24 | "last 1 chrome version", 25 | "last 1 firefox version", 26 | "last 1 safari version" 27 | ] 28 | }, 29 | "eslintConfig": { 30 | "extends": [ 31 | "react-app", 32 | "react-app/jest" 33 | ] 34 | }, 35 | "dependencies": { 36 | "@types/node": "^16.10.4", 37 | "@types/react": "^17.0.29", 38 | "@types/react-dom": "^17.0.0", 39 | "cheerio": "^1.0.0-rc.10", 40 | "lodash": "^4.17.21", 41 | "react": "^17.0.2", 42 | "react-dom": "^17.0.2", 43 | "react-redux": "^7.2.5", 44 | "react-scripts": "^5.0.1", 45 | "semver": "^7.5.2", 46 | "web-vitals": "^2.1.1" 47 | }, 48 | "devDependencies": { 49 | "@testing-library/dom": "^8.7.2", 50 | "@testing-library/jest-dom": "^5.11.4", 51 | "@testing-library/react": "^12.1.2", 52 | "@testing-library/user-event": "^13.2.1", 53 | "@types/jest": "^27.0.2", 54 | "@types/lodash": "^4.14.175", 55 | "@types/semver": "^7.3.9", 56 | "@typescript-eslint/eslint-plugin": "^5.0.0", 57 | "@typescript-eslint/parser": "^5.0.0", 58 | "eslint-plugin-prettier": "^4.0.0", 59 | "jest-fetch-mock": "^3.0.3", 60 | "prettier": "^2.4.1", 61 | "sass": "^1.43.2", 62 | "sass-loader": "^12.2.0", 63 | "typescript": "^4.4.4" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { Host, Target } from "./types"; 2 | 3 | export const hosts: Readonly = [ 4 | Host.windows, 5 | Host.windows_arm64, 6 | Host.mac, 7 | Host.linux, 8 | Host.linux_arm64, 9 | ]; 10 | export const targetsForHost = (host: Host): Target[] => { 11 | switch (host) { 12 | case Host.linux: 13 | return [Target.desktop, Target.android]; 14 | case Host.linux_arm64: 15 | return [Target.desktop]; 16 | case Host.mac: 17 | return [Target.desktop, Target.android, Target.ios]; 18 | case Host.windows: 19 | return [Target.desktop, Target.android, Target.winrt]; 20 | case Host.windows_arm64: 21 | return [Target.desktop]; 22 | case Host.all_os: 23 | return []; 24 | } 25 | }; 26 | 27 | const hostOs = (): Host => { 28 | const app_ver = navigator.appVersion; 29 | if (app_ver.indexOf("Win") !== -1) return Host.windows; 30 | if (app_ver.indexOf("Mac") !== -1) return Host.mac; 31 | return Host.linux; 32 | }; 33 | 34 | export const get_host_target_targets = ( 35 | host?: Host, 36 | target?: Target 37 | ): [Host, Target, Target[]] => { 38 | const host_os: Host = 39 | host !== null && host !== undefined && hosts.includes(host) 40 | ? host 41 | : hostOs(); 42 | const targets = targetsForHost(host_os); 43 | const target_sdk = 44 | target && targets.includes(target) ? target : Target.desktop; 45 | return [host_os, target_sdk, targets]; 46 | }; 47 | 48 | export const copyText = async (el: HTMLElement): Promise => { 49 | await navigator.clipboard.writeText(el.textContent as string); 50 | }; 51 | 52 | export const toHumanReadableSize = (bytes: string): string => { 53 | const numBytes = parseInt(bytes); 54 | if (numBytes === 0) return "0"; 55 | const units = ["B", "KB", "MB", "GB", "TB", "PB"]; 56 | let [amt, dividedAmt, index] = [numBytes, numBytes / 1024.0, 0]; 57 | while (Math.floor(dividedAmt) > 0 && index < units.length - 1) { 58 | [amt, dividedAmt, index] = [dividedAmt, dividedAmt / 1024.0, index + 1]; 59 | } 60 | return `${amt.toPrecision(4)} ${units[index]}`; 61 | }; 62 | -------------------------------------------------------------------------------- /src/Components/ToolSelectPanel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { NO_SELECTION, SelectNone, ToolData } from "../State"; 3 | import ComboBox, { options } from "./ComboBox"; 4 | import SelectMany from "./SelectMany"; 5 | 6 | interface Props { 7 | toolNames: SelectNone; 8 | selectedTools: Map; 9 | addTool: (toolName: string) => Promise; 10 | removeTool: (toolName: string) => void; 11 | setToolVariant: (toolName: string, toolVariant: string, on: boolean) => void; 12 | toggleToolVariants: (toolName: string, on: boolean) => void; 13 | } 14 | 15 | const ToolSelectPanel = (props: Props): JSX.Element => ( 16 |
17 | props.addTool(toolName)} 23 | > 24 | {options(props.toolNames, "tool-adder")} 25 | 26 | {[...props.selectedTools.values()].map( 27 | (toolData: ToolData, index: number) => ( 28 |
29 | props.removeTool(toolData.name)} 36 | /> 37 | {toolData.name}} 42 | options={toolData.variants} 43 | toggleAll={(on: boolean) => 44 | props.toggleToolVariants(toolData.name, on) 45 | } 46 | toggleOne={(on: boolean, name: string) => 47 | props.setToolVariant(toolData.name, name, on) 48 | } 49 | /> 50 |
51 | ) 52 | )} 53 |
54 | ); 55 | 56 | export default ToolSelectPanel; 57 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-620-expect.json: -------------------------------------------------------------------------------- 1 | { 2 | "architectures": [ 3 | "win64_mingw81", 4 | "win64_msvc2019_64", 5 | "win64_msvc2019_arm64" 6 | ], 7 | "modules_by_arch": { 8 | "win64_mingw81": [ 9 | "qt3d", 10 | "qtactiveqt", 11 | "qtcharts", 12 | "qtconnectivity", 13 | "qtdatavis3d", 14 | "qtimageformats", 15 | "qtlottie", 16 | "qtmultimedia", 17 | "qtnetworkauth", 18 | "qtpositioning", 19 | "qtremoteobjects", 20 | "qtscxml", 21 | "qtsensors", 22 | "qtserialbus", 23 | "qtserialport", 24 | "qtvirtualkeyboard", 25 | "qtwebchannel", 26 | "qtwebsockets", 27 | "qtwebview", 28 | "debug_info", 29 | "qt5compat", 30 | "qtquick3d", 31 | "qtquicktimeline", 32 | "qtshadertools" 33 | ], 34 | "win64_msvc2019_64": [ 35 | "qt3d", 36 | "qtactiveqt", 37 | "qtcharts", 38 | "qtconnectivity", 39 | "qtdatavis3d", 40 | "qtimageformats", 41 | "qtlottie", 42 | "qtmultimedia", 43 | "qtnetworkauth", 44 | "qtpositioning", 45 | "qtremoteobjects", 46 | "qtscxml", 47 | "qtsensors", 48 | "qtserialbus", 49 | "qtserialport", 50 | "qtvirtualkeyboard", 51 | "qtwebchannel", 52 | "qtwebengine", 53 | "qtwebsockets", 54 | "qtwebview", 55 | "debug_info", 56 | "qt5compat", 57 | "qtquick3d", 58 | "qtquicktimeline", 59 | "qtshadertools" 60 | ], 61 | "win64_msvc2019_arm64": [ 62 | "qt3d", 63 | "qtactiveqt", 64 | "qtcharts", 65 | "qtconnectivity", 66 | "qtdatavis3d", 67 | "qtimageformats", 68 | "qtlottie", 69 | "qtmultimedia", 70 | "qtnetworkauth", 71 | "qtpositioning", 72 | "qtremoteobjects", 73 | "qtscxml", 74 | "qtsensors", 75 | "qtserialbus", 76 | "qtserialport", 77 | "qtvirtualkeyboard", 78 | "qtwebchannel", 79 | "qtwebsockets", 80 | "debug_info", 81 | "qt5compat", 82 | "qtquick3d", 83 | "qtquicktimeline", 84 | "qtshadertools" 85 | ] 86 | } 87 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | aqt list-qt server 28 | 29 | 30 | 31 | 32 | Fork me on GitHub 35 | 36 |
37 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-desktop-expect.json: -------------------------------------------------------------------------------- 1 | { 2 | "qt": { 3 | "qt": [ 4 | "5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9", 5 | "5.10.0 5.10.1", 6 | "5.11.0 5.11.1 5.11.2 5.11.3", 7 | "5.12.0 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.12.10 5.12.11 5.12.12", 8 | "5.13.0 5.13.1 5.13.2", 9 | "5.14.0 5.14.1 5.14.2", 10 | "5.15.0 5.15.1 5.15.2", 11 | "6.0.0 6.0.1 6.0.2 6.0.3 6.0.4", 12 | "6.1.0 6.1.1 6.1.2 6.1.3", 13 | "6.2.0 6.2.1 6.2.2 6.2.3 6.2.4", 14 | "6.3.0" 15 | ], 16 | "preview": [ 17 | "5.6-preview", 18 | "5.9-preview", 19 | "5.10-preview", 20 | "5.11-preview", 21 | "5.12-preview", 22 | "5.13-preview", 23 | "5.14-preview", 24 | "5.15-preview", 25 | "6.0-preview", 26 | "6.1-preview" 27 | ], 28 | "wasm": [ 29 | "5.13.1 5.13.2", 30 | "5.14.0 5.14.1 5.14.2", 31 | "5.15.0 5.15.1 5.15.2" 32 | ], 33 | "wasm_preview": [ 34 | "5.13-preview", 35 | "5.14-preview", 36 | "5.15-preview" 37 | ], 38 | "src_doc_examples": [ 39 | "5.3.0", 40 | "5.4.0", 41 | "5.5.0", 42 | "5.6.0", 43 | "5.7.0", 44 | "5.8.0", 45 | "5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9", 46 | "5.10.0 5.10.1", 47 | "5.11.0 5.11.1 5.11.2 5.11.3", 48 | "5.12.0 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.12.10", 49 | "5.13.0 5.13.1 5.13.2", 50 | "5.14.0 5.14.1 5.14.2", 51 | "5.15.0 5.15.1 5.15.2", 52 | "6.0.0 6.0.1 6.0.2 6.0.3", 53 | "6.1.0" 54 | ] 55 | }, 56 | "tools": [ 57 | "tools_vcredist", 58 | "tools_telemetry_preview", 59 | "tools_telemetry", 60 | "tools_qtdesignstudio_preview", 61 | "tools_qtdesignstudio", 62 | "tools_qtcreator_preview", 63 | "tools_qtcreator", 64 | "tools_qt3dstudio_runtime_preview", 65 | "tools_qt3dstudio_runtime_240", 66 | "tools_qt3dstudio_runtime_230", 67 | "tools_qt3dstudio_runtime_220", 68 | "tools_qt3dstudio_runtime_210", 69 | "tools_qt3dstudio_runtime", 70 | "tools_qt3dstudio_preview", 71 | "tools_qt3dstudio_openglruntime_preview", 72 | "tools_qt3dstudio_openglruntime_280_5151", 73 | "tools_qt3dstudio_openglruntime_280", 74 | "tools_qt3dstudio_openglruntime_270_5150", 75 | "tools_qt3dstudio_openglruntime_270", 76 | "tools_qt3dstudio_openglruntime_260", 77 | "tools_qt3dstudio_openglruntime_250", 78 | "tools_qt3dstudio_openglruntime_240", 79 | "tools_qt3dstudio", 80 | "tools_openssl_x86", 81 | "tools_openssl_x64", 82 | "tools_openssl_src", 83 | "tools_ninja", 84 | "tools_mingw", 85 | "tools_mingw90", 86 | "tools_maintenance_early_access", 87 | "tools_maintenance", 88 | "tools_ifw", 89 | "tools_generic", 90 | "tools_conan", 91 | "tools_cmake" 92 | ] 93 | } -------------------------------------------------------------------------------- /src/Components/ComboBox.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { NO_SELECTION, SelectOne, SelectState, Versions } from "../State"; 3 | 4 | interface Props { 5 | id: string; 6 | isAutofocus?: boolean; 7 | label: string; 8 | selectState: SelectState; 9 | value: string; 10 | children: JSX.Element[]; 11 | onchange: (newValue: string) => void; 12 | } 13 | 14 | interface OptionProps { 15 | value: string; 16 | displayName?: string; 17 | } 18 | const Option = (props: OptionProps): JSX.Element => { 19 | return ( 20 | 21 | ); 22 | }; 23 | 24 | const emptyOption = (key_id: string): JSX.Element => ( 25 | 70 | {minor_group.map((version, index) => ( 71 | 77 | ); 78 | }) 79 | ); 80 | }; 81 | 82 | const ComboBox = (props: Props): JSX.Element => { 83 | const { selectState, id, label, value } = props; 84 | return ( 85 |
86 | 87 | 98 |
99 | ); 100 | }; 101 | export default ComboBox; 102 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-desktop-directory.json: -------------------------------------------------------------------------------- 1 | {"tools": ["tools_cmake", "tools_conan", "tools_generic", "tools_ifw", "tools_maintenance", "tools_maintenance_early_access", "tools_mingw", "tools_mingw90", "tools_ninja", "tools_openssl_src", "tools_openssl_x64", "tools_openssl_x86", "tools_qt3dstudio", "tools_qt3dstudio_openglruntime_240", "tools_qt3dstudio_openglruntime_250", "tools_qt3dstudio_openglruntime_260", "tools_qt3dstudio_openglruntime_270", "tools_qt3dstudio_openglruntime_270_5150", "tools_qt3dstudio_openglruntime_280", "tools_qt3dstudio_openglruntime_280_5151", "tools_qt3dstudio_openglruntime_preview", "tools_qt3dstudio_preview", "tools_qt3dstudio_runtime", "tools_qt3dstudio_runtime_210", "tools_qt3dstudio_runtime_220", "tools_qt3dstudio_runtime_230", "tools_qt3dstudio_runtime_240", "tools_qt3dstudio_runtime_preview", "tools_qtcreator", "tools_qtcreator_preview", "tools_qtdesignstudio", "tools_qtdesignstudio_preview", "tools_telemetry", "tools_telemetry_preview", "tools_vcredist"], "qt": ["qt5_5100", "qt5_5100_src_doc_examples", "qt5_5101", "qt5_5101_src_doc_examples", "qt5_5110", "qt5_5110_src_doc_examples", "qt5_5111", "qt5_5111_src_doc_examples", "qt5_5112", "qt5_5112_src_doc_examples", "qt5_5113", "qt5_5113_src_doc_examples", "qt5_5120", "qt5_5120_src_doc_examples", "qt5_5121", "qt5_51210", "qt5_51210_src_doc_examples", "qt5_51211", "qt5_51211_src_doc_examples", "qt5_51212", "qt5_51212_src_doc_examples", "qt5_5121_src_doc_examples", "qt5_5122", "qt5_5122_src_doc_examples", "qt5_5123", "qt5_5123_src_doc_examples", "qt5_5124", "qt5_5124_src_doc_examples", "qt5_5125", "qt5_5125_src_doc_examples", "qt5_5126", "qt5_5126_src_doc_examples", "qt5_5127", "qt5_5127_src_doc_examples", "qt5_5128", "qt5_5128_src_doc_examples", "qt5_5129", "qt5_5129_src_doc_examples", "qt5_5130", "qt5_5130_src_doc_examples", "qt5_5131", "qt5_5131_src_doc_examples", "qt5_5131_wasm", "qt5_5132", "qt5_5132_src_doc_examples", "qt5_5132_wasm", "qt5_5140", "qt5_5140_src_doc_examples", "qt5_5140_wasm", "qt5_5141", "qt5_5141_src_doc_examples", "qt5_5141_wasm", "qt5_5142", "qt5_5142_src_doc_examples", "qt5_5142_wasm", "qt5_5150", "qt5_5150_src_doc_examples", "qt5_5150_wasm", "qt5_5151", "qt5_5151_src_doc_examples", "qt5_5151_wasm", "qt5_5152", "qt5_5152_src_doc_examples", "qt5_5152_wasm", "qt5_53_src_doc_examples", "qt5_54_src_doc_examples", "qt5_55_src_doc_examples", "qt5_56_src_doc_examples", "qt5_57_src_doc_examples", "qt5_58_src_doc_examples", "qt5_59", "qt5_591", "qt5_591_src_doc_examples", "qt5_592", "qt5_592_src_doc_examples", "qt5_593", "qt5_593_src_doc_examples", "qt5_594", "qt5_594_src_doc_examples", "qt5_595", "qt5_595_src_doc_examples", "qt5_596", "qt5_596_src_doc_examples", "qt5_597", "qt5_597_src_doc_examples", "qt5_598", "qt5_598_src_doc_examples", "qt5_599", "qt5_599_src_doc_examples", "qt5_59_src_doc_examples", "qt6_600", "qt6_600_src_doc_examples", "qt6_601", "qt6_601_src_doc_examples", "qt6_602", "qt6_602_src_doc_examples", "qt6_603", "qt6_603_src_doc_examples", "qt6_604", "qt6_604_src_doc_examples", "qt6_610", "qt6_610_src_doc_examples", "qt6_611", "qt6_611_src_doc_examples", "qt6_612", "qt6_612_src_doc_examples", "qt6_613", "qt6_613_src_doc_examples", "qt6_620", "qt6_620_src_doc_examples", "qt6_620_wasm", "qt6_621", "qt6_621_src_doc_examples", "qt6_621_wasm", "qt6_622", "qt6_622_src_doc_examples", "qt6_622_wasm", "qt6_623", "qt6_623_src_doc_examples", "qt6_623_wasm", "qt6_624", "qt6_624_src_doc_examples", "qt6_624_wasm", "qt6_630", "qt6_630_src_doc_examples", "qt6_630_wasm"]} -------------------------------------------------------------------------------- /src/lib/Actions.ts: -------------------------------------------------------------------------------- 1 | import { State, ToolData, StateUtils as S } from "../State"; 2 | import { Host, PackageUpdate, Target, UnifiedInstallers } from "./types"; 3 | 4 | export const enum ActionT { 5 | chooseHost, 6 | chooseTarget, 7 | loadedVersionsTools, 8 | chooseVersion, 9 | loadedArchitectures, 10 | chooseArchitecture, 11 | loadedModulesArchives, 12 | chooseModule, 13 | chooseArchive, 14 | chooseTool, 15 | loadedToolVariants, 16 | chooseToolVariant, 17 | } 18 | 19 | export interface Action { 20 | type: ActionT; 21 | reduce: (state: State) => State; 22 | } 23 | 24 | export const setHost = (host: Host): Action => ({ 25 | type: ActionT.chooseHost, 26 | reduce: S.withHostLoadingVersionsTools(host), 27 | }); 28 | 29 | export const setTarget = (target: Target): Action => ({ 30 | type: ActionT.chooseTarget, 31 | reduce: S.withTargetLoadingVersionsTools(target), 32 | }); 33 | 34 | export const loadedVersionsTools = ( 35 | installers: UnifiedInstallers, 36 | versions: string[][], 37 | tools: string[] 38 | ): Action => ({ 39 | type: ActionT.loadedVersionsTools, 40 | reduce: S.withInstallersVersionsToolsLoaded(installers, versions, tools), 41 | }); 42 | 43 | export const setVersion = (version: string): Action => ({ 44 | type: ActionT.chooseVersion, 45 | reduce: S.withVersionLoadingArches(version), 46 | }); 47 | 48 | export const loadedArchitectures = (arches: string[]): Action => ({ 49 | type: ActionT.loadedArchitectures, 50 | reduce: S.withArchesLoaded(arches), 51 | }); 52 | 53 | export const setArchitecture = (arch: string): Action => ({ 54 | type: ActionT.chooseArchitecture, 55 | reduce: S.withArchLoadingModulesArchives(arch), 56 | }); 57 | 58 | export const loadedModulesArchives = ( 59 | modules: PackageUpdate[], 60 | archives: Map 61 | ): Action => ({ 62 | type: ActionT.loadedModulesArchives, 63 | reduce: S.withModulesArchivesLoaded(modules, archives), 64 | }); 65 | 66 | export const setModule = (module: string, isAdd: boolean): Action => ({ 67 | type: ActionT.chooseModule, 68 | reduce: S.withModuleSet(module, isAdd), 69 | }); 70 | 71 | export const setAllModules = (): Action => ({ 72 | type: ActionT.chooseModule, 73 | reduce: S.withToggledModules(true), 74 | }); 75 | 76 | export const clearModules = (): Action => ({ 77 | type: ActionT.chooseModule, 78 | reduce: S.withToggledModules(false), 79 | }); 80 | 81 | export const setArchive = (archive: string, isAdd: boolean): Action => ({ 82 | type: ActionT.chooseArchive, 83 | reduce: S.withArchiveSet(archive, isAdd), 84 | }); 85 | 86 | export const setAllArchives = (): Action => ({ 87 | type: ActionT.chooseArchive, 88 | reduce: S.withToggledArchives(true), 89 | }); 90 | 91 | export const addTool = (toolName: string): Action => ({ 92 | type: ActionT.chooseTool, 93 | reduce: S.withNewTool(new ToolData(toolName, true, new Map())), 94 | }); 95 | 96 | export const loadedToolVariants = (variants: ToolData): Action => ({ 97 | type: ActionT.loadedToolVariants, 98 | reduce: S.withNewTool(variants), 99 | }); 100 | 101 | export const removeTool = (toolName: string): Action => ({ 102 | type: ActionT.chooseTool, 103 | reduce: S.withoutTool(toolName), 104 | }); 105 | 106 | export const addToolVariant = ( 107 | toolName: string, 108 | toolVariant: string 109 | ): Action => ({ 110 | type: ActionT.chooseToolVariant, 111 | reduce: S.withToolVariant(toolName, toolVariant, true), 112 | }); 113 | 114 | export const removeToolVariant = ( 115 | toolName: string, 116 | toolVariant: string 117 | ): Action => ({ 118 | type: ActionT.chooseToolVariant, 119 | reduce: S.withToolVariant(toolName, toolVariant, false), 120 | }); 121 | 122 | export const addAllToolVariants = (toolName: string): Action => ({ 123 | type: ActionT.chooseToolVariant, 124 | reduce: S.withToggledToolVariants(toolName, true), 125 | }); 126 | 127 | export const clearAllToolVariants = (toolName: string): Action => ({ 128 | type: ActionT.chooseToolVariant, 129 | reduce: S.withToggledToolVariants(toolName, false), 130 | }); 131 | -------------------------------------------------------------------------------- /src/lib/types.ts: -------------------------------------------------------------------------------- 1 | export interface PackageUpdate { 2 | DisplayName: string; 3 | Name: string; 4 | Description: string; 5 | ReleaseDate: string; 6 | Version: string; 7 | CompressedSize: string; 8 | UncompressedSize: string; 9 | DownloadableArchives: string[]; 10 | Dependencies: string[]; 11 | AutoDependOn: string[]; 12 | ArchiveSizes: Map; 13 | } 14 | 15 | export interface SelectableElement { 16 | pkg: PackageUpdate | null; 17 | size: string | null; 18 | name: string; 19 | selected: boolean; 20 | } 21 | 22 | export const seToolInstallName = (se: SelectableElement): string | null => 23 | se.pkg === null ? null : se.pkg.Name; 24 | 25 | const installableModuleRegex = /^qt\.qt\d\.\d+(\.addons)?\.(.+)\.[^.]+$/; 26 | export const packageNameToModuleName = (name: string): string => 27 | name.replace(installableModuleRegex, "$2"); 28 | 29 | export const seModuleInstallName = (se: SelectableElement): string | null => { 30 | if (se.pkg === null) { 31 | return null; 32 | } 33 | return packageNameToModuleName(se.pkg.Name); 34 | }; 35 | 36 | export interface RawPackageUpdate { 37 | DisplayName?: string | null | undefined; 38 | Name?: string | null | undefined; 39 | Description?: string | null | undefined; 40 | ReleaseDate?: string | null | undefined; 41 | Version?: string | null | undefined; 42 | CompressedSize?: string | null | undefined; 43 | UncompressedSize?: string | null | undefined; 44 | DownloadableArchives?: string | string[] | null | undefined; 45 | Dependencies?: string[] | null | undefined; 46 | AutoDependOn?: string[] | null | undefined; 47 | ArchiveSizes?: Record; // { [key: string]: string } | null | undefined; 48 | } 49 | 50 | export interface RawPackageUpdates { 51 | [key: string]: RawPackageUpdate; 52 | } 53 | export const to_package_updates = ( 54 | updates: RawPackageUpdates 55 | ): PackageUpdate[] => Object.values(updates).map(toPackageUpdate); 56 | 57 | const toStringArray = (o: string | string[] | null | undefined): string[] => { 58 | if (typeof o === "string" || o instanceof String) { 59 | return o.split(",").map((s: string) => s.trim()); 60 | } else if (Array.isArray(o)) { 61 | return o; 62 | } else { 63 | return []; 64 | } 65 | }; 66 | const toArchiveSizes = (obj: RawPackageUpdate): Map => { 67 | const trimExcess = (archive: string) => archive.split("-")[0]; 68 | if (obj.ArchiveSizes !== null && obj.ArchiveSizes !== undefined) { 69 | return new Map( 70 | Object.entries(obj.ArchiveSizes).map(([k, v]: [string, string]) => [ 71 | trimExcess(k), 72 | v, 73 | ]) 74 | ); 75 | } 76 | // Otherwise, there's probably only one archive whose size is obj.CompressedSize: 77 | const firstArchive = Array.isArray(obj.DownloadableArchives) 78 | ? obj.DownloadableArchives[0] 79 | : obj.DownloadableArchives; 80 | if ( 81 | typeof firstArchive === "string" && 82 | typeof obj.CompressedSize === "string" 83 | ) { 84 | return new Map([ 85 | [trimExcess(firstArchive), obj.CompressedSize], 86 | ]); 87 | } 88 | return new Map(); 89 | }; 90 | 91 | export const toPackageUpdate = (obj: RawPackageUpdate): PackageUpdate => ({ 92 | DisplayName: obj.DisplayName ?? "", 93 | Name: obj.Name ?? "", 94 | Description: obj.Description ?? "", 95 | ReleaseDate: obj.ReleaseDate ?? "", 96 | Version: obj.Version ?? "", 97 | CompressedSize: obj.CompressedSize ?? "", 98 | UncompressedSize: obj.UncompressedSize ?? "", 99 | DownloadableArchives: toStringArray(obj.DownloadableArchives), 100 | Dependencies: obj.Dependencies ?? [], 101 | AutoDependOn: obj.AutoDependOn ?? [], 102 | ArchiveSizes: toArchiveSizes(obj), 103 | }); 104 | 105 | export type Directory = { qt: string[]; tools: string[] }; 106 | 107 | export enum Host { 108 | windows, 109 | windows_arm64, 110 | mac, 111 | linux, 112 | linux_arm64, 113 | all_os, 114 | } 115 | export type HostString = keyof typeof Host; 116 | export const hostToStr = (h: Host): string => Host[h]; 117 | export const hostFromStr = (h: keyof typeof Host): Host => Host[h]; 118 | 119 | export enum Target { 120 | desktop, 121 | android, 122 | ios, 123 | winrt, 124 | } 125 | export type TargetString = keyof typeof Target; 126 | export const targetToStr = (t: Target): string => Target[t]; 127 | export const targetFromStr = (t: keyof typeof Target): Target => Target[t]; 128 | 129 | export type OnlineInstallers = { "online_installers/": object }; 130 | export type UnifiedInstallers = (host: Host) => string; 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aqt list server 2 | 3 | [![codecov](https://codecov.io/gh/ddalcino/aqt-list-server/branch/main/graph/badge.svg?token=8SVNX4YCGE)]( 4 | https://codecov.io/gh/ddalcino/aqt-list-server 5 | ) 6 | 7 | This project is meant to provide a web-based GUI interface to help users find 8 | out what options are available for [aqtinstall](https://github.com/miurahr/aqtinstall) 9 | and [install-qt-action](https://github.com/jurplel/install-qt-action). 10 | `aqtinstall` provides CLI-only tools called `aqt list-qt` and `aqt list-tool`, 11 | but these tools must be installed locally in order to be used. 12 | This project assumes that many users of `aqtinstall` and `install-qt-action` 13 | have no interest in installing the `aqtinstall` locally, because they intend 14 | to use it as part of a CI/CD workflow. 15 | Those users will be able to use this project instead of those CLI-based tools. 16 | 17 | This project is meant as a convenience for users of `aqtinstall` and `install-qt-action`. 18 | Please refer to [the `aqtinstall` documentation](https://aqtinstall.readthedocs.io/en/latest/) 19 | for definitive information on how `aqtinstall` should be used. 20 | 21 | ## Technical design 22 | This project includes a Typescript re-implementation of `aqt list-qt` and 23 | `aqt list-tool`, at `src/aqt-list-qt-ts`. 24 | Instead of accessing data directly from download.qt.io, it reads cached .json 25 | files at https://github.com/ddalcino/qt-repo-cache that are updated daily. 26 | This cache is meant to make access fast and available from any website, without 27 | the need for any backend server. 28 | The CORS policy at download.qt.io prevents any browser-based implementation 29 | of `aqt list-qt` from reading HTML and XML files directly from download.qt.io, 30 | which means that 31 | It is possible that this data is stale or incorrect; if you discover any 32 | inaccuracies, you are strongly encouraged to [file an issue](https://github.com/ddalcino/aqt-list-server/issues)! 33 | 34 | This project includes a frontend written in React, boostrapped with 35 | [Create React App](https://github.com/facebook/create-react-app), that consumes 36 | the above-described re-implementation of `aqt list-qt`. 37 | 38 | # Setup: 39 | 40 | First, make sure you have [python](https://www.python.org), [nodejs](https://nodejs.org/) and 41 | [yarn](https://yarnpkg.com/) installed. 42 | 43 | Install this project's dependencies with: 44 | ```bash 45 | pip install aqtinstall 46 | yarn install 47 | ``` 48 | 49 | Note that Python and aqtinstall are only required for running the functional tests. 50 | 51 | ## Available Scripts 52 | 53 | In the project directory, you can run: 54 | 55 | ### `yarn lint` 56 | Runs code auto-formatting and linting tasks. 57 | Strongly recommended: set up your editor to run this when you save your code. 58 | This project will fail to transpile if the code is not properly formatted. 59 | 60 | ### `yarn start` 61 | 62 | Runs the app in the development mode.\ 63 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 64 | 65 | The page will reload if you make edits.\ 66 | You will also see any lint errors in the console. 67 | 68 | ### `yarn test` 69 | 70 | Launches the test runner in the interactive watch mode.\ 71 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 72 | 73 | ### `yarn build` 74 | 75 | Builds the app for production to the `build` folder.\ 76 | It correctly bundles React in production mode and optimizes the build for the best performance. 77 | 78 | The build is minified and the filenames include the hashes.\ 79 | Your app is ready to be deployed! 80 | 81 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 82 | 83 | ### `yarn eject` 84 | 85 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 86 | 87 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 88 | 89 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 90 | 91 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 92 | 93 | ## Learn More 94 | 95 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 96 | 97 | To learn React, check out the [React documentation](https://reactjs.org/). 98 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/list-qt.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directory, 3 | Host, 4 | OnlineInstallers, 5 | PackageUpdate, 6 | RawPackageUpdates, 7 | Target, 8 | UnifiedInstallers, 9 | } from "../lib/types"; 10 | import { SemVer } from "semver"; 11 | import { 12 | official_releases_url, 13 | to_arches, 14 | to_archives, 15 | to_directory, 16 | to_modules, 17 | to_tool_variants, 18 | to_tools, 19 | to_tools_updates_json, 20 | to_unified_installers, 21 | to_updates_urls, 22 | to_updates_urls_by_arch, 23 | to_versions, 24 | } from "./list-qt-impl"; 25 | import Result from "../lib/Result"; 26 | 27 | class FetchError extends Error {} 28 | type FetchResult = Result; 29 | 30 | /** 31 | * Fetch a json object at `url`, 32 | * push it through the `json_transform` function with the arguments (json_object, json_args), 33 | * and catch any errors (fetch or json marshalling). 34 | * @param url 35 | * @param json_transform Function that turns json obj into usable data 36 | */ 37 | const generic_fetch_data = ( 38 | url: string, 39 | json_transform: (obj: V, args: U) => T 40 | ): ((json_args: U) => Promise>) => { 41 | return async (json_args: U) => { 42 | // console.log(`fetch ${url}`); 43 | return fetch(url, { cache: "force-cache" }) 44 | .then((response: Response) => response.json()) 45 | .then((obj: V) => 46 | Result.Ok(json_transform(obj, json_args)) 47 | ) 48 | .catch((err) => { 49 | return Result.Err(new FetchError(err)); 50 | }); 51 | }; 52 | }; 53 | 54 | export const fetch_versions = async ( 55 | host: Host, 56 | target: Target 57 | ): Promise => { 58 | const versions = await generic_fetch_data( 59 | to_directory([host, target]), 60 | to_versions 61 | )().then((result) => result.unwrap()); 62 | if (target !== Target.android) { 63 | return versions; 64 | } 65 | // If we have android target, we need to fetch from the all_os directory as well. 66 | const all_os_versions = await generic_fetch_data( 67 | to_directory([Host.all_os, target]), 68 | to_versions 69 | )().then((result) => result.unwrap()); 70 | 71 | // Return versions (less than 6.7.0) and all_os_versions (greater or equal to 6.7.0) 72 | const has_versions_gte_670 = (versions: string[]): boolean => { 73 | if (versions.length === 0) return false; 74 | return new SemVer(versions[0]).compare("6.7.0") >= 0; 75 | }; 76 | 77 | return [ 78 | ...versions.filter((row: string[]) => !has_versions_gte_670(row)), 79 | ...all_os_versions.filter((row: string[]) => has_versions_gte_670(row)), 80 | ]; 81 | }; 82 | 83 | export const fetch_arches = async ( 84 | host: Host, 85 | target: Target, 86 | version: SemVer 87 | ): Promise => { 88 | const all_arches = await Promise.all( 89 | to_updates_urls(host, target, version).map((url) => 90 | generic_fetch_data( 91 | url, 92 | to_arches 93 | )([version]).then((result) => 94 | result.match( 95 | (arches: string[]): string[] => arches, 96 | (_err: FetchError): string[] => [] 97 | ) 98 | ) 99 | ) 100 | ); 101 | return all_arches.flat(); 102 | }; 103 | 104 | export const fetch_modules = ( 105 | host: Host, 106 | target: Target, 107 | version: SemVer, 108 | arch: string 109 | ): Promise => 110 | generic_fetch_data( 111 | to_updates_urls_by_arch(arch)([host, target, version]), 112 | to_modules 113 | )([version, arch]).then((result) => result.unwrap()); 114 | 115 | export const fetch_archive_info = async ( 116 | host: Host, 117 | target: Target, 118 | version: SemVer, 119 | arch: string, 120 | modules: string[] 121 | ): Promise> => 122 | generic_fetch_data< 123 | Map, 124 | [SemVer, string, string[]], 125 | RawPackageUpdates 126 | >( 127 | to_updates_urls_by_arch(arch)([host, target, version]), 128 | to_archives 129 | )([version, arch, modules]).then((result) => result.unwrap()); 130 | export const fetch_archives = async ( 131 | host: Host, 132 | target: Target, 133 | version: SemVer, 134 | arch: string, 135 | modules: string[] 136 | ): Promise => { 137 | const archiveInfo = await fetch_archive_info( 138 | host, 139 | target, 140 | version, 141 | arch, 142 | modules 143 | ); 144 | return [...archiveInfo.keys()].sort(); 145 | }; 146 | 147 | export const fetch_tools = (host: Host, target: Target): Promise => 148 | generic_fetch_data( 149 | to_directory([host, target]), 150 | to_tools 151 | )().then((result) => result.unwrap()); 152 | 153 | export const fetch_tool_variants = ( 154 | host: Host, 155 | target: Target, 156 | tool_name: string 157 | ): Promise => 158 | generic_fetch_data( 159 | to_tools_updates_json([host, target, tool_name]), 160 | to_tool_variants 161 | )().then((result) => result.unwrap()); 162 | 163 | export const fetch_online_installers = (): Promise => 164 | generic_fetch_data( 165 | official_releases_url, 166 | to_unified_installers 167 | )().then((result) => result.unwrap()); 168 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-desktop-tools_vcredist-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "qt.tools.vcredist": { 3 | "Name": "qt.tools.vcredist", 4 | "DisplayName": "VCRedist for MSVC 32bit", 5 | "Description": "Needed by all included Qt applications.", 6 | "Version": "2022-06-07", 7 | "ReleaseDate": "2022-06-10", 8 | "Script": "installscript.qs", 9 | "Virtual": "true", 10 | "DownloadableArchives": "vcredist_x86.7z", 11 | "CompressedSize": "8.6M", 12 | "UncompressedSize": "8.6M", 13 | "SHA1": "938fd39f13d038eaa0b2b297d8e1946d831dcef1" 14 | }, 15 | "qt.tools.vcredist_64": { 16 | "Name": "qt.tools.vcredist_64", 17 | "DisplayName": "VCRedist for MSVC 64bit", 18 | "Description": "Needed by all included Qt applications.", 19 | "Version": "2022-06-07", 20 | "ReleaseDate": "2022-06-10", 21 | "Script": "installscript.qs", 22 | "Virtual": "true", 23 | "DownloadableArchives": "vcredist_x64.7z", 24 | "CompressedSize": "9.9M", 25 | "UncompressedSize": "9.8M", 26 | "SHA1": "f7a86d298c0f876c198e35b7198d916b3059b75b" 27 | }, 28 | "qt.tools.vcredist_msvc2013_x64": { 29 | "Name": "qt.tools.vcredist_msvc2013_x64", 30 | "DisplayName": "VCRedist for MSVC 2013 64bit", 31 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2013 64 bit", 32 | "Version": "2017-03-22-0", 33 | "ReleaseDate": "2022-06-10", 34 | "Script": "installscript.qs", 35 | "Virtual": "true", 36 | "DownloadableArchives": "vcredist_msvc2013_x64.7z", 37 | "CompressedSize": "6.7M", 38 | "UncompressedSize": "6.9M", 39 | "SHA1": "9bec8dfdd70b0ee0607a1d96c7ee44b8b76bb4ab" 40 | }, 41 | "qt.tools.vcredist_msvc2013_x86": { 42 | "Name": "qt.tools.vcredist_msvc2013_x86", 43 | "DisplayName": "VCRedist for MSVC 2013 32bit", 44 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2013 32 bit", 45 | "Version": "2014-30-12-1", 46 | "ReleaseDate": "2022-06-10", 47 | "Script": "installscript.qs", 48 | "Virtual": "true", 49 | "DownloadableArchives": "vcredist_msvc2013_x86.7z", 50 | "CompressedSize": "6.0M", 51 | "UncompressedSize": "6.2M", 52 | "SHA1": "52fd4043307adcd165e5f4ffac8c39c6758aa756" 53 | }, 54 | "qt.tools.vcredist_msvc2015_x64": { 55 | "Name": "qt.tools.vcredist_msvc2015_x64", 56 | "DisplayName": "VCRedist for MSVC 2015 64bit", 57 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2015 64 bit", 58 | "Version": "2017-03-22-0", 59 | "ReleaseDate": "2022-06-10", 60 | "Script": "installscript.qs", 61 | "Virtual": "true", 62 | "DownloadableArchives": "vcredist_msvc2015_x64.7z", 63 | "CompressedSize": "13.0M", 64 | "UncompressedSize": "13.9M", 65 | "SHA1": "f54bea33255af844007f8f7cc21441aeb946f008" 66 | }, 67 | "qt.tools.vcredist_msvc2015_x86": { 68 | "Name": "qt.tools.vcredist_msvc2015_x86", 69 | "DisplayName": "VCRedist for MSVC 2015 32bit", 70 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2015 32 bit", 71 | "Version": "2017-02-01-0", 72 | "ReleaseDate": "2022-06-10", 73 | "Script": "installscript.qs", 74 | "Virtual": "true", 75 | "DownloadableArchives": "vcredist_msvc2015_x86.7z", 76 | "CompressedSize": "12.2M", 77 | "UncompressedSize": "13.8M", 78 | "SHA1": "17e17c17ff9c376b07a4672428b6f0214c296631" 79 | }, 80 | "qt.tools.vcredist_msvc2017_x64": { 81 | "Name": "qt.tools.vcredist_msvc2017_x64", 82 | "DisplayName": "VCRedist for MSVC 2017 64bit", 83 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2017 64 bit", 84 | "Version": "2019-02-13-1", 85 | "ReleaseDate": "2022-06-10", 86 | "Script": "installscript.qs", 87 | "Virtual": "true", 88 | "DownloadableArchives": "vcredist_msvc2017_x64.7z", 89 | "CompressedSize": "13.0M", 90 | "UncompressedSize": "14.6M", 91 | "SHA1": "90be6ece659a33d0b07f6f238af63b5caaf86272" 92 | }, 93 | "qt.tools.vcredist_msvc2017_x86": { 94 | "Name": "qt.tools.vcredist_msvc2017_x86", 95 | "DisplayName": "VCRedist for MSVC 2017 32bit", 96 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2017 32 bit", 97 | "Version": "2019-02-13-1", 98 | "ReleaseDate": "2022-06-10", 99 | "Script": "installscript.qs", 100 | "Virtual": "true", 101 | "DownloadableArchives": "vcredist_msvc2017_x86.7z", 102 | "CompressedSize": "12.3M", 103 | "UncompressedSize": "14.0M", 104 | "SHA1": "e739395f1625b3e0dd3124d9a22b643d2f0598e2" 105 | }, 106 | "qt.tools.vcredist_msvc2019_x64": { 107 | "Name": "qt.tools.vcredist_msvc2019_x64", 108 | "DisplayName": "VCRedist for MSVC 2019 64bit", 109 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2019 64 bit", 110 | "Version": "2022-06-07", 111 | "ReleaseDate": "2022-06-10", 112 | "Script": "installscript.qs", 113 | "Virtual": "true", 114 | "DownloadableArchives": "vcredist_msvc2019_x64.7z", 115 | "CompressedSize": "12.7M", 116 | "UncompressedSize": "14.4M", 117 | "SHA1": "da891aab9697f86af4734b5d1372c750280bb8ea" 118 | }, 119 | "qt.tools.vcredist_msvc2019_x86": { 120 | "Name": "qt.tools.vcredist_msvc2019_x86", 121 | "DisplayName": "VCRedist for MSVC 2019 32bit", 122 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2019 32 bit", 123 | "Version": "2022-06-07", 124 | "ReleaseDate": "2022-06-10", 125 | "Script": "installscript.qs", 126 | "Virtual": "true", 127 | "DownloadableArchives": "vcredist_msvc2019_x86.7z", 128 | "CompressedSize": "12.1M", 129 | "UncompressedSize": "13.7M", 130 | "SHA1": "3994694b307508f0b0656f4d4ef4d06ab81df573" 131 | } 132 | } -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/functional.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | fetch_arches, 3 | fetch_archives, 4 | fetch_modules, 5 | fetch_tools, 6 | } from "./list-qt"; 7 | import util from "util"; 8 | import { exec } from "child_process"; 9 | import { hosts, targetsForHost } from "../lib/utils"; 10 | import { 11 | Host, 12 | hostFromStr, 13 | HostString, 14 | hostToStr, 15 | PackageUpdate, 16 | Target, 17 | targetFromStr, 18 | TargetString, 19 | targetToStr, 20 | } from "../lib/types"; 21 | import { SemVer } from "semver"; 22 | 23 | const exec_promise = util.promisify(exec); 24 | 25 | const get_versions = async ( 26 | host: Host, 27 | target: Target 28 | ): Promise => { 29 | const stdout: string = ( 30 | await exec_promise( 31 | `python -m aqt list-qt ${hostToStr(host)} ${targetToStr(target)}` 32 | ) 33 | ).stdout.trim(); 34 | if (stdout.length === 0) return []; 35 | return stdout.split(/\r?\n/).map((line: string) => line.split(/\s+/)); 36 | }; 37 | 38 | const get_aqt_output = async (args: string[]): Promise => { 39 | const stdout: string = ( 40 | await exec_promise(`python -m aqt ${args.join(" ")}`) 41 | ).stdout.trim(); 42 | if (stdout.length === 0) return []; 43 | return stdout.split(/\s+/); 44 | }; 45 | 46 | describe("list-qt.ts", () => { 47 | hosts 48 | .filter((host: Host) => host !== Host.windows_arm64) 49 | .forEach((host: Host) => 50 | targetsForHost(host).forEach((target: Target) => { 51 | // aqt list-qt is currently broken for this purpose 52 | // it(`lists versions for host ${hostToStr(host)} and target ${targetToStr( 53 | // target 54 | // )}`, async () => { 55 | // const actual = await fetch_versions(host, target); 56 | // const expected = await get_versions(host, target); 57 | // expect(actual).toEqual(expected); 58 | // }); 59 | 60 | it(`lists tools for host ${hostToStr(host)} and target ${targetToStr( 61 | target 62 | )}`, async () => { 63 | const actual = await fetch_tools(host, target); 64 | const expected = await get_aqt_output([ 65 | "list-tool", 66 | hostToStr(host), 67 | targetToStr(target), 68 | ]) 69 | // tools_generic is an empty module and should not be reported 70 | .then((x) => 71 | x.filter( 72 | (s: string) => 73 | !s.includes("preview") && !["tools_generic"].includes(s) 74 | ) 75 | ) 76 | .then((x) => { 77 | // Edge case: tools_telemetry_eval_gui for linux_arm64 does not include an Updates.xml file. 78 | // aqtinstall cannot install it; list-qt should not list it. 79 | return x.filter( 80 | (s: string) => 81 | !( 82 | s === "tools_telemetry_eval_gui" && 83 | host === Host.linux_arm64 84 | ) 85 | ); 86 | }) 87 | .then((x) => x.sort()); 88 | expect(actual).toEqual(expected); 89 | }); 90 | }) 91 | ); 92 | 93 | it.each` 94 | host | target | version 95 | ${"windows"} | ${"desktop"} | ${"5.9.0"} 96 | ${"windows"} | ${"desktop"} | ${"5.13.0"} 97 | ${"windows"} | ${"desktop"} | ${"5.13.1"} 98 | ${"windows"} | ${"desktop"} | ${"5.15.2"} 99 | ${"windows"} | ${"desktop"} | ${"6.2.4"} 100 | ${"windows"} | ${"android"} | ${"5.9.0"} 101 | ${"windows"} | ${"android"} | ${"5.13.1"} 102 | ${"windows"} | ${"android"} | ${"5.15.2"} 103 | ${"windows"} | ${"android"} | ${"6.2.4"} 104 | ${"mac"} | ${"ios"} | ${"5.9.0"} 105 | ${"mac"} | ${"ios"} | ${"5.13.1"} 106 | ${"mac"} | ${"ios"} | ${"5.15.2"} 107 | ${"mac"} | ${"ios"} | ${"6.2.4"} 108 | ${"linux"} | ${"desktop"} | ${"6.5.0"} 109 | `( 110 | "should retrieve architectures for $host $target $version", 111 | async ({ 112 | host, 113 | target, 114 | version, 115 | }: { 116 | host: HostString; 117 | target: TargetString; 118 | version: string; 119 | hard_expect: string; 120 | }) => { 121 | const actual = await fetch_arches( 122 | hostFromStr(host), 123 | targetFromStr(target), 124 | new SemVer(version) 125 | ); 126 | const expected = await get_aqt_output([ 127 | "list-qt", 128 | host, 129 | target, 130 | "--arch", 131 | version, 132 | ]); 133 | 134 | expect(actual.sort()).toEqual(expected.sort()); 135 | }, 136 | 10 * 1000 // 10 second timeout: it takes 6 seconds to run `aqt list-qt android --arch 6.2.4` 137 | ); 138 | 139 | it.each` 140 | host | target | version | arch 141 | ${"windows"} | ${"desktop"} | ${"5.9.0"} | ${"win32_mingw53"} 142 | ${"windows"} | ${"desktop"} | ${"5.13.1"} | ${"wasm_32"} 143 | ${"windows"} | ${"desktop"} | ${"5.15.2"} | ${"win64_mingw81"} 144 | ${"windows"} | ${"desktop"} | ${"6.2.4"} | ${"win64_mingw"} 145 | `( 146 | "should retrieve modules for $host $target $version $arch", 147 | async ({ 148 | host, 149 | target, 150 | version, 151 | arch, 152 | }: { 153 | host: HostString; 154 | target: TargetString; 155 | version: string; 156 | arch: string; 157 | }) => { 158 | type ArgsT = [Host, Target, SemVer, string]; 159 | const args: ArgsT = [ 160 | hostFromStr(host), 161 | targetFromStr(target), 162 | new SemVer(version), 163 | arch, 164 | ]; 165 | const actual_modules = (await fetch_modules(...args)) 166 | .map((pkg: PackageUpdate): string => { 167 | const parts = pkg.Name.split("."); 168 | return parts[parts.length - 2]; 169 | }) 170 | .sort(); 171 | const actual_archives = (await fetch_archives(...args, [])).sort(); 172 | const [expect_modules, expect_archives] = await Promise.all([ 173 | get_aqt_output(["list-qt", host, target, "--modules", version, arch]), 174 | get_aqt_output(["list-qt", host, target, "--archives", version, arch]), 175 | ]); 176 | 177 | expect(actual_modules).toEqual(expect_modules); 178 | expect(actual_archives).toEqual(expect_archives); 179 | } 180 | ); 181 | }); 182 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-desktop-tools_vcredist-expect.json: -------------------------------------------------------------------------------- 1 | { 2 | "modules": [ 3 | "qt.tools.vcredist", 4 | "qt.tools.vcredist_msvc2015_x86", 5 | "qt.tools.vcredist_msvc2013_x64", 6 | "qt.tools.vcredist_msvc2015_x64", 7 | "qt.tools.vcredist_msvc2013_x86", 8 | "qt.tools.vcredist_msvc2017_x64", 9 | "qt.tools.vcredist_msvc2017_x86", 10 | "qt.tools.vcredist_64", 11 | "qt.tools.vcredist_msvc2019_x64", 12 | "qt.tools.vcredist_msvc2019_x86" 13 | ], 14 | "architectures": [ 15 | "msvc2015_x86", 16 | "msvc2013_x64", 17 | "msvc2015_x64", 18 | "msvc2013_x86", 19 | "msvc2017_x64", 20 | "msvc2017_x86", 21 | "64", 22 | "msvc2019_x64", 23 | "msvc2019_x86" 24 | ], 25 | "modules_data": { 26 | "qt.tools.vcredist": { 27 | "DisplayName": "VCRedist for MSVC 32bit", 28 | "Description": "Needed by all included Qt applications.", 29 | "Version": "2011-03-03-1", 30 | "ReleaseDate": "2014-11-17", 31 | "Script": "installscript.qs", 32 | "Virtual": "true", 33 | "DownloadableArchives": "vcredist_x86.7z", 34 | "UpdateFile": { 35 | "CompressedSize": "9065989", 36 | "UncompressedSize": "8990592", 37 | "OS": "Any" 38 | }, 39 | "SHA1": "6ef633831c4f10e2a975f0cb8bfbbf572dcec1dd" 40 | }, 41 | "qt.tools.vcredist_msvc2015_x86": { 42 | "DisplayName": "VCRedist for MSVC 2015 32bit", 43 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2015 32 bit", 44 | "Version": "2017-02-01-0", 45 | "ReleaseDate": "2017-01-20", 46 | "Script": "installscript.qs", 47 | "Virtual": "true", 48 | "DownloadableArchives": "vcredist_msvc2015_x86.7z", 49 | "UpdateFile": { 50 | "CompressedSize": "12766475", 51 | "UncompressedSize": "14456912", 52 | "OS": "Any" 53 | }, 54 | "SHA1": "04c9b1bdc305877640643b1faae639c61f687b3b" 55 | }, 56 | "qt.tools.vcredist_msvc2013_x64": { 57 | "DisplayName": "VCRedist for MSVC 2013 64bit", 58 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2013 64 bit", 59 | "Version": "2017-3-22-0", 60 | "ReleaseDate": "2017-03-23", 61 | "Script": "installscript.qs", 62 | "Virtual": "true", 63 | "DownloadableArchives": "vcredist_msvc2013_x64.7z", 64 | "UpdateFile": { 65 | "CompressedSize": "6985453", 66 | "UncompressedSize": "7194352", 67 | "OS": "Any" 68 | }, 69 | "SHA1": "51f48b502beb8600ec3a1a782513efdea76472ec" 70 | }, 71 | "qt.tools.vcredist_msvc2015_x64": { 72 | "DisplayName": "VCRedist for MSVC 2015 64bit", 73 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2015 64 bit", 74 | "Version": "2017-03-22-0", 75 | "ReleaseDate": "2017-03-23", 76 | "Script": "installscript.qs", 77 | "Virtual": "true", 78 | "DownloadableArchives": "vcredist_msvc2015_x64.7z", 79 | "UpdateFile": { 80 | "CompressedSize": "13606284", 81 | "UncompressedSize": "14572040", 82 | "OS": "Any" 83 | }, 84 | "SHA1": "5ee3387de572f380387ade03ae8ec258c08e30c1" 85 | }, 86 | "qt.tools.vcredist_msvc2013_x86": { 87 | "DisplayName": "VCRedist for MSVC 2013 32bit", 88 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2013 32 bit", 89 | "Version": "2014-30-12-1", 90 | "ReleaseDate": "2019-04-16", 91 | "Script": "installscript.qs", 92 | "Virtual": "true", 93 | "DownloadableArchives": "vcredist_msvc2013_x86.7z", 94 | "UpdateFile": { 95 | "CompressedSize": "6233389", 96 | "UncompressedSize": "6504024", 97 | "OS": "Any" 98 | }, 99 | "SHA1": "cda6e0ce528e0d38b34f41a8ba5fb57269611578" 100 | }, 101 | "qt.tools.vcredist_msvc2017_x64": { 102 | "DisplayName": "VCRedist for MSVC 2017 64bit", 103 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2017 64 bit", 104 | "Version": "2019-02-13-1", 105 | "ReleaseDate": "2019-04-16", 106 | "Script": "installscript.qs", 107 | "Virtual": "true", 108 | "DownloadableArchives": "vcredist_msvc2017_x64.7z", 109 | "UpdateFile": { 110 | "CompressedSize": "13483747", 111 | "UncompressedSize": "15330104", 112 | "OS": "Any" 113 | }, 114 | "SHA1": "bec7506fdf840eeaa871c3b44b0c3064a81e9a40" 115 | }, 116 | "qt.tools.vcredist_msvc2017_x86": { 117 | "DisplayName": "VCRedist for MSVC 2017 32bit", 118 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2017 32 bit", 119 | "Version": "2019-02-13-1", 120 | "ReleaseDate": "2019-04-16", 121 | "Script": "installscript.qs", 122 | "Virtual": "true", 123 | "DownloadableArchives": "vcredist_msvc2017_x86.7z", 124 | "UpdateFile": { 125 | "CompressedSize": "12811307", 126 | "UncompressedSize": "14648504", 127 | "OS": "Any" 128 | }, 129 | "SHA1": "26b5a9ae55b13a538791f549c98621a315d26969" 130 | }, 131 | "qt.tools.vcredist_64": { 132 | "DisplayName": "VCRedist for MSVC 64bit", 133 | "Description": "Needed by all included Qt applications.", 134 | "Version": "2020-03-18", 135 | "ReleaseDate": "2020-03-19", 136 | "Script": "installscript.qs", 137 | "Virtual": "true", 138 | "DownloadableArchives": "vcredist_x64.7z", 139 | "UpdateFile": { 140 | "CompressedSize": "10249462", 141 | "UncompressedSize": "10274176", 142 | "OS": "Any" 143 | }, 144 | "SHA1": "3cb06ab7fc3a2633edeb1bc9f91ecf7048323b9e" 145 | }, 146 | "qt.tools.vcredist_msvc2019_x64": { 147 | "DisplayName": "VCRedist for MSVC 2019 64bit", 148 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2019 64 bit", 149 | "Version": "2020-05-19-1", 150 | "ReleaseDate": "2020-05-19", 151 | "Script": "installscript.qs", 152 | "Virtual": "true", 153 | "DownloadableArchives": "vcredist_msvc2019_x64.7z", 154 | "UpdateFile": { 155 | "CompressedSize": "13209756", 156 | "UncompressedSize": "15060536", 157 | "OS": "Any" 158 | }, 159 | "SHA1": "5e1a6ebf086382c0f2f7e816fe0f15daecb07bf6" 160 | }, 161 | "qt.tools.vcredist_msvc2019_x86": { 162 | "DisplayName": "VCRedist for MSVC 2019 32bit", 163 | "Description": "Visual C++ Redistributable Packages for Visual Studio 2019 32 bit", 164 | "Version": "2019-05-19-1", 165 | "ReleaseDate": "2020-05-19", 166 | "Script": "installscript.qs", 167 | "Virtual": "true", 168 | "DownloadableArchives": "vcredist_msvc2019_x86.7z", 169 | "UpdateFile": { 170 | "CompressedSize": "12515252", 171 | "UncompressedSize": "14364480", 172 | "OS": "Any" 173 | }, 174 | "SHA1": "e82eeed4f19dd172944149a478c8bf48ff148b0d" 175 | } 176 | } 177 | } -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import QtSelectorPanel from "./Components/QtSelectorPanel"; 3 | import CommandPanel from "./Components/CommandPanel"; 4 | import ToolSelectPanel from "./Components/ToolSelectPanel"; 5 | import SelectMany from "./Components/SelectMany"; 6 | import { makeState, NO_SELECTION, StateUtils as S, ToolData } from "./State"; 7 | import { 8 | Host, 9 | hostFromStr, 10 | HostString, 11 | Target, 12 | targetFromStr, 13 | TargetString, 14 | } from "./lib/types"; 15 | import { 16 | fetch_arches, 17 | fetch_archive_info, 18 | fetch_modules, 19 | fetch_online_installers, 20 | fetch_tool_variants, 21 | fetch_tools, 22 | fetch_versions, 23 | } from "./aqt-list-qt-ts/list-qt"; 24 | import "./app.scss"; 25 | import { SemVer } from "semver"; 26 | import ComboBox, { options } from "./Components/ComboBox"; 27 | 28 | const App = (): JSX.Element => { 29 | const [state, setState] = useState(makeState((_) => "")); 30 | const loadVersionsTools = async (host: Host, target: Target) => { 31 | const [versions, tools, unifiedInstallers] = await Promise.all([ 32 | fetch_versions(host, target), 33 | fetch_tools(host, target), 34 | fetch_online_installers(), 35 | ]); 36 | setState( 37 | S.withInstallersVersionsToolsLoaded(unifiedInstallers, versions, tools) 38 | ); 39 | }; 40 | const loadModulesArchives = async ( 41 | host: Host, 42 | target: Target, 43 | version: string, 44 | arch: string 45 | ) => { 46 | const [modules, archives] = await Promise.all([ 47 | fetch_modules(host, target, new SemVer(version), arch), 48 | fetch_archive_info(host, target, new SemVer(version), arch, []), 49 | ]); 50 | setState(S.withModulesArchivesLoaded(modules, archives)); 51 | }; 52 | const loadArches = async (host: Host, target: Target, version: string) => { 53 | const arches = await fetch_arches(host, target, new SemVer(version)); 54 | setState(S.withArchesLoaded(arches)); // will set arch automatically if only 1 arch available 55 | if (arches.length === 1) { 56 | // chain load of arches when only one option exists 57 | await loadModulesArchives(host, target, version, arches[0]); 58 | } 59 | }; 60 | const loadTool = async (host: Host, target: Target, toolName: string) => { 61 | const variants = await fetch_tool_variants(host, target, toolName); 62 | setState(S.withNewTool(ToolData.fromPackageUpdates(toolName, variants))); 63 | }; 64 | const isInvalid = (option: string) => option === NO_SELECTION || !option; 65 | 66 | // If versions is marked 'Loading...', we should load it: 67 | if (state.version.selected.state.isLoading()) 68 | loadVersionsTools( 69 | hostFromStr(state.host.selected.value as HostString), 70 | targetFromStr(state.target.selected.value as TargetString) 71 | ); 72 | 73 | return ( 74 |
75 |

aqt list-qt server

76 |
77 | 83 | setState( 84 | S.withHostLoadingVersionsTools(hostFromStr(host as HostString)) 85 | ) 86 | } 87 | changeTarget={async (target: string) => 88 | setState( 89 | S.withTargetLoadingVersionsTools( 90 | targetFromStr(target as TargetString) 91 | ) 92 | ) 93 | } 94 | changeVersion={async (version: string) => { 95 | setState(S.withVersionLoadingArches(version)); 96 | if (isInvalid(version)) return; 97 | const { host, target } = state.values(); 98 | await loadArches(host, target, version); 99 | }} 100 | changeArch={async (arch: string) => { 101 | setState(S.withArchLoadingModulesArchives(arch)); 102 | const { host, target, version } = state.values(); 103 | if (isInvalid(arch) || isInvalid(version)) return; 104 | await loadModulesArchives(host, target, version, arch); 105 | }} 106 | /> 107 | Choose modules:} 111 | options={state.modules.selections} 112 | toggleAll={(on: boolean) => setState(S.withToggledModules(on))} 113 | toggleOne={(on: boolean, name: string) => 114 | setState(S.withModuleSet(name, on)) 115 | } 116 | /> 117 | Choose archives:} 121 | options={state.archives.selections} 122 | toggleAll={(on: boolean) => setState(S.withToggledArchives(on))} 123 | toggleOne={(on: boolean, name: string) => 124 | setState(S.withArchiveSet(name, on)) 125 | } 126 | /> 127 |
128 | { 132 | const { host, target } = state.values(); 133 | setState(S.withNewTool(new ToolData(toolName, true, new Map()))); 134 | await loadTool(host, target, toolName); 135 | }} 136 | removeTool={(toolName: string) => setState(S.withoutTool(toolName))} 137 | setToolVariant={(toolName: string, toolVariant: string, on: boolean) => 138 | setState(S.withToolVariant(toolName, toolVariant, on)) 139 | } 140 | toggleToolVariants={(toolName: string, on: boolean) => 141 | setState(S.withToggledToolVariants(toolName, on)) 142 | } 143 | /> 144 | 148 | Your aqt install{" "} 149 | command: 150 | 151 | } 152 | command={state.toAqtInstallCmd()} 153 | isDisabled={!state.hasOutputs()} 154 | /> 155 | 161 | setState(S.withInstallActionVersion(version)) 162 | } 163 | > 164 | {options(state.installActionVersion, "install-action-version")} 165 | 166 | 170 | Your{" "} 171 | 172 | jurplel/install-qt-action 173 | {" "} 174 | yml: 175 | 176 | } 177 | command={state.toInstallQtAction()} 178 | isDisabled={!state.hasOutputs()} 179 | /> 180 | 184 | Your{" "} 185 | 186 | official qt install 187 | {" "} 188 | {state.isWindows() ? "powershell" : "bash"} command: (Please note 189 | that this command will require patience and CLI option wrangling to 190 | get it to work unattended) 191 | 192 | } 193 | command={state.toOfficialInstallCmd()} 194 | isDisabled={!state.hasOutputs()} 195 | /> 196 |
197 | ); 198 | }; 199 | export default App; 200 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/list-qt-impl.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directory, 3 | Host, 4 | hostToStr, 5 | OnlineInstallers, 6 | PackageUpdate, 7 | RawPackageUpdates, 8 | Target, 9 | to_package_updates, 10 | UnifiedInstallers, 11 | } from "../lib/types"; 12 | import semver, { SemVer } from "semver"; 13 | import Config from "../config.json"; 14 | 15 | const BASE_URL = Config.QT_JSON_CACHE_BASE_URL; 16 | const HARDCODED_ALLOWED_TOOLS = ["sdktool"]; 17 | 18 | export const to_versions = (directory: Directory): string[][] => { 19 | const should_include_folder = (name: string): boolean => 20 | ["_preview", "_src_doc_examples"].reduce( 21 | (accum: boolean, ext: string) => accum && !name.endsWith(ext), 22 | true 23 | ); 24 | const raw_versions = directory.qt 25 | .filter(should_include_folder) 26 | .map((name: string) => name.match(/^qt\d_(\d+)/)) 27 | .reduce>((accum, match: RegExpMatchArray | null) => { 28 | if (match !== null) accum.add(match[1]); 29 | return accum; 30 | }, new Set()); 31 | const versions = Array.from(raw_versions) 32 | .map((ver: string) => { 33 | const chop_at = (a: number, b: number) => 34 | new SemVer(`${ver.slice(0, a)}.${ver.slice(a, b)}.${ver.slice(b)}`); 35 | if (ver.length > 3) return chop_at(1, 3); 36 | if (ver.length === 3) return chop_at(1, 2); 37 | if (ver.length === 2) return new SemVer(`${ver[0]}.${ver[1]}.0`); 38 | throw new Error("Regex should make this unreachable"); 39 | }) 40 | .sort(semver.compare); 41 | 42 | // Sort and stratify 43 | const to_major_minor = (ver: SemVer): string => `${ver.major}.${ver.minor}`; 44 | const initial: { stratified: string[][]; major_minor: string } = { 45 | stratified: [], 46 | major_minor: "", 47 | }; 48 | return versions.reduce(({ stratified, major_minor }, ver) => { 49 | const curr_mm = to_major_minor(ver); 50 | if (major_minor === "") 51 | return { stratified: [[ver.format()]], major_minor: curr_mm }; 52 | else if (major_minor != curr_mm) 53 | return { 54 | stratified: [...stratified, [ver.format()]], 55 | major_minor: curr_mm, 56 | }; 57 | stratified[stratified.length - 1].push(ver.format()); 58 | return { stratified, major_minor }; 59 | }, initial).stratified; 60 | }; 61 | 62 | export const version_nodot = (version: SemVer): string => 63 | version.compare("5.9.0") === 0 64 | ? `${version.major}${version.minor}` 65 | : `${version.major}${version.minor}${version.patch}`; 66 | 67 | export const to_arches = ( 68 | updates: RawPackageUpdates, 69 | [actual_ver]: [SemVer] 70 | ): string[] => { 71 | const ver_nodot = version_nodot(actual_ver); 72 | return to_package_updates(updates) 73 | .filter((pkg: PackageUpdate) => pkg.DownloadableArchives.length) 74 | .reduce((accum, pkg: PackageUpdate) => { 75 | const [ver, arch] = pkg.Name.split(".").slice(-2); 76 | if (ver === ver_nodot) accum.push(arch); 77 | return accum; 78 | }, Array()) 79 | .sort(); 80 | }; 81 | 82 | export const to_modules = ( 83 | updates: RawPackageUpdates, 84 | [actual_ver, arch]: [SemVer, string] 85 | ): PackageUpdate[] => { 86 | const ver_nodot = version_nodot(actual_ver); 87 | //(r"^(preview\.)?qt\.(qt" + str(version.major) + r"\.)?" + qt_ver_str + r"\.(.+)$") 88 | const pattern = new RegExp( 89 | "^(preview.)?qt.(qt" + 90 | actual_ver.major + 91 | ".)?" + 92 | ver_nodot + 93 | ".(addons.)?(.+)." + 94 | arch + 95 | "$" 96 | ); 97 | return to_package_updates(updates) 98 | .filter((pkg: PackageUpdate) => pkg.DownloadableArchives.length) 99 | .filter((pkg: PackageUpdate): boolean => { 100 | const module = pkg.Name.match(pattern)?.[4]; 101 | return module !== undefined && (module as string).length > 0; 102 | }); 103 | // .reduce((accum, pkg: PackageUpdate) => { 104 | // const mod_arch = pkg.Name.match(pattern)?.[4]; 105 | // if (mod_arch) { 106 | // const chop_at = mod_arch.lastIndexOf("."); 107 | // if (chop_at > 0 && arch === mod_arch.slice(chop_at + 1)) 108 | // accum.push(mod_arch.slice(0, chop_at)); 109 | // } 110 | // return accum; 111 | // }, Array()); 112 | }; 113 | 114 | // const retrieve_archive_info = (pkg_update: PackageUpdate): {filename_7z: string, size: string}[] => { 115 | // if 116 | // return []; 117 | // }; 118 | 119 | type StringMap = Map; 120 | const flattenMaps = (maps: StringMap[]): StringMap => { 121 | return maps.reduce((accum: StringMap, m: StringMap) => { 122 | m.forEach((value: string, key: string) => { 123 | accum.set(key, value); 124 | }); 125 | return accum; 126 | }, new Map()); 127 | }; 128 | 129 | export const to_archives = ( 130 | updates: RawPackageUpdates, 131 | [ver, arch, modules]: [SemVer, string, string[]] 132 | ): Map => { 133 | const ver_nodot = version_nodot(ver); 134 | const maps = to_package_updates(updates) 135 | .filter((pkg: PackageUpdate) => { 136 | const [mod, _arch] = pkg.Name.split(".").slice(-2); 137 | return ( 138 | pkg.DownloadableArchives.length > 0 && 139 | ((arch === _arch && modules.includes(mod)) || 140 | pkg.Name.endsWith(`${ver_nodot}.${arch}`)) 141 | ); 142 | }) 143 | .map((pkg: PackageUpdate) => pkg.ArchiveSizes); 144 | return flattenMaps(maps); 145 | }; 146 | 147 | export const to_tools = (directory: Directory): string[] => 148 | directory.tools 149 | .filter( 150 | (href: string) => 151 | href.startsWith("tools_") || HARDCODED_ALLOWED_TOOLS.includes(href) 152 | ) 153 | .map((href: string) => (href.endsWith("/") ? href.slice(0, -1) : href)); 154 | 155 | export const to_tool_variants = ( 156 | updates: RawPackageUpdates 157 | ): PackageUpdate[] => { 158 | return to_package_updates(updates).filter( 159 | (pkg: PackageUpdate) => pkg.DownloadableArchives.length 160 | ); 161 | }; 162 | 163 | const to_url = ([host, target]: [Host, Target]): string => 164 | `${BASE_URL}/${Host[host]}/${Target[target]}`; 165 | 166 | export const to_directory = ([host, target]: [Host, Target]): string => 167 | `${to_url([host, target])}/directory.json`; 168 | 169 | const updates_url = ( 170 | [host, target, version]: [Host, Target, SemVer], 171 | ext?: string 172 | ): string => { 173 | const ver_nodot = `qt${version.major}_${version_nodot(version)}`; 174 | const _ext = ext ? `_${ext}` : ""; 175 | if (should_override_host_all_os(target, version)) { 176 | host = Host.all_os; 177 | } 178 | const folder = 179 | version.compare(new SemVer("6.8.0")) >= 0 ? `${ver_nodot}/` : ""; 180 | return `${to_url([host, target])}/${folder}${ver_nodot}${_ext}.json`; 181 | }; 182 | 183 | const choose_ext_for_arch = (args: [Host, Target, SemVer], arch: string) => { 184 | const [_, target, version] = args; 185 | if (arch.includes("wasm_singlethread")) { 186 | return "wasm_singlethread"; 187 | } else if (arch.includes("wasm_multithread")) { 188 | return "wasm_multithread"; 189 | } else if (arch.includes("wasm")) { 190 | return "wasm"; 191 | } 192 | if (version.major >= 6 && target == Target.android) { 193 | if (!arch.startsWith("android_")) { 194 | return ""; 195 | } 196 | const suffix = arch.substring("android_".length); 197 | if (!["arm64_v8a", "armv7", "x86_64", "x86"].includes(suffix)) { 198 | return ""; 199 | } 200 | return suffix; 201 | } 202 | }; 203 | 204 | const should_override_host_all_os = (target: Target, version: SemVer) => 205 | target == Target.android && version.compare(new SemVer("6.7.0")) >= 0; 206 | 207 | export const to_updates_urls_by_arch = 208 | (arch: string) => 209 | (args: [Host, Target, SemVer]): string => 210 | updates_url(args, choose_ext_for_arch(args, arch)); 211 | 212 | export const to_updates_urls = ( 213 | host: Host, 214 | target: Target, 215 | version: SemVer 216 | ): string[] => { 217 | const args: [Host, Target, SemVer] = [host, target, version]; 218 | if (should_override_host_all_os(target, version)) { 219 | args[0] = Host.all_os; 220 | } 221 | const extensions: string[] = ((): string[] => { 222 | if (target === Target.android && version.major >= 6) { 223 | return ["arm64_v8a", "armv7", "x86", "x86_64"]; 224 | } else if (target === Target.desktop && version.compare("6.5.0") >= 0) { 225 | return ["", "wasm_singlethread", "wasm_multithread"]; 226 | } else if (target === Target.desktop && version.compare("5.13.0") > 0) { 227 | return ["", "wasm"]; 228 | } else { 229 | return [""]; 230 | } 231 | })(); 232 | 233 | return extensions.map((suffix) => updates_url(args, suffix)); 234 | }; 235 | 236 | export const to_tools_updates_json = ([host, target, tool_name]: [ 237 | Host, 238 | Target, 239 | string 240 | ]): string => `${to_url([host, target])}/${tool_name}.json`; 241 | 242 | export const official_releases_url = `${BASE_URL}/official_releases.json`; 243 | 244 | export const to_unified_installers = ( 245 | o: OnlineInstallers, 246 | _: void 247 | ): UnifiedInstallers => { 248 | const keys = Object.entries(o["online_installers/"]).map(([key, _]) => key); 249 | return (host: Host): string => 250 | keys.find((key) => key.includes(hostToStr(host))) || ""; 251 | }; 252 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/list-qt-impl.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | to_arches, 3 | to_archives, 4 | to_modules, 5 | to_updates_urls_by_arch, 6 | to_tool_variants, 7 | to_tools, 8 | to_directory, 9 | to_versions, 10 | to_unified_installers, 11 | } from "./list-qt-impl"; 12 | import { Host, PackageUpdate, RawPackageUpdates, Target } from "../lib/types"; 13 | import win_desktop_directory from "./test_data/windows-desktop-directory.json"; 14 | import expect_win_desktop from "./test_data/windows-desktop-expect.json"; 15 | import win_620_json from "./test_data/windows-620-update.json"; 16 | import expect_win_620 from "./test_data/windows-620-expect.json"; 17 | import win_59_json from "./test_data/windows-59-update.json"; 18 | import expect_win_59 from "./test_data/windows-59-expect.json"; 19 | import win_desktop_vcredist_json from "./test_data/windows-desktop-tools_vcredist-update.json"; 20 | import expect_vcredist from "./test_data/windows-desktop-tools_vcredist-expect.json"; 21 | import official_releases from "./test_data/official_releases.json"; 22 | import Config from "../config.json"; 23 | import { SemVer } from "semver"; 24 | import { toHumanReadableSize } from "../lib/utils"; 25 | 26 | test("scrapes versions from html", () => { 27 | const expected = expect_win_desktop.qt.qt.map((major_minor_row: string) => 28 | major_minor_row.split(" ") 29 | ); 30 | const actual = to_versions(win_desktop_directory); 31 | expect(actual).toEqual(expected); 32 | }); 33 | 34 | describe("retrieves arches from json", () => { 35 | it.each` 36 | version | updates_json | expected_arches 37 | ${"5.9.0"} | ${win_59_json} | ${expect_win_59.architectures} 38 | ${"6.2.0"} | ${win_620_json} | ${expect_win_620.architectures} 39 | `( 40 | "should retrieve arches from json for version $version", 41 | ({ 42 | version, 43 | updates_json, 44 | expected_arches, 45 | }: { 46 | version: string; 47 | updates_json: RawPackageUpdates; 48 | expected_arches: string[]; 49 | }) => { 50 | const actual = to_arches(updates_json, [new SemVer(version)]); 51 | expect(actual).toEqual(expected_arches); 52 | } 53 | ); 54 | }); 55 | 56 | describe("retrieves modules from json", () => { 57 | const join_ver_testdata = ( 58 | ver: SemVer, 59 | arch_expected: [string, string[]][], 60 | updates: RawPackageUpdates 61 | ): [SemVer, string, string[], RawPackageUpdates][] => 62 | arch_expected.map(([arch, x_modules]) => [ver, arch, x_modules, updates]); 63 | 64 | it.each( 65 | join_ver_testdata( 66 | new SemVer("6.2.0"), 67 | Object.entries(expect_win_620.modules_by_arch), 68 | win_620_json as unknown as RawPackageUpdates 69 | ).concat( 70 | join_ver_testdata( 71 | new SemVer("5.9.0"), 72 | Object.entries(expect_win_59.modules_by_arch), 73 | win_59_json as unknown as RawPackageUpdates 74 | ) 75 | ) 76 | )( 77 | `should return modules when version is %s and arch is %s`, 78 | ( 79 | ver: SemVer, 80 | arch: string, 81 | expected_modules: string[], 82 | updates: RawPackageUpdates 83 | ) => { 84 | const actual = to_modules(updates, [ver, arch]).map( 85 | (pkg: PackageUpdate): string => { 86 | const parts = pkg.Name.split("."); 87 | return parts[parts.length - 2]; 88 | } 89 | ); 90 | expect(actual).toEqual(expected_modules); 91 | } 92 | ); 93 | }); 94 | 95 | test("retrieves archives from json", () => { 96 | const win_620_base_archives = [ 97 | "qtbase-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 98 | "qtsvg-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 99 | "qtdeclarative-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 100 | "qttools-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 101 | "qttranslations-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 102 | "d3dcompiler_47-x64.7z", 103 | "opengl32sw-64-mesa_11_2_2-signed.7z", 104 | ]; 105 | const win_620_pos_archives = [ 106 | "qtlocation-Windows-Windows_10-MSVC2019-Windows-Windows_10-X86_64.7z", 107 | ...win_620_base_archives, 108 | ]; 109 | 110 | const [ver, arch] = [new SemVer("6.2.0"), "win64_msvc2019_64"]; 111 | const actual_base_arc = to_archives( 112 | win_620_json as unknown as RawPackageUpdates, 113 | [ver, arch, []] 114 | ); 115 | expect([...actual_base_arc.keys()].sort()).toEqual( 116 | win_620_base_archives.map((s) => s.split("-")[0]).sort() 117 | ); 118 | const actual_base_pos_arc = to_archives( 119 | win_620_json as unknown as RawPackageUpdates, 120 | [ver, arch, ["qtpositioning"]] 121 | ); 122 | expect([...actual_base_pos_arc.keys()].sort()).toEqual( 123 | win_620_pos_archives.map((s) => s.split("-")[0]).sort() 124 | ); 125 | }); 126 | 127 | test("scrapes tools from html", () => { 128 | const expected = expect_win_desktop.tools; 129 | const actual = to_tools(win_desktop_directory); 130 | expect(actual.sort()).toEqual(expected.sort()); 131 | }); 132 | 133 | test.skip("retrieves tool variants from json", () => { 134 | const expected = Object.entries(expect_vcredist.modules_data).map( 135 | ([name, variant]) => { 136 | const { 137 | DisplayName, 138 | Description, 139 | ReleaseDate, 140 | Version, 141 | DownloadableArchives, 142 | UpdateFile: { CompressedSize, UncompressedSize }, 143 | } = variant; 144 | return { 145 | Name: name, 146 | DisplayName, 147 | Description, 148 | ReleaseDate, 149 | Version, 150 | CompressedSize: toHumanReadableSize(CompressedSize), 151 | UncompressedSize: toHumanReadableSize(UncompressedSize), 152 | DownloadableArchives: DownloadableArchives.split(", "), 153 | Dependencies: [], 154 | AutoDependOn: [], 155 | ArchiveSizes: new Map(), 156 | // selected: false, 157 | } as PackageUpdate; 158 | } 159 | ); 160 | const actual = to_tool_variants(win_desktop_vcredist_json); 161 | expect(actual).toEqual(expected); 162 | }); 163 | 164 | const BASE_URL = Config.QT_JSON_CACHE_BASE_URL; 165 | describe("constructs url for directory", () => { 166 | it.each` 167 | host | target | result 168 | ${Host.windows} | ${Target.desktop} | ${BASE_URL + "/windows/desktop/directory.json"} 169 | ${Host.windows} | ${Target.android} | ${BASE_URL + "/windows/android/directory.json"} 170 | ${Host.windows} | ${Target.winrt} | ${BASE_URL + "/windows/winrt/directory.json"} 171 | ${Host.linux} | ${Target.desktop} | ${BASE_URL + "/linux/desktop/directory.json"} 172 | ${Host.linux} | ${Target.android} | ${BASE_URL + "/linux/android/directory.json"} 173 | ${Host.mac} | ${Target.desktop} | ${BASE_URL + "/mac/desktop/directory.json"} 174 | ${Host.mac} | ${Target.android} | ${BASE_URL + "/mac/android/directory.json"} 175 | ${Host.mac} | ${Target.ios} | ${BASE_URL + "/mac/ios/directory.json"} 176 | `( 177 | `should return url when host is %s, target is %s`, 178 | ({ 179 | host, 180 | target, 181 | result, 182 | }: { 183 | host: Host; 184 | target: Target; 185 | result: string; 186 | }) => { 187 | const actual = to_directory([host, target]); 188 | expect(actual).toEqual(result); 189 | } 190 | ); 191 | }); 192 | describe("constructs url for Updates.json", () => { 193 | it.each` 194 | version | arch | expected_folder 195 | ${"5.9.0"} | ${"wasm_32"} | ${"qt5_59_wasm"} 196 | ${"6.2.0"} | ${"wasm_64"} | ${"qt6_620_wasm"} 197 | ${"6.6.0"} | ${"wasm_128"} | ${"qt6_660_wasm"} 198 | ${"5.12.11"} | ${"wasm_16"} | ${"qt5_51211_wasm"} 199 | ${"5.9.0"} | ${"mingw"} | ${"qt5_59"} 200 | ${"6.2.0"} | ${"mingw"} | ${"qt6_620"} 201 | ${"6.7.0"} | ${"mingw"} | ${"qt6_670"} 202 | ${"6.8.0"} | ${"mingw"} | ${"qt6_680/qt6_680"} 203 | ${"5.12.11"} | ${"mingw"} | ${"qt5_51211"} 204 | ${"6.7.0"} | ${"wasm_singlethread"} | ${"qt6_670_wasm_singlethread"} 205 | ${"6.7.0"} | ${"wasm_multithread"} | ${"qt6_670_wasm_multithread"} 206 | ${"6.8.0"} | ${"wasm_multithread"} | ${"qt6_680/qt6_680_wasm_multithread"} 207 | `( 208 | `should return url when version is $version, arch is $arch`, 209 | ({ 210 | version, 211 | arch, 212 | expected_folder, 213 | }: { 214 | version: string; 215 | arch: string; 216 | expected_folder: string; 217 | }) => { 218 | const [host, target] = [Host.windows, Target.desktop]; 219 | const actual = to_updates_urls_by_arch(arch)([ 220 | host, 221 | target, 222 | new SemVer(version), 223 | ]); 224 | expect(actual).toEqual( 225 | `${BASE_URL}/windows/desktop/${expected_folder}.json` 226 | ); 227 | } 228 | ); 229 | }); 230 | 231 | describe("to_unified_installers", () => { 232 | it.each` 233 | host | installer 234 | ${Host.mac} | ${"qt-unified-mac-x64-online.dmg"} 235 | ${Host.linux} | ${"qt-unified-linux-x64-online.run"} 236 | ${Host.windows} | ${"qt-unified-windows-x64-online.exe"} 237 | `( 238 | `should return the $installer installer`, 239 | ({ host, installer }: { host: Host; installer: string }) => { 240 | const actual = to_unified_installers(official_releases); 241 | expect(actual(host)).toEqual(installer); 242 | } 243 | ); 244 | }); 245 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-620-wasm-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "qt.qt6.620.addons.qtcharts.wasm_32": { 3 | "Name": "qt.qt6.620.addons.qtcharts.wasm_32", 4 | "DisplayName": "Qt Charts for WebAssembly", 5 | "Description": null, 6 | "Version": "6.2.0-0-202109261634", 7 | "ReleaseDate": "2021-09-26", 8 | "AutoDependOn": "qt.qt6.620.addons.qtcharts, qt.qt6.620.wasm_32", 9 | "Dependencies": "qt.qt6.620.wasm_32", 10 | "Virtual": "true", 11 | "Script": "installscript.qs", 12 | "SortingPriority": null, 13 | "DownloadableArchives": "qtcharts-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 14 | "CompressedSize": "16.2M", 15 | "UncompressedSize": "108.0M", 16 | "SHA1": "d207af714d34e6837828d1d25a85f965caf1cca9" 17 | }, 18 | "qt.qt6.620.addons.qtdatavis3d.wasm_32": { 19 | "Name": "qt.qt6.620.addons.qtdatavis3d.wasm_32", 20 | "DisplayName": "Qt Data Visualization for WebAssembly", 21 | "Description": null, 22 | "Version": "6.2.0-0-202109261634", 23 | "ReleaseDate": "2021-09-26", 24 | "AutoDependOn": "qt.qt6.620.addons.qtdatavis3d, qt.qt6.620.wasm_32", 25 | "Dependencies": "qt.qt6.620.wasm_32", 26 | "Virtual": "true", 27 | "Script": "installscript.qs", 28 | "SortingPriority": null, 29 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 30 | "CompressedSize": "7.9M", 31 | "UncompressedSize": "56.3M", 32 | "SHA1": "b8d00e07d2b7ae16755dcc0640c0304acb9a3e2c" 33 | }, 34 | "qt.qt6.620.addons.qtimageformats.wasm_32": { 35 | "Name": "qt.qt6.620.addons.qtimageformats.wasm_32", 36 | "DisplayName": "Qt ImageFormats for WebAssembly", 37 | "Description": null, 38 | "Version": "6.2.0-0-202109261634", 39 | "ReleaseDate": "2021-09-26", 40 | "AutoDependOn": "qt.qt6.620.addons.qtimageformats, qt.qt6.620.wasm_32", 41 | "Dependencies": "qt.qt6.620.wasm_32", 42 | "Virtual": "true", 43 | "Script": "installscript.qs", 44 | "SortingPriority": null, 45 | "DownloadableArchives": "qtimageformats-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 46 | "CompressedSize": "2.0M", 47 | "UncompressedSize": "11.5M", 48 | "SHA1": "0f73ef7a4caea47e905da5b484e44b18a9069d52" 49 | }, 50 | "qt.qt6.620.addons.qtlottie.wasm_32": { 51 | "Name": "qt.qt6.620.addons.qtlottie.wasm_32", 52 | "DisplayName": "Qt Lottie Animation for WebAssembly", 53 | "Description": null, 54 | "Version": "6.2.0-0-202109261634", 55 | "ReleaseDate": "2021-09-26", 56 | "AutoDependOn": "qt.qt6.620.addons.qtlottie, qt.qt6.620.wasm_32", 57 | "Dependencies": "qt.qt6.620.wasm_32", 58 | "Virtual": "true", 59 | "Script": "installscript.qs", 60 | "SortingPriority": null, 61 | "DownloadableArchives": "qtlottie-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 62 | "CompressedSize": "3.6M", 63 | "UncompressedSize": "22.1M", 64 | "SHA1": "0b4b80930f2373679f77b9a93d7908e59e048fbd" 65 | }, 66 | "qt.qt6.620.addons.qtmultimedia.wasm_32": { 67 | "Name": "qt.qt6.620.addons.qtmultimedia.wasm_32", 68 | "DisplayName": "Qt Multimedia for WebAssembly", 69 | "Description": null, 70 | "Version": "6.2.0-0-202109261634", 71 | "ReleaseDate": "2021-09-26", 72 | "AutoDependOn": "qt.qt6.620.addons.qtmultimedia, qt.qt6.620.wasm_32", 73 | "Dependencies": "qt.qt6.620.wasm_32", 74 | "Virtual": "true", 75 | "Script": "installscript.qs", 76 | "SortingPriority": null, 77 | "DownloadableArchives": "qtmultimedia-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 78 | "CompressedSize": "5.6M", 79 | "UncompressedSize": "33.6M", 80 | "SHA1": "a980629f6c125b770edc64f303baddd28d98bf01" 81 | }, 82 | "qt.qt6.620.addons.qtscxml.wasm_32": { 83 | "Name": "qt.qt6.620.addons.qtscxml.wasm_32", 84 | "DisplayName": "Qt State Machines for WebAssembly", 85 | "Description": null, 86 | "Version": "6.2.0-0-202109261634", 87 | "ReleaseDate": "2021-09-26", 88 | "AutoDependOn": "qt.qt6.620.addons.qtscxml, qt.qt6.620.wasm_32", 89 | "Dependencies": "qt.qt6.620.wasm_32", 90 | "Virtual": "true", 91 | "Script": "installscript.qs", 92 | "SortingPriority": null, 93 | "DownloadableArchives": "qtscxml-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 94 | "CompressedSize": "6.6M", 95 | "UncompressedSize": "39.2M", 96 | "SHA1": "05496f08fb487ee0ee261e6df11b18372de08aca" 97 | }, 98 | "qt.qt6.620.addons.qtvirtualkeyboard.wasm_32": { 99 | "Name": "qt.qt6.620.addons.qtvirtualkeyboard.wasm_32", 100 | "DisplayName": "Qt Virtual Keyboard for WebAssembly", 101 | "Description": null, 102 | "Version": "6.2.0-0-202109261634", 103 | "ReleaseDate": "2021-09-26", 104 | "AutoDependOn": "qt.qt6.620.addons.qtvirtualkeyboard, qt.qt6.620.wasm_32", 105 | "Dependencies": "qt.qt6.620.wasm_32", 106 | "Virtual": "true", 107 | "Script": "installscript.qs", 108 | "SortingPriority": null, 109 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 110 | "CompressedSize": "8.3M", 111 | "UncompressedSize": "45.4M", 112 | "SHA1": "9c2ac673df175ea456d00b880b599ba6435cb01c" 113 | }, 114 | "qt.qt6.620.addons.qtwebchannel.wasm_32": { 115 | "Name": "qt.qt6.620.addons.qtwebchannel.wasm_32", 116 | "DisplayName": "Qt WebChannel for WebAssembly", 117 | "Description": null, 118 | "Version": "6.2.0-0-202109261634", 119 | "ReleaseDate": "2021-09-26", 120 | "AutoDependOn": "qt.qt6.620.addons.qtwebchannel, qt.qt6.620.wasm_32", 121 | "Dependencies": "qt.qt6.620.wasm_32", 122 | "Virtual": "true", 123 | "Script": "installscript.qs", 124 | "SortingPriority": null, 125 | "DownloadableArchives": "qtwebchannel-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 126 | "CompressedSize": "1.2M", 127 | "UncompressedSize": "6.5M", 128 | "SHA1": "b783461b25d7b41cd5eb099a450de4680267af5a" 129 | }, 130 | "qt.qt6.620.addons.qtwebsockets.wasm_32": { 131 | "Name": "qt.qt6.620.addons.qtwebsockets.wasm_32", 132 | "DisplayName": "Qt WebSockets for WebAssembly", 133 | "Description": null, 134 | "Version": "6.2.0-0-202109261634", 135 | "ReleaseDate": "2021-09-26", 136 | "AutoDependOn": "qt.qt6.620.addons.qtwebsockets, qt.qt6.620.wasm_32", 137 | "Dependencies": "qt.qt6.620.wasm_32", 138 | "Virtual": "true", 139 | "Script": "installscript.qs", 140 | "SortingPriority": null, 141 | "DownloadableArchives": "qtwebsockets-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 142 | "CompressedSize": "1.5M", 143 | "UncompressedSize": "8.5M", 144 | "SHA1": "cb676c41bdea73393fa1fdc72b264be37b60fb49" 145 | }, 146 | "qt.qt6.620.qt5compat.wasm_32": { 147 | "Name": "qt.qt6.620.qt5compat.wasm_32", 148 | "DisplayName": "Qt 5 Compatibility Module for WebAssembly", 149 | "Description": null, 150 | "Version": "6.2.0-0-202109261634", 151 | "ReleaseDate": "2021-09-26", 152 | "AutoDependOn": "qt.qt6.620.qt5compat, qt.qt6.620.wasm_32", 153 | "Dependencies": "qt.qt6.620.wasm_32", 154 | "Virtual": "true", 155 | "Script": "installscript.qs", 156 | "SortingPriority": null, 157 | "DownloadableArchives": "qt5compat-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 158 | "CompressedSize": "3.1M", 159 | "UncompressedSize": "20.6M", 160 | "SHA1": "cb0993c6cf8b395c732a78261fed127ec09c8f7e" 161 | }, 162 | "qt.qt6.620.qtquick3d.wasm_32": { 163 | "Name": "qt.qt6.620.qtquick3d.wasm_32", 164 | "DisplayName": "Qt Quick 3D for WebAssembly", 165 | "Description": null, 166 | "Version": "6.2.0-0-202109261634", 167 | "ReleaseDate": "2021-09-26", 168 | "AutoDependOn": "qt.qt6.620.qtquick3d, qt.qt6.620.wasm_32", 169 | "Dependencies": "qt.qt6.620.wasm_32", 170 | "Virtual": "true", 171 | "Script": "installscript.qs", 172 | "SortingPriority": null, 173 | "DownloadableArchives": "qtquick3d-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 174 | "CompressedSize": "33.5M", 175 | "UncompressedSize": "204.3M", 176 | "SHA1": "9128329fbba53b50bf8919f6cc556309d29838f7" 177 | }, 178 | "qt.qt6.620.qtquicktimeline.wasm_32": { 179 | "Name": "qt.qt6.620.qtquicktimeline.wasm_32", 180 | "DisplayName": "Qt Quick Timeline for WebAssembly", 181 | "Description": null, 182 | "Version": "6.2.0-0-202109261634", 183 | "ReleaseDate": "2021-09-26", 184 | "AutoDependOn": "qt.qt6.620.qtquicktimeline, qt.qt6.620.wasm_32", 185 | "Dependencies": "qt.qt6.620.wasm_32", 186 | "Virtual": "true", 187 | "Script": "installscript.qs", 188 | "SortingPriority": null, 189 | "DownloadableArchives": "qtquicktimeline-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 190 | "CompressedSize": "873.6K", 191 | "UncompressedSize": "4.4M", 192 | "SHA1": "333d79e89116fea3ccfe83d043307e2e334517e0" 193 | }, 194 | "qt.qt6.620.qtshadertools.wasm_32": { 195 | "Name": "qt.qt6.620.qtshadertools.wasm_32", 196 | "DisplayName": "Qt Shader Tools for WebAssembly", 197 | "Description": null, 198 | "Version": "6.2.0-0-202109261634", 199 | "ReleaseDate": "2021-09-26", 200 | "AutoDependOn": "qt.qt6.620.qtshadertools, qt.qt6.620.wasm_32", 201 | "Dependencies": "qt.qt6.620.wasm_32", 202 | "Virtual": "true", 203 | "Script": "installscript.qs", 204 | "SortingPriority": null, 205 | "DownloadableArchives": "qtshadertools-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 206 | "CompressedSize": "12.7M", 207 | "UncompressedSize": "84.7M", 208 | "SHA1": "8c09fa9caef80f5a8a571939b90148c04d12e873" 209 | }, 210 | "qt.qt6.620.wasm_32": { 211 | "Name": "qt.qt6.620.wasm_32", 212 | "DisplayName": "WebAssembly (TP)", 213 | "Description": "Qt 6.2.0 Prebuilt Components for WebAssembly (Desktop).

The release of WebAssembly with Qt 6.2 is a Technology Preview.", 214 | "Version": "6.2.0-0-202109261634", 215 | "ReleaseDate": "2021-09-26", 216 | "Dependencies": null, 217 | "AutoDependOn": null, 218 | "Default": "false", 219 | "Script": "installscript.qs", 220 | "SortingPriority": "700", 221 | "DownloadableArchives": "qtbase-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z, qtdeclarative-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z, qtsvg-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z, qttools-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z, qttranslations-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z", 222 | "CompressedSize": "269.3M", 223 | "UncompressedSize": "1.7G", 224 | "SHA1": "0c8123dfed868c04080efaf73cae1955fad05bb0", 225 | "ArchiveSizes": { 226 | "qttranslations-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z": "1.6M", 227 | "qttools-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z": "2.3M", 228 | "qtsvg-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z": "2.8M", 229 | "qtdeclarative-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z": "146M", 230 | "qtbase-Windows-Windows_10-Clang-Windows-WebAssembly-X86_64.7z": "117M" 231 | } 232 | } 233 | } -------------------------------------------------------------------------------- /src/State.test.ts: -------------------------------------------------------------------------------- 1 | import { makeState, State, StateReducer, StateUtils, ToolData } from "./State"; 2 | import { 3 | Host, 4 | hostFromStr, 5 | hostToStr, 6 | RawPackageUpdates, 7 | Target, 8 | targetFromStr, 9 | } from "./lib/types"; 10 | import win_620_json from "./aqt-list-qt-ts/test_data/windows-620-update.json"; 11 | import tools_vcredist from "./aqt-list-qt-ts/test_data/windows-desktop-tools_vcredist-update.json"; 12 | import tools_vcredist_expect from "./aqt-list-qt-ts/test_data/windows-desktop-tools_vcredist-expect.json"; 13 | import official_rel from "./aqt-list-qt-ts/test_data/official_releases.json"; 14 | import { 15 | to_archives, 16 | to_modules, 17 | to_tool_variants, 18 | } from "./aqt-list-qt-ts/list-qt-impl"; 19 | import { SemVer } from "semver"; 20 | 21 | const _makeState = (host: keyof typeof Host, target: keyof typeof Target) => 22 | makeState(unifiedInstallers, hostFromStr(host), targetFromStr(target)); 23 | 24 | describe("makeState", () => { 25 | it.each` 26 | host | target 27 | ${"windows"} | ${"desktop"} 28 | ${"mac"} | ${"ios"} 29 | ${"linux"} | ${"android"} 30 | `( 31 | "should make a new State with $host $target", 32 | ({ 33 | host, 34 | target, 35 | }: { 36 | host: "windows" | "mac" | "linux"; 37 | target: "desktop" | "android" | "ios" | "winrt"; 38 | }) => { 39 | const state = _makeState(host, target); 40 | expect(state.host.selected.value).toEqual(host); 41 | expect(state.target.selected.value).toEqual(target); 42 | expect(state.version.selected.state.isLoading()).toEqual(true); 43 | } 44 | ); 45 | }); 46 | 47 | const versions = [["6.1.0", "6.1.1", "6.1.2"], ["6.2.0"]]; 48 | const version = "6.2.0"; 49 | const arches = ["win64_mingw81", "win64_msvc2019_64", "win64_msvc2019_arm64"]; 50 | const arch = "win64_mingw81"; 51 | const tools = ["qtcreator", "qtifw", "tools_vcredist"]; 52 | 53 | const win620JsonRaw = win_620_json as unknown as RawPackageUpdates; 54 | const modules = to_modules(win620JsonRaw, [new SemVer(version), arch]); 55 | const archives = to_archives(win620JsonRaw, [new SemVer(version), arch, []]); 56 | const vcredist = to_tool_variants( 57 | tools_vcredist as unknown as RawPackageUpdates 58 | ); 59 | 60 | const pipe = 61 | (funcs: StateReducer[]): StateReducer => 62 | (state: State): State => 63 | funcs.reduce((accum: State, func: StateReducer) => func(accum), state); 64 | 65 | const apply = (state: State, funcs: StateReducer[]) => pipe(funcs)(state); 66 | 67 | const state2modules = (state: State) => 68 | Array.from(state.modules.selections.values()).map((v) => v.pkg); 69 | const state2archives = (state: State) => 70 | new Map( 71 | Array.from(state.archives.selections.values()).map((v) => [v.name, v.size]) 72 | ); 73 | 74 | const makeLoadedState = () => 75 | apply(_makeState("windows", "desktop"), [ 76 | StateUtils.withInstallersVersionsToolsLoaded( 77 | unifiedInstallers, 78 | versions, 79 | tools 80 | ), 81 | StateUtils.withVersionLoadingArches(version), 82 | StateUtils.withArchesLoaded(arches), 83 | StateUtils.withArchLoadingModulesArchives(arch), 84 | StateUtils.withModulesArchivesLoaded(modules, archives), 85 | ]); 86 | 87 | describe("withVersionsToolsLoaded", () => { 88 | it("adds versions and tools to state", () => { 89 | const state = apply(_makeState("windows", "desktop"), [ 90 | StateUtils.withInstallersVersionsToolsLoaded( 91 | unifiedInstallers, 92 | versions, 93 | tools 94 | ), 95 | ]); 96 | 97 | expect(state.version.versions).toEqual(versions); 98 | expect(state.version.selected.state.hasSelection()).toEqual(false); 99 | expect(state.toolNames.options).toEqual(tools); 100 | }); 101 | }); 102 | 103 | describe("withArchesLoaded", () => { 104 | it("adds architectures", () => { 105 | const state = apply(_makeState("windows", "desktop"), [ 106 | StateUtils.withInstallersVersionsToolsLoaded( 107 | unifiedInstallers, 108 | versions, 109 | tools 110 | ), 111 | StateUtils.withVersionLoadingArches(version), 112 | StateUtils.withArchesLoaded(arches), 113 | ]); 114 | 115 | expect(state.version.selected.value).toEqual(version); 116 | expect(state.arch.options).toEqual(arches); 117 | expect(state.arch.selected.state.hasSelection()).toEqual(false); 118 | }); 119 | }); 120 | 121 | describe("withModulesArchivesLoaded", () => { 122 | it("adds modules and archives", () => { 123 | const state = makeLoadedState(); 124 | 125 | const actual = state2modules(state); 126 | expect(actual).toEqual(modules); 127 | expect(state.modules.hasAllOff()).toEqual(true); 128 | expect(state.modules.state.isNotLoaded()).toEqual(false); 129 | expect(state.modules.state.hasSelection()).toEqual(false); 130 | }); 131 | }); 132 | 133 | describe("withToggledModules", () => { 134 | it("selects all modules", () => { 135 | const state = StateUtils.withToggledModules(true)(makeLoadedState()); 136 | 137 | const allModules = state2modules(state); 138 | expect(allModules).toEqual(modules); 139 | expect(state.modules.hasAllOff()).toEqual(false); 140 | expect(state.modules.hasAllOn()).toEqual(true); 141 | }); 142 | it("deselects all modules", () => { 143 | const state = apply(makeLoadedState(), [ 144 | StateUtils.withToggledModules(true), 145 | StateUtils.withToggledModules(false), 146 | ]); 147 | 148 | const allModules = state2modules(state); 149 | expect(allModules).toEqual(modules); 150 | expect(state.modules.hasAllOff()).toEqual(true); 151 | expect(state.modules.hasAllOn()).toEqual(false); 152 | }); 153 | }); 154 | 155 | describe("withToggledArchives", () => { 156 | it("turns off all archives", () => { 157 | const state = StateUtils.withToggledArchives(false)(makeLoadedState()); 158 | 159 | const allArchives = state2archives(state); 160 | expect(allArchives).toEqual(archives); 161 | expect(state.archives.hasAllOff()).toEqual(true); 162 | expect(state.archives.hasAllOn()).toEqual(false); 163 | }); 164 | it("reselects all archives", () => { 165 | const state = apply(makeLoadedState(), [ 166 | StateUtils.withToggledArchives(false), 167 | StateUtils.withToggledArchives(true), 168 | ]); 169 | 170 | const allArchives = state2archives(state); 171 | expect(allArchives).toEqual(archives); 172 | expect(state.archives.hasAllOff()).toEqual(false); 173 | expect(state.archives.hasAllOn()).toEqual(true); 174 | }); 175 | }); 176 | 177 | describe("withArchiveSet", () => { 178 | it("deselects one archive", () => { 179 | const archiveName = "qtdeclarative"; 180 | const state = StateUtils.withArchiveSet( 181 | archiveName, 182 | false 183 | )(makeLoadedState()); 184 | 185 | const actual = state2archives(state); 186 | expect(actual).toEqual(archives); 187 | expect(state.archives.hasAllOff()).toEqual(false); 188 | expect(state.archives.hasAllOn()).toEqual(false); 189 | expect(state.archives.state.isNotLoaded()).toEqual(false); 190 | expect(state.archives.state.hasSelection()).toEqual(true); 191 | expect(state.archives.selections.get(archiveName)?.selected).toEqual(false); 192 | expect(state.archives.selections.get("qtbase")?.selected).toEqual(true); 193 | }); 194 | }); 195 | 196 | describe("withModuleSet", () => { 197 | it("selects one module", () => { 198 | const moduleName = "qt.qt6.620.addons.qtcharts.win64_mingw81"; 199 | const state = StateUtils.withModuleSet(moduleName, true)(makeLoadedState()); 200 | 201 | const actual = state2modules(state); 202 | expect(actual).toEqual(modules); 203 | expect(state.modules.hasAllOff()).toEqual(false); 204 | expect(state.modules.hasAllOn()).toEqual(false); 205 | expect(state.modules.state.isNotLoaded()).toEqual(false); 206 | expect(state.modules.state.hasSelection()).toEqual(true); 207 | expect(state.modules.selections.get(moduleName)?.selected).toEqual(true); 208 | }); 209 | }); 210 | 211 | // TODO: figure out how to mock out config.json with different file contents! 212 | describe("toInstallQtAction", () => { 213 | describe("with no qt or tools selected", () => { 214 | it("should display valid yml", () => { 215 | const state = _makeState("windows", "desktop"); 216 | expect(state.toInstallQtAction()).toEqual( 217 | "Please select a Qt version or a tool." 218 | ); 219 | }); 220 | }); 221 | describe("with qt but no tools selected", () => { 222 | it("should display valid yml", () => { 223 | const state = makeLoadedState(); 224 | expect(state.toInstallQtAction()).toEqual(` - name: Install Qt 225 | uses: jurplel/install-qt-action@v3 226 | with: 227 | aqtversion: '==3.1.*' 228 | version: '6.2.0' 229 | host: 'windows' 230 | target: 'desktop' 231 | arch: 'win64_mingw81'`); 232 | }); 233 | }); 234 | describe("with tools but no qt selected", () => { 235 | it("should display valid yml", () => { 236 | const state = apply(_makeState("windows", "desktop"), [ 237 | StateUtils.withInstallersVersionsToolsLoaded( 238 | unifiedInstallers, 239 | versions, 240 | ["tools_vcredist"] 241 | ), 242 | StateUtils.withNewTool( 243 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 244 | ), 245 | StateUtils.withToggledToolVariants("tools_vcredist", true), 246 | ]); 247 | expect(state.toInstallQtAction()).toEqual(` - name: Install Qt 248 | uses: jurplel/install-qt-action@v3 249 | with: 250 | aqtversion: '==3.1.*' 251 | host: 'windows' 252 | target: 'desktop' 253 | toolsOnly: 'true' 254 | tools: 'tools_vcredist'`); 255 | }); 256 | it("should properly select one tool", () => { 257 | const state = apply(_makeState("windows", "desktop"), [ 258 | StateUtils.withInstallersVersionsToolsLoaded( 259 | unifiedInstallers, 260 | versions, 261 | ["tools_vcredist"] 262 | ), 263 | StateUtils.withNewTool( 264 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 265 | ), 266 | StateUtils.withToolVariant( 267 | "tools_vcredist", 268 | "qt.tools.vcredist_msvc2019_x86", 269 | true 270 | ), 271 | ]); 272 | expect(state.toInstallQtAction()).toEqual(` - name: Install Qt 273 | uses: jurplel/install-qt-action@v3 274 | with: 275 | aqtversion: '==3.1.*' 276 | host: 'windows' 277 | target: 'desktop' 278 | toolsOnly: 'true' 279 | tools: 'tools_vcredist,qt.tools.vcredist_msvc2019_x86'`); 280 | }); 281 | }); 282 | describe("with both qt and tools selected", () => { 283 | it("should display valid yml", () => { 284 | const state = apply(makeLoadedState(), [ 285 | StateUtils.withNewTool( 286 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 287 | ), 288 | StateUtils.withToggledToolVariants("tools_vcredist", true), 289 | ]); 290 | expect(state.toInstallQtAction()).toEqual(` - name: Install Qt 291 | uses: jurplel/install-qt-action@v3 292 | with: 293 | aqtversion: '==3.1.*' 294 | version: '6.2.0' 295 | host: 'windows' 296 | target: 'desktop' 297 | arch: 'win64_mingw81' 298 | tools: 'tools_vcredist'`); 299 | }); 300 | }); 301 | }); 302 | 303 | const unifiedInstallers = (host: Host) => { 304 | const installers = official_rel["online_installers/"]; 305 | return ( 306 | Object.entries(installers) 307 | ?.map(([key, _]) => key) 308 | ?.find((key) => key.includes(hostToStr(host))) || "" 309 | ); 310 | }; 311 | 312 | const officialQtUnifiedPreamble = (host: Host) => { 313 | const installer = unifiedInstallers(host); 314 | if (host == Host.windows) { 315 | return `Invoke-WebRequest \` 316 | -OutFile 'qt-unified-windows-x64-online.exe' \` 317 | 'https://download.qt.io/official_releases/online_installers/qt-unified-windows-x64-online.exe' 318 | .\\qt-unified-windows-x64-online.exe \` 319 | --accept-licenses \` 320 | --default-answer \` 321 | --confirm-command install \` 322 | `; 323 | } 324 | const chmod_line = `chmod u+x ${installer} && \\\n`; 325 | return `curl -L -O https://download.qt.io/official_releases/online_installers/${installer} && \\ 326 | chmod u+x ${installer} 327 | ./${installer} \\ 328 | --accept-licenses \\ 329 | --default-answer \\ 330 | --confirm-command install \\ 331 | `; 332 | }; 333 | 334 | describe("isWindows", () => { 335 | it.each` 336 | host | isWindows 337 | ${"windows"} | ${true} 338 | ${"mac"} | ${false} 339 | ${"linux"} | ${false} 340 | `( 341 | "on $host, isWindows() should return $isWindows", 342 | ({ 343 | host, 344 | isWindows, 345 | }: { 346 | host: "windows" | "mac" | "linux"; 347 | isWindows: boolean; 348 | }) => { 349 | const state = _makeState(host, "desktop"); 350 | expect(state.host.selected.value).toEqual(host); 351 | expect(state.isWindows()).toEqual(isWindows); 352 | } 353 | ); 354 | }); 355 | 356 | describe("toOfficialInstallCmd", () => { 357 | describe("with no qt or tools selected", () => { 358 | it("should display valid yml", () => { 359 | const state = makeState( 360 | unifiedInstallers, 361 | hostFromStr("windows"), 362 | targetFromStr("desktop") 363 | ); 364 | expect(state.toOfficialInstallCmd()).toEqual( 365 | "Please select a Qt version or a tool." 366 | ); 367 | }); 368 | }); 369 | describe("with qt but no tools selected", () => { 370 | it("should display valid commands", () => { 371 | const state = makeLoadedState(); 372 | const pre = officialQtUnifiedPreamble(Host.windows); 373 | expect(state.toOfficialInstallCmd()).toEqual( 374 | pre + "qt.qt6.620.win64_mingw81" 375 | ); 376 | }); 377 | it("should add modules", () => { 378 | const selected_modules = [ 379 | "qt.qt6.620.addons.qtcharts.win64_mingw81", 380 | "qt.qt6.620.qtquicktimeline.win64_mingw81", 381 | ]; 382 | const state = apply( 383 | makeLoadedState(), 384 | selected_modules.map((mod) => StateUtils.withModuleSet(mod, true)) 385 | ); 386 | expect(state.toOfficialInstallCmd()).toEqual( 387 | officialQtUnifiedPreamble(Host.windows) + 388 | `qt.qt6.620.win64_mingw81 \` 389 | qt.qt6.620.addons.qtcharts.win64_mingw81 \` 390 | qt.qt6.620.qtquicktimeline.win64_mingw81` 391 | ); 392 | }); 393 | }); 394 | 395 | describe("with tools but no qt selected", () => { 396 | it("should display command that installs all tools in group", () => { 397 | const state = apply(_makeState("windows", "desktop"), [ 398 | StateUtils.withInstallersVersionsToolsLoaded( 399 | unifiedInstallers, 400 | versions, 401 | ["tools_vcredist"] 402 | ), 403 | StateUtils.withNewTool( 404 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 405 | ), 406 | StateUtils.withToggledToolVariants("tools_vcredist", true), 407 | ]); 408 | expect(state.toOfficialInstallCmd()).toEqual( 409 | officialQtUnifiedPreamble(Host.windows) + 410 | tools_vcredist_expect.modules.sort().join(" `\n ") 411 | ); 412 | }); 413 | it("should properly select one tool", () => { 414 | const variant = "qt.tools.vcredist_msvc2019_x86"; 415 | const state = apply(_makeState("windows", "desktop"), [ 416 | StateUtils.withInstallersVersionsToolsLoaded( 417 | unifiedInstallers, 418 | versions, 419 | ["tools_vcredist"] 420 | ), 421 | StateUtils.withNewTool( 422 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 423 | ), 424 | StateUtils.withToolVariant("tools_vcredist", variant, true), 425 | ]); 426 | expect(state.toOfficialInstallCmd()).toEqual( 427 | officialQtUnifiedPreamble(Host.windows) + variant 428 | ); 429 | }); 430 | }); 431 | describe("with both qt and tools selected", () => { 432 | it("should display command that installs qt, modules, and all tools in group", () => { 433 | const selected_modules = [ 434 | "qt.qt6.620.addons.qtcharts.win64_mingw81", 435 | "qt.qt6.620.qtquicktimeline.win64_mingw81", 436 | ]; 437 | const state = apply(makeLoadedState(), [ 438 | ...selected_modules.map((mod) => StateUtils.withModuleSet(mod, true)), 439 | StateUtils.withNewTool( 440 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 441 | ), 442 | StateUtils.withToggledToolVariants("tools_vcredist", true), 443 | ]); 444 | expect(state.toOfficialInstallCmd()).toEqual( 445 | officialQtUnifiedPreamble(Host.windows) + 446 | `qt.qt6.620.win64_mingw81 \` 447 | qt.qt6.620.addons.qtcharts.win64_mingw81 \` 448 | qt.qt6.620.qtquicktimeline.win64_mingw81 \` 449 | ${tools_vcredist_expect.modules.sort().join(" `\n ")}` 450 | ); 451 | }); 452 | it("should display command that installs qt, modules, and one tool in group", () => { 453 | const variant = "qt.tools.vcredist_msvc2019_x86"; 454 | const selected_modules = [ 455 | "qt.qt6.620.addons.qtcharts.win64_mingw81", 456 | "qt.qt6.620.qtquicktimeline.win64_mingw81", 457 | ]; 458 | const state = apply(_makeState("mac", "desktop"), [ 459 | StateUtils.withInstallersVersionsToolsLoaded( 460 | unifiedInstallers, 461 | versions, 462 | ["tools_vcredist"] 463 | ), 464 | StateUtils.withVersionLoadingArches(version), 465 | StateUtils.withArchesLoaded(arches), 466 | StateUtils.withArchLoadingModulesArchives(arch), 467 | StateUtils.withModulesArchivesLoaded(modules, archives), 468 | ...selected_modules.map((mod) => StateUtils.withModuleSet(mod, true)), 469 | StateUtils.withNewTool( 470 | ToolData.fromPackageUpdates("tools_vcredist", vcredist) 471 | ), 472 | StateUtils.withToolVariant("tools_vcredist", variant, true), 473 | ]); 474 | expect(state.toOfficialInstallCmd()).toEqual( 475 | officialQtUnifiedPreamble(Host.mac) + 476 | `qt.qt6.620.win64_mingw81 \\ 477 | qt.qt6.620.addons.qtcharts.win64_mingw81 \\ 478 | qt.qt6.620.qtquicktimeline.win64_mingw81 \\ 479 | ${variant}` 480 | ); 481 | }); 482 | }); 483 | }); 484 | -------------------------------------------------------------------------------- /src/State.ts: -------------------------------------------------------------------------------- 1 | // import _ from 'lodash'; 2 | 3 | import { get_host_target_targets, hosts } from "./lib/utils"; 4 | import _ from "lodash"; 5 | import { 6 | Host, 7 | hostFromStr, 8 | HostString, 9 | hostToStr, 10 | PackageUpdate, 11 | SelectableElement, 12 | seModuleInstallName, 13 | seToolInstallName, 14 | Target, 15 | targetFromStr, 16 | TargetString, 17 | targetToStr, 18 | UnifiedInstallers, 19 | } from "./lib/types"; 20 | import Config from "./config.json"; 21 | import { version_nodot } from "./aqt-list-qt-ts/list-qt-impl"; 22 | import { SemVer } from "semver"; 23 | 24 | export const enum SelectValue { 25 | NotLoaded, 26 | Loading, 27 | Loaded, 28 | Selected, 29 | } 30 | 31 | export class SelectState { 32 | constructor(private state: SelectValue) {} 33 | 34 | hasSelection(): boolean { 35 | return this.state === SelectValue.Selected; 36 | } 37 | 38 | isLoading(): boolean { 39 | return this.state === SelectValue.Loading; 40 | } 41 | 42 | isNotLoaded(): boolean { 43 | return this.isLoading() || this.state === SelectValue.NotLoaded; 44 | } 45 | 46 | copy(): SelectState { 47 | return new SelectState(this.state); 48 | } 49 | } 50 | 51 | export const NO_SELECTION = "---"; 52 | 53 | class Selection { 54 | public state: SelectState; // = SelectState.NotLoaded; 55 | public value: string; // = NO_SELECTION; 56 | 57 | constructor(valueOrState: string | SelectValue, state?: SelectValue) { 58 | if (typeof valueOrState === "string") { 59 | this.value = valueOrState; 60 | this.state = new SelectState( 61 | state !== undefined 62 | ? state 63 | : valueOrState === NO_SELECTION 64 | ? SelectValue.Loaded 65 | : SelectValue.Selected 66 | ); 67 | } else { 68 | // it's a SelectState 69 | if (valueOrState === undefined) 70 | throw new Error("Misuse of Selection constructor"); 71 | this.state = new SelectState(valueOrState as SelectValue); 72 | this.value = NO_SELECTION; 73 | } 74 | } 75 | } 76 | 77 | export class SelectOne { 78 | constructor( 79 | public selected: Selection, 80 | public options: Readonly = [], 81 | public allowEmpty: boolean = true 82 | ) {} 83 | 84 | copy(): SelectOne { 85 | return this.copyWithOption(this.selected.value); 86 | } 87 | 88 | copyWithOption(option: string): SelectOne { 89 | console.assert( 90 | this.options.length > 0, 91 | "There's no need to copy a SelectOne that contains no selections" 92 | ); 93 | const selected = new Selection( 94 | option, 95 | this.options.includes(option) ? SelectValue.Selected : SelectValue.Loaded 96 | ); 97 | return new SelectOne(selected, [...this.options], this.allowEmpty); 98 | } 99 | } 100 | 101 | export class SelectNone extends SelectOne { 102 | constructor(value: SelectValue, options: string[] = []) { 103 | const state = value === SelectValue.Selected ? SelectValue.Loaded : value; 104 | super(new Selection(state), options); 105 | } 106 | } 107 | 108 | export const contains = (haystack: Array>, needle: T): boolean => 109 | haystack.reduce( 110 | (accum: boolean, row: Array) => accum || row.includes(needle), 111 | false 112 | ); 113 | 114 | export class Versions { 115 | public allowEmpty = true; 116 | 117 | constructor( 118 | public selected: Selection, 119 | public versions: Array> 120 | ) {} 121 | 122 | copy(): Versions { 123 | return this.copyWithOption(this.selected.value); 124 | } 125 | 126 | copyWithOption(option: string): Versions { 127 | console.assert( 128 | this.versions.length > 0, 129 | "There's no need to copy a Versions that contains no selections" 130 | ); 131 | const selected = new Selection( 132 | option, 133 | contains(this.versions, option) 134 | ? SelectValue.Selected 135 | : SelectValue.Loaded 136 | ); 137 | return new Versions( 138 | selected, 139 | this.versions.map((row: Array) => [...row]) 140 | ); 141 | } 142 | } 143 | 144 | export class SelectMany { 145 | constructor( 146 | public state: SelectState = new SelectState(SelectValue.NotLoaded), 147 | public selections: Map = new Map() 148 | ) {} 149 | 150 | hasSelections(): boolean { 151 | return ( 152 | [...this.selections.values()].findIndex( 153 | (el: SelectableElement) => el.selected 154 | ) >= 0 155 | ); 156 | } 157 | 158 | hasAllOn(): boolean { 159 | return ( 160 | !this.isEmpty() && 161 | [...this.selections.values()].every( 162 | (el: SelectableElement) => el.selected 163 | ) 164 | ); 165 | } 166 | 167 | hasAllOff(): boolean { 168 | return ( 169 | !this.isEmpty() && 170 | [...this.selections.values()].every( 171 | (el: SelectableElement) => !el.selected 172 | ) 173 | ); 174 | } 175 | 176 | isLoading(): boolean { 177 | return this.state.isLoading(); 178 | } 179 | 180 | isEmpty(): boolean { 181 | return this.selections.size === 0; 182 | } 183 | 184 | optionsTurnedOn(): Array { 185 | return [...this.selections.entries()] 186 | .filter(([, el]) => el.selected) 187 | .map(([name, el]) => seModuleInstallName(el) || name); 188 | } 189 | 190 | optionKeysTurnedOn(): Array { 191 | return [...this.selections.entries()] 192 | .filter(([, el]) => el.selected) 193 | .map(([key, _]) => key); 194 | } 195 | 196 | copy(): SelectMany { 197 | return new SelectMany(this.state.copy(), new Map(this.selections)); 198 | } 199 | 200 | copyWithOptionSet(selectedOption: string, on: boolean): SelectMany { 201 | console.assert(this.selections.has(selectedOption)); 202 | const m = new Map(this.selections); 203 | const { pkg, name, size } = this.selections.get( 204 | selectedOption 205 | ) as SelectableElement; 206 | m.set(selectedOption, { pkg: pkg, size: size, name: name, selected: on }); 207 | return new SelectMany(new SelectState(SelectValue.Selected), m); 208 | } 209 | 210 | copyWithAllOptions(allOn: boolean): SelectMany { 211 | const packages = Array.from(this.selections.values()) 212 | .map((v) => v.pkg) 213 | .filter((pkg) => pkg !== null) as PackageUpdate[]; 214 | const archives = new Map( 215 | Array.from(this.selections, ([key, value]) => [key, value.size || "???"]) 216 | ); 217 | 218 | return makeSelectMany(packages.length > 0 ? packages : archives, allOn); 219 | } 220 | } 221 | 222 | const makeSelectMany = ( 223 | options: string[] | PackageUpdate[] | Map, 224 | allOn: boolean 225 | ): SelectMany => { 226 | if (options instanceof Map) { 227 | const m = [...options.entries()].map( 228 | ([option, size]): [string, SelectableElement] => [ 229 | option, 230 | { 231 | pkg: null, 232 | size, 233 | name: option, 234 | selected: allOn, 235 | }, 236 | ] 237 | ); 238 | return new SelectMany(new SelectState(SelectValue.Loaded), new Map(m)); 239 | } else { 240 | const m = options.map( 241 | ( 242 | option: string | PackageUpdate | Map 243 | ): [string, SelectableElement] => { 244 | const name = 245 | typeof option === "string" ? option : (option as PackageUpdate).Name; 246 | const pkg = 247 | typeof option === "string" ? null : (option as PackageUpdate); 248 | return [ 249 | name, 250 | { 251 | pkg, 252 | size: null, 253 | name, 254 | selected: allOn, 255 | }, 256 | ]; 257 | } 258 | ); 259 | return new SelectMany(new SelectState(SelectValue.Loaded), new Map(m)); 260 | } 261 | }; 262 | 263 | export class ToolData { 264 | constructor( 265 | public name: string, 266 | public isLoading: boolean, 267 | public variants: Map 268 | ) {} 269 | 270 | copy(): ToolData { 271 | return this._copy((k: string, selected: boolean) => selected); 272 | } 273 | copyWithVariantSet(variant: string, on: boolean): ToolData { 274 | return this._copy((k: string, selected: boolean) => 275 | k === variant ? on : selected 276 | ); 277 | } 278 | copyWithToggledVariants(on: boolean): ToolData { 279 | return this._copy((_k: string, _selected: boolean) => on); 280 | } 281 | _copy( 282 | shouldSelect: (variantName: string, existingSelected: boolean) => boolean 283 | ): ToolData { 284 | const variants = new Map(); 285 | this.variants.forEach((value: SelectableElement, variantName: string) => 286 | variants.set(variantName, { 287 | ...value, 288 | selected: shouldSelect(variantName, value.selected), 289 | }) 290 | ); 291 | return new ToolData(this.name, this.isLoading, variants); 292 | } 293 | hasSelectedVariants(): boolean { 294 | return ( 295 | [...this.variants.values()].findIndex( 296 | (variant: SelectableElement) => variant.selected 297 | ) >= 0 298 | ); 299 | } 300 | 301 | selectedVariants(): string[] { 302 | return [...this.variants.entries()] 303 | .filter(([_, variant]) => variant.selected) 304 | .map(([key, _]) => key); 305 | } 306 | 307 | installCmd(host: string, target: string): string { 308 | if ( 309 | [...this.variants.values()].every( 310 | (variant: SelectableElement) => variant.selected 311 | ) 312 | ) 313 | return `aqt install-tool ${host} ${target} ${this.name}`; 314 | return [...this.variants.values()] 315 | .filter((variant: SelectableElement) => variant.selected) 316 | .map( 317 | (variant: SelectableElement) => 318 | `aqt install-tool ${host} ${target} ${this.name} ${seToolInstallName( 319 | variant 320 | )}` 321 | ) 322 | .join("\n"); 323 | } 324 | variantTuples(actionVersion: number): string { 325 | // For aqt < 2; jurplel/install-qt-action < 3 326 | const action2ToolsTuple = (variant: PackageUpdate): string => 327 | `${this.name},${variant.Version},${variant.Name}`; 328 | // For aqt >= 2; jurplel/install-qt-action >= 3 329 | const action3ToolsTuple = (variant: PackageUpdate): string => 330 | `${this.name},${variant.Name}`; 331 | 332 | if ( 333 | [...this.variants.values()].every( 334 | (variant: SelectableElement) => variant.selected 335 | ) && 336 | actionVersion >= 3 337 | ) 338 | return this.name; 339 | 340 | return [...this.variants.values()] 341 | .filter( 342 | (variant: SelectableElement) => 343 | variant.selected && variant?.pkg !== null 344 | ) 345 | .map((variant: SelectableElement) => 346 | actionVersion >= 3 347 | ? action3ToolsTuple(variant.pkg as PackageUpdate) 348 | : action2ToolsTuple(variant.pkg as PackageUpdate) 349 | ) 350 | .join(" "); 351 | } 352 | public static fromPackageUpdates( 353 | tool_name: string, 354 | pkgUpdates: PackageUpdate[] 355 | ): ToolData { 356 | return new ToolData( 357 | tool_name, 358 | false, 359 | new Map( 360 | pkgUpdates.map((pkgUpdate) => [ 361 | pkgUpdate.Name, 362 | { 363 | pkg: pkgUpdate, 364 | name: pkgUpdate.Name, 365 | selected: false, 366 | } as SelectableElement, 367 | ]) 368 | ) 369 | ); 370 | } 371 | } 372 | 373 | export class ToolSelector { 374 | constructor(public name: string, public toolVariants: SelectMany) {} 375 | 376 | copy(): ToolSelector { 377 | return new ToolSelector(this.name, this.toolVariants.copy()); 378 | } 379 | 380 | copyWithVariantSet(selectedVariant: string, on: boolean): ToolSelector { 381 | return new ToolSelector( 382 | this.name, 383 | this.toolVariants.copyWithOptionSet(selectedVariant, on) 384 | ); 385 | } 386 | } 387 | 388 | export class State { 389 | constructor( 390 | public unifiedInstallers: UnifiedInstallers, 391 | public host: SelectOne, 392 | public target: SelectOne, 393 | public toolNames: SelectNone, // = new SelectNone(SelectValue.NotLoaded), 394 | public selectedTools: Map, // = new Map(), // Map: supports easy removal 395 | public version: Versions, // = new Versions(new Selection(SelectValue.NotLoaded), []), 396 | public arch: SelectOne = new SelectOne( 397 | new Selection(SelectValue.NotLoaded), 398 | [] 399 | ), 400 | public modules: SelectMany = new SelectMany(), 401 | public archives: SelectMany = new SelectMany(), 402 | public installActionVersion: SelectOne = new SelectOne( 403 | new Selection("3"), 404 | ["2", "3"], 405 | false 406 | ) 407 | ) {} 408 | 409 | copy(): State { 410 | return new State( 411 | this.unifiedInstallers, 412 | this.host.copy(), 413 | this.target.copy(), 414 | this.toolNames.copy(), 415 | new Map(this.selectedTools), 416 | this.version.copy(), 417 | this.arch.copy(), 418 | this.modules.copy(), 419 | this.archives.copy(), 420 | this.installActionVersion.copy() 421 | ); 422 | } 423 | hasSelectedTools(): boolean { 424 | return ( 425 | [...this.selectedTools.values()].findIndex((toolData: ToolData) => 426 | toolData.hasSelectedVariants() 427 | ) >= 0 428 | ); 429 | } 430 | hasOutputs(): boolean { 431 | return ( 432 | this.hasSelectedTools() || 433 | (this.version.selected.state.hasSelection() && 434 | this.arch.selected.state.hasSelection()) 435 | ); 436 | } 437 | 438 | values(): { host: Host; target: Target; version: string; arch: string } { 439 | return { 440 | host: hostFromStr(this.host.selected.value as HostString), 441 | target: targetFromStr(this.target.selected.value as TargetString), 442 | version: this.version.selected.value, 443 | arch: this.arch.selected.value, 444 | }; 445 | } 446 | 447 | toAqtInstallCmd(): string { 448 | const { host, target, version, arch } = this.values(); 449 | const toolsLines = 450 | this.selectedTools.size === 0 451 | ? "" 452 | : "\n" + 453 | [...this.selectedTools.values()] 454 | .map((toolData: ToolData) => 455 | toolData.installCmd(hostToStr(host), targetToStr(target)) 456 | ) 457 | .filter((tuple: string) => tuple.length > 0) 458 | .join("\n"); 459 | if ( 460 | toolsLines.trim().length > 0 && 461 | !this.arch.selected.state.hasSelection() 462 | ) { 463 | return toolsLines.trim(); 464 | } else if (!this.version.selected.state.hasSelection()) { 465 | return "Please select a Qt version or a tool."; 466 | } else if (!this.arch.selected.state.hasSelection()) { 467 | return "Please select a Qt architecture or a tool."; 468 | } 469 | if (this.modules.hasAllOff() && this.archives.hasAllOff()) 470 | return "Cannot run `aqt` with no archives and no modules selected."; 471 | const modulesFlag = this.modules.hasAllOn() 472 | ? " -m all" 473 | : this.modules.hasSelections() 474 | ? " -m " + this.modules.optionsTurnedOn().join(" ") 475 | : ""; 476 | const archivesFlag = 477 | this.archives.hasAllOn() || this.archives.isEmpty() 478 | ? "" 479 | : this.archives.hasAllOff() 480 | ? " --noarchives" 481 | : " --archives " + this.archives.optionsTurnedOn().join(" "); 482 | return `aqt install-qt ${hostToStr(host)} ${targetToStr( 483 | target 484 | )} ${version} ${arch}${modulesFlag}${archivesFlag}${toolsLines}`; 485 | } 486 | 487 | toOfficialInstallCmd(): string { 488 | const { host, version, arch } = this.values(); 489 | const multiline_cmd = (lines: string[]) => 490 | lines.join(host === Host.windows ? " `\n " : " \\\n "); 491 | const installer_bin = this.unifiedInstallers(host); 492 | const get_installer_cmd = (() => { 493 | if (host === Host.windows) { 494 | return multiline_cmd([ 495 | "Invoke-WebRequest", 496 | `-OutFile '${installer_bin}'`, 497 | `'https://download.qt.io/official_releases/online_installers/${installer_bin}'`, 498 | ]); 499 | } else { 500 | return multiline_cmd([ 501 | `curl -L -O https://download.qt.io/official_releases/online_installers/${installer_bin} &&`, 502 | `chmod u+x ${installer_bin}`, 503 | ]); 504 | } 505 | })(); 506 | const tools = [...this.selectedTools.values()].flatMap( 507 | (toolData: ToolData) => toolData.selectedVariants() 508 | ); 509 | if (tools.length === 0) { 510 | if (!this.version.selected.state.hasSelection()) { 511 | return "Please select a Qt version or a tool."; 512 | } else if (!this.arch.selected.state.hasSelection()) { 513 | return "Please select a Qt architecture or a tool."; 514 | } 515 | } 516 | const arch_modules = ((): string[] => { 517 | if (!this.version.selected.state.hasSelection()) { 518 | return []; 519 | } 520 | const ver = new SemVer(version); 521 | return [`qt.qt${ver.major}.${version_nodot(ver)}.${arch}`]; 522 | })(); 523 | const modules = [ 524 | ...arch_modules, 525 | ...this.modules.optionKeysTurnedOn(), 526 | ...tools, 527 | ]; 528 | const install_cmd = multiline_cmd([ 529 | `.${host === Host.windows ? "\\" : "/"}${installer_bin}`, 530 | "--accept-licenses", 531 | "--default-answer", 532 | "--confirm-command install", 533 | ...modules, 534 | ]); 535 | return [get_installer_cmd, install_cmd].join("\n"); 536 | } 537 | 538 | toInstallQtAction(): string { 539 | const installQtActionVersion = parseInt( 540 | this.installActionVersion.selected.value 541 | ); 542 | const toolsTuples = [...this.selectedTools.values()] 543 | .map((toolData: ToolData) => 544 | toolData.variantTuples(installQtActionVersion) 545 | ) 546 | .filter((tuple: string) => tuple.length > 0) 547 | .join(" "); 548 | const toolsLine = 549 | toolsTuples.length === 0 ? "" : `\n tools: '${toolsTuples}'`; 550 | const py7zr = Config.REQUIRED_PY7ZR 551 | ? `\n py7zrversion: '${Config.REQUIRED_PY7ZR}'` 552 | : ""; 553 | const postscript = Config.POSTSCRIPT 554 | ? "\n " + Config.POSTSCRIPT 555 | : ""; 556 | if ( 557 | toolsLine.trim().length > 0 && 558 | !this.arch.selected.state.hasSelection() 559 | ) { 560 | return ( 561 | ` - name: Install Qt 562 | uses: jurplel/install-qt-action@v${installQtActionVersion} 563 | with: 564 | aqtversion: '==${Config.RECOMMEND_AQT_VERSION}'${py7zr} 565 | host: '${this.host.selected.value}' 566 | target: '${this.target.selected.value}' 567 | toolsOnly: 'true'` + 568 | toolsLine + 569 | postscript 570 | ); 571 | } else if (!this.version.selected.state.hasSelection()) { 572 | return "Please select a Qt version or a tool."; 573 | } else if (!this.arch.selected.state.hasSelection()) { 574 | return "Please select a Qt architecture or a tool."; 575 | } 576 | const modulesLine = this.modules.hasSelections() 577 | ? `\n modules: '${this.modules.optionsTurnedOn().join(" ")}'` 578 | : ""; 579 | const archivesLine = 580 | !this.archives.hasAllOn() && this.archives.hasSelections() 581 | ? `\n archives: '${this.archives.optionsTurnedOn().join(" ")}'` 582 | : ""; 583 | return ( 584 | ` - name: Install Qt 585 | uses: jurplel/install-qt-action@v${installQtActionVersion} 586 | with: 587 | aqtversion: '==${Config.RECOMMEND_AQT_VERSION}'${py7zr} 588 | version: '${this.version.selected.value}' 589 | host: '${this.host.selected.value}' 590 | target: '${this.target.selected.value}' 591 | arch: '${this.arch.selected.value}'` + 592 | modulesLine + 593 | toolsLine + 594 | archivesLine + 595 | postscript 596 | ); 597 | } 598 | 599 | isWindows() { 600 | return this.host.selected.value === "windows"; 601 | } 602 | } 603 | 604 | export type StateReducer = (state: State) => State; 605 | export const StateUtils = { 606 | withHostLoadingVersionsTools: 607 | (newHost: Host) => 608 | (state: State): State => 609 | makeState( 610 | state.unifiedInstallers, 611 | newHost, 612 | targetFromStr(state.target.selected.value as TargetString) 613 | ), 614 | 615 | withTargetLoadingVersionsTools: 616 | (newTarget: Target) => 617 | (state: State): State => 618 | makeState( 619 | state.unifiedInstallers, 620 | hostFromStr(state.host.selected.value as HostString), 621 | newTarget 622 | ), 623 | 624 | withInstallersVersionsToolsLoaded: ( 625 | unifiedInstallers: UnifiedInstallers, 626 | versions: string[][], 627 | tools: string[] 628 | ): StateReducer => { 629 | const versionsState = 630 | versions.length > 0 ? SelectValue.Loaded : SelectValue.NotLoaded; 631 | const toolsState = 632 | tools.length > 0 ? SelectValue.Loaded : SelectValue.NotLoaded; 633 | return (state: State): State => 634 | new State( 635 | unifiedInstallers, 636 | state.host.copy(), 637 | state.target.copy(), 638 | new SelectNone(toolsState, tools), 639 | new Map(), 640 | new Versions(new Selection(versionsState), versions) 641 | ); 642 | }, 643 | 644 | withVersionLoadingArches: 645 | (newVersion: string) => 646 | (state: State): State => { 647 | if (newVersion === NO_SELECTION) { 648 | return StateUtils.withInstallersVersionsToolsLoaded( 649 | state.unifiedInstallers, 650 | [...state.version.versions], 651 | [...state.toolNames.options] 652 | )(state); 653 | } 654 | const newState = _.cloneDeep(state); 655 | newState.version.selected = new Selection( 656 | newVersion, 657 | SelectValue.Selected 658 | ); 659 | newState.arch = new SelectOne(new Selection(SelectValue.Loading), []); 660 | newState.modules = new SelectMany(); 661 | newState.archives = new SelectMany(); 662 | return newState; 663 | }, 664 | 665 | withArchesLoaded: 666 | (arches: string[]) => 667 | (state: State): State => { 668 | const selection = (() => { 669 | if (arches.length === 1) return new Selection(arches[0]); 670 | if (arches.length > 1) return new Selection(SelectValue.Loaded); 671 | return new Selection(SelectValue.NotLoaded); 672 | })(); 673 | const newState = _.cloneDeep(state); 674 | newState.arch = new SelectOne(selection, arches); 675 | return newState; 676 | }, 677 | 678 | withArchLoadingModulesArchives: 679 | (newArch: string) => 680 | (state: State): State => { 681 | if (newArch === NO_SELECTION) { 682 | return StateUtils.withArchesLoaded([...state.arch.options])(state); 683 | } 684 | const newState = _.cloneDeep(state); 685 | newState.arch.selected = new Selection(newArch, SelectValue.Selected); 686 | newState.modules = new SelectMany(new SelectState(SelectValue.Loading)); 687 | newState.archives = new SelectMany(new SelectState(SelectValue.Loading)); 688 | return newState; 689 | }, 690 | 691 | withModulesArchivesLoaded: 692 | (modules: PackageUpdate[], archives: Map) => 693 | (state: State): State => { 694 | const newState = _.cloneDeep(state); 695 | newState.modules = makeSelectMany(modules, false); 696 | newState.archives = makeSelectMany(archives, true); 697 | return newState; 698 | }, 699 | 700 | withToggledModules: 701 | (on: boolean) => 702 | (state: State): State => { 703 | const newState = _.cloneDeep(state); 704 | newState.modules = state.modules.copyWithAllOptions(on); 705 | // TODO update archives 706 | return newState; 707 | }, 708 | 709 | withModuleSet: 710 | (moduleName: string, on: boolean) => 711 | (state: State): State => { 712 | const newState = _.cloneDeep(state); 713 | newState.modules = state.modules.copyWithOptionSet(moduleName, on); 714 | // TODO update archives 715 | return newState; 716 | }, 717 | 718 | withArchiveSet: 719 | (archive: string, on: boolean) => 720 | (state: State): State => { 721 | const newState = _.cloneDeep(state); 722 | newState.archives = state.archives.copyWithOptionSet(archive, on); 723 | return newState; 724 | }, 725 | 726 | withToggledArchives: 727 | (on: boolean) => 728 | (state: State): State => { 729 | const newState = _.cloneDeep(state); 730 | newState.archives = state.archives.copyWithAllOptions(on); 731 | return newState; 732 | }, 733 | 734 | withNewTool: 735 | (newToolData: ToolData) => 736 | (state: State): State => { 737 | const newState = _.cloneDeep(state); 738 | newState.selectedTools.set(newToolData.name, newToolData); 739 | return newState; 740 | }, 741 | 742 | withInstallActionVersion: 743 | (newInstallActionVersion: string) => 744 | (state: State): State => { 745 | const newState = _.cloneDeep(state); 746 | newState.installActionVersion.selected.value = newInstallActionVersion; 747 | return newState; 748 | }, 749 | 750 | withoutTool: 751 | (toolName: string) => 752 | (state: State): State => { 753 | const newState = _.cloneDeep(state); 754 | newState.selectedTools.delete(toolName); 755 | return newState; 756 | }, 757 | 758 | withToolVariant: 759 | (toolName: string, toolVariant: string, on: boolean) => 760 | (state: State): State => { 761 | const newState = _.cloneDeep(state); 762 | const toolData = state.selectedTools.get(toolName) as ToolData; 763 | newState.selectedTools.set( 764 | toolName, 765 | toolData.copyWithVariantSet(toolVariant, on) 766 | ); 767 | return newState; 768 | }, 769 | 770 | withToggledToolVariants: 771 | (toolName: string, on: boolean) => 772 | (state: State): State => { 773 | const newState = _.cloneDeep(state); 774 | const toolData = state.selectedTools.get(toolName) as ToolData; 775 | newState.selectedTools.set( 776 | toolName, 777 | toolData.copyWithToggledVariants(on) 778 | ); 779 | return newState; 780 | }, 781 | }; 782 | 783 | export const makeState = ( 784 | installers: UnifiedInstallers, 785 | host?: Host, 786 | target?: Target 787 | ): State => { 788 | const [_host, _target, _targets] = get_host_target_targets(host, target); 789 | return new State( 790 | installers, 791 | new SelectOne( 792 | new Selection(hostToStr(_host), SelectValue.Selected), 793 | hosts.map(hostToStr), 794 | false 795 | ), 796 | new SelectOne( 797 | new Selection(targetToStr(_target), SelectValue.Selected), 798 | _targets.map(targetToStr), 799 | false 800 | ), 801 | new SelectNone(SelectValue.Loading), 802 | new Map(), 803 | new Versions(new Selection(SelectValue.Loading), []) 804 | ); 805 | }; 806 | -------------------------------------------------------------------------------- /src/aqt-list-qt-ts/test_data/windows-59-update.json: -------------------------------------------------------------------------------- 1 | { 2 | "qt.59.qtcharts.win32_mingw53": { 3 | "Name": "qt.59.qtcharts.win32_mingw53", 4 | "DisplayName": "Qt Charts for MinGW 5.3.0 32-bit", 5 | "Description": null, 6 | "Version": "5.9.0-0-201705291821", 7 | "ReleaseDate": "2017-05-29", 8 | "AutoDependOn": "qt.59.qtcharts, qt.59.win32_mingw53", 9 | "Dependencies": "qt.59.win32_mingw53", 10 | "Virtual": "true", 11 | "Script": "installscript.qs", 12 | "SortingPriority": null, 13 | "DownloadableArchives": "qtcharts-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 14 | "CompressedSize": "13.2M", 15 | "UncompressedSize": "92.8M", 16 | "SHA1": "cc7f5ca10084923f3b302775efcc25c0ecd4d399" 17 | }, 18 | "qt.59.qtcharts.win32_msvc2015": { 19 | "Name": "qt.59.qtcharts.win32_msvc2015", 20 | "DisplayName": "Qt Charts for msvc2015 32-bit", 21 | "Description": null, 22 | "Version": "5.9.0-0-201705291821", 23 | "ReleaseDate": "2017-05-29", 24 | "AutoDependOn": "qt.59.qtcharts, qt.59.win32_msvc2015", 25 | "Dependencies": "qt.59.win32_msvc2015", 26 | "Virtual": "true", 27 | "Script": "installscript.qs", 28 | "SortingPriority": null, 29 | "DownloadableArchives": "qtcharts-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 30 | "CompressedSize": "5.3M", 31 | "UncompressedSize": "43.0M", 32 | "SHA1": "c6a4778a16618ece6bafcd67cee5b98499fb5bdd" 33 | }, 34 | "qt.59.qtcharts.win64_msvc2013_64": { 35 | "Name": "qt.59.qtcharts.win64_msvc2013_64", 36 | "DisplayName": "Qt Charts for msvc2013 64-bit", 37 | "Description": null, 38 | "Version": "5.9.0-0-201705291821", 39 | "ReleaseDate": "2017-05-29", 40 | "AutoDependOn": "qt.59.qtcharts, qt.59.win64_msvc2013_64", 41 | "Dependencies": "qt.59.win64_msvc2013_64", 42 | "Virtual": "true", 43 | "Script": "installscript.qs", 44 | "SortingPriority": null, 45 | "DownloadableArchives": "qtcharts-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 46 | "CompressedSize": "5.3M", 47 | "UncompressedSize": "42.2M", 48 | "SHA1": "50e8607fd8220892cb13d4521993a897b6c7fd06" 49 | }, 50 | "qt.59.qtcharts.win64_msvc2015_64": { 51 | "Name": "qt.59.qtcharts.win64_msvc2015_64", 52 | "DisplayName": "Qt Charts for msvc2015 64-bit", 53 | "Description": null, 54 | "Version": "5.9.0-0-201705291821", 55 | "ReleaseDate": "2017-05-29", 56 | "AutoDependOn": "qt.59.qtcharts, qt.59.win64_msvc2015_64", 57 | "Dependencies": "qt.59.win64_msvc2015_64", 58 | "Virtual": "true", 59 | "Script": "installscript.qs", 60 | "SortingPriority": null, 61 | "DownloadableArchives": "qtcharts-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 62 | "CompressedSize": "5.8M", 63 | "UncompressedSize": "44.2M", 64 | "SHA1": "7446596b4853afae944b4beab7a008ed55769164" 65 | }, 66 | "qt.59.qtcharts.win64_msvc2017_64": { 67 | "Name": "qt.59.qtcharts.win64_msvc2017_64", 68 | "DisplayName": "Qt Charts for msvc2017 64-bit", 69 | "Description": null, 70 | "Version": "5.9.0-0-201705291821", 71 | "ReleaseDate": "2017-05-29", 72 | "AutoDependOn": "qt.59.qtcharts, qt.59.win64_msvc2017_64", 73 | "Dependencies": "qt.59.win64_msvc2017_64", 74 | "Virtual": "true", 75 | "Script": "installscript.qs", 76 | "SortingPriority": null, 77 | "DownloadableArchives": "qtcharts-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 78 | "CompressedSize": "5.9M", 79 | "UncompressedSize": "44.8M", 80 | "SHA1": "c4d277c8c96a83bf3e401e60ef9b33e46f1ae0a9" 81 | }, 82 | "qt.59.qtdatavis3d.win32_mingw53": { 83 | "Name": "qt.59.qtdatavis3d.win32_mingw53", 84 | "DisplayName": "Qt Data Visualization for MinGW 5.3.0 32-bit", 85 | "Description": null, 86 | "Version": "5.9.0-0-201705291821", 87 | "ReleaseDate": "2017-05-29", 88 | "AutoDependOn": "qt.59.qtdatavis3d, qt.59.win32_mingw53", 89 | "Dependencies": "qt.59.win32_mingw53", 90 | "Virtual": "true", 91 | "Script": "installscript.qs", 92 | "SortingPriority": null, 93 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 94 | "CompressedSize": "12.1M", 95 | "UncompressedSize": "87.0M", 96 | "SHA1": "77e5ddf1c01b357008802247a39ae92bd9dcb371" 97 | }, 98 | "qt.59.qtdatavis3d.win32_msvc2015": { 99 | "Name": "qt.59.qtdatavis3d.win32_msvc2015", 100 | "DisplayName": "Qt Data Visualization for msvc2015 32-bit", 101 | "Description": null, 102 | "Version": "5.9.0-0-201705291821", 103 | "ReleaseDate": "2017-05-29", 104 | "AutoDependOn": "qt.59.qtdatavis3d, qt.59.win32_msvc2015", 105 | "Dependencies": "qt.59.win32_msvc2015", 106 | "Virtual": "true", 107 | "Script": "installscript.qs", 108 | "SortingPriority": null, 109 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 110 | "CompressedSize": "4.7M", 111 | "UncompressedSize": "41.0M", 112 | "SHA1": "9a185f6eab042f444be262afa7f9d3436bc7d190" 113 | }, 114 | "qt.59.qtdatavis3d.win64_msvc2013_64": { 115 | "Name": "qt.59.qtdatavis3d.win64_msvc2013_64", 116 | "DisplayName": "Qt Data Visualization for msvc2013 64-bit", 117 | "Description": null, 118 | "Version": "5.9.0-0-201705291821", 119 | "ReleaseDate": "2017-05-29", 120 | "AutoDependOn": "qt.59.qtdatavis3d, qt.59.win64_msvc2013_64", 121 | "Dependencies": "qt.59.win64_msvc2013_64", 122 | "Virtual": "true", 123 | "Script": "installscript.qs", 124 | "SortingPriority": null, 125 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 126 | "CompressedSize": "4.7M", 127 | "UncompressedSize": "39.8M", 128 | "SHA1": "027f652ad79b4e5ccdd1c6f1a5876e0c72f62817" 129 | }, 130 | "qt.59.qtdatavis3d.win64_msvc2015_64": { 131 | "Name": "qt.59.qtdatavis3d.win64_msvc2015_64", 132 | "DisplayName": "Qt Data Visualization for msvc2015 64-bit", 133 | "Description": null, 134 | "Version": "5.9.0-0-201705291821", 135 | "ReleaseDate": "2017-05-29", 136 | "AutoDependOn": "qt.59.qtdatavis3d, qt.59.win64_msvc2015_64", 137 | "Dependencies": "qt.59.win64_msvc2015_64", 138 | "Virtual": "true", 139 | "Script": "installscript.qs", 140 | "SortingPriority": null, 141 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 142 | "CompressedSize": "5.1M", 143 | "UncompressedSize": "41.8M", 144 | "SHA1": "d629ec44692855d64f29b00f6e5ea52128ee1e1a" 145 | }, 146 | "qt.59.qtdatavis3d.win64_msvc2017_64": { 147 | "Name": "qt.59.qtdatavis3d.win64_msvc2017_64", 148 | "DisplayName": "Qt Data Visualization for msvc2017 64-bit", 149 | "Description": null, 150 | "Version": "5.9.0-0-201705291821", 151 | "ReleaseDate": "2017-05-29", 152 | "AutoDependOn": "qt.59.qtdatavis3d, qt.59.win64_msvc2017_64", 153 | "Dependencies": "qt.59.win64_msvc2017_64", 154 | "Virtual": "true", 155 | "Script": "installscript.qs", 156 | "SortingPriority": null, 157 | "DownloadableArchives": "qtdatavis3d-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 158 | "CompressedSize": "5.2M", 159 | "UncompressedSize": "42.3M", 160 | "SHA1": "0c0460d26e382607b39be7e8035e4679e12ef95f" 161 | }, 162 | "qt.59.qtnetworkauth.win32_mingw53": { 163 | "Name": "qt.59.qtnetworkauth.win32_mingw53", 164 | "DisplayName": "Qt Network Authentication for MinGW 5.3.0 32-bit", 165 | "Description": null, 166 | "Version": "5.9.0-0-201705291821", 167 | "ReleaseDate": "2017-05-29", 168 | "AutoDependOn": "qt.59.qtnetworkauth, qt.59.win32_mingw53", 169 | "Dependencies": "qt.59.win32_mingw53", 170 | "Virtual": "true", 171 | "Script": "installscript.qs", 172 | "SortingPriority": null, 173 | "DownloadableArchives": "qtnetworkauth-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 174 | "CompressedSize": "1.3M", 175 | "UncompressedSize": "8.5M", 176 | "SHA1": "5706ce5bab4c0ed43fe5fac4ce1201139794de63" 177 | }, 178 | "qt.59.qtnetworkauth.win32_msvc2015": { 179 | "Name": "qt.59.qtnetworkauth.win32_msvc2015", 180 | "DisplayName": "Qt Network Authentication for msvc2015 32-bit", 181 | "Description": null, 182 | "Version": "5.9.0-0-201705291821", 183 | "ReleaseDate": "2017-05-29", 184 | "AutoDependOn": "qt.59.qtnetworkauth, qt.59.win32_msvc2015", 185 | "Dependencies": "qt.59.win32_msvc2015", 186 | "Virtual": "true", 187 | "Script": "installscript.qs", 188 | "SortingPriority": null, 189 | "DownloadableArchives": "qtnetworkauth-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 190 | "CompressedSize": "1.6M", 191 | "UncompressedSize": "12.5M", 192 | "SHA1": "8b5a30ffd27af6cae954f6fc32dc381089c50e37" 193 | }, 194 | "qt.59.qtnetworkauth.win64_msvc2013_64": { 195 | "Name": "qt.59.qtnetworkauth.win64_msvc2013_64", 196 | "DisplayName": "Qt Network Authentication for msvc2013 64-bit", 197 | "Description": null, 198 | "Version": "5.9.0-0-201705291821", 199 | "ReleaseDate": "2017-05-29", 200 | "AutoDependOn": "qt.59.qtnetworkauth, qt.59.win64_msvc2013_64", 201 | "Dependencies": "qt.59.win64_msvc2013_64", 202 | "Virtual": "true", 203 | "Script": "installscript.qs", 204 | "SortingPriority": null, 205 | "DownloadableArchives": "qtnetworkauth-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 206 | "CompressedSize": "1.7M", 207 | "UncompressedSize": "11.9M", 208 | "SHA1": "78dcace69f87bef79733c850ea57496059d4ca3b" 209 | }, 210 | "qt.59.qtnetworkauth.win64_msvc2015_64": { 211 | "Name": "qt.59.qtnetworkauth.win64_msvc2015_64", 212 | "DisplayName": "Qt Network Authentication for msvc2015_64-bit", 213 | "Description": null, 214 | "Version": "5.9.0-0-201705291821", 215 | "ReleaseDate": "2017-05-29", 216 | "AutoDependOn": "qt.59.qtnetworkauth, qt.59.win64_msvc2015_64", 217 | "Dependencies": "qt.59.win64_msvc2015_64", 218 | "Virtual": "true", 219 | "Script": "installscript.qs", 220 | "SortingPriority": null, 221 | "DownloadableArchives": "qtnetworkauth-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 222 | "CompressedSize": "1.8M", 223 | "UncompressedSize": "12.7M", 224 | "SHA1": "21cd97ef0f1ee8b5be5cd1833b18d807a890c86d" 225 | }, 226 | "qt.59.qtnetworkauth.win64_msvc2017_64": { 227 | "Name": "qt.59.qtnetworkauth.win64_msvc2017_64", 228 | "DisplayName": "Qt Network Authentication for msvc2017_64-bit", 229 | "Description": null, 230 | "Version": "5.9.0-0-201705291821", 231 | "ReleaseDate": "2017-05-29", 232 | "AutoDependOn": "qt.59.qtnetworkauth, qt.59.win64_msvc2017_64", 233 | "Dependencies": "qt.59.win64_msvc2017_64", 234 | "Virtual": "true", 235 | "Script": "installscript.qs", 236 | "SortingPriority": null, 237 | "DownloadableArchives": "qtnetworkauth-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 238 | "CompressedSize": "1.9M", 239 | "UncompressedSize": "12.8M", 240 | "SHA1": "b5a0381ab08324d3deedb3e69a280983a739809b" 241 | }, 242 | "qt.59.qtpurchasing.win32_mingw53": { 243 | "Name": "qt.59.qtpurchasing.win32_mingw53", 244 | "DisplayName": "Qt Purchasing for MinGW 5.3.0 32-bit", 245 | "Description": null, 246 | "Version": "5.9.0-0-201705291821", 247 | "ReleaseDate": "2017-05-29", 248 | "AutoDependOn": "qt.59.qtpurchasing, qt.59.win32_mingw53", 249 | "Dependencies": "qt.59.win32_mingw53", 250 | "Virtual": "true", 251 | "Script": "installscript.qs", 252 | "SortingPriority": null, 253 | "DownloadableArchives": "qtpurchasing-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 254 | "CompressedSize": "715.1K", 255 | "UncompressedSize": "4.6M", 256 | "SHA1": "2459646d41b85fbbb9b5c7f242a136759c2f4f5d" 257 | }, 258 | "qt.59.qtpurchasing.win32_msvc2015": { 259 | "Name": "qt.59.qtpurchasing.win32_msvc2015", 260 | "DisplayName": "Qt Location for msvc2015 32-bit", 261 | "Description": null, 262 | "Version": "5.9.0-0-201705291821", 263 | "ReleaseDate": "2017-05-29", 264 | "AutoDependOn": "qt.59.qtpurchasing, qt.59.win32_msvc2015", 265 | "Dependencies": "qt.59.win32_msvc2015", 266 | "Virtual": "true", 267 | "Script": "installscript.qs", 268 | "SortingPriority": null, 269 | "DownloadableArchives": "qtpurchasing-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 270 | "CompressedSize": "893.4K", 271 | "UncompressedSize": "7.6M", 272 | "SHA1": "efe8a5aba8f3f480c9e33cab28c8acaabe63a930" 273 | }, 274 | "qt.59.qtpurchasing.win64_msvc2013_64": { 275 | "Name": "qt.59.qtpurchasing.win64_msvc2013_64", 276 | "DisplayName": "Qt Purchasing for msvc2013 64-bit", 277 | "Description": null, 278 | "Version": "5.9.0-0-201705291821", 279 | "ReleaseDate": "2017-05-29", 280 | "AutoDependOn": "qt.59.qtpurchasing, qt.59.win64_msvc2013_64", 281 | "Dependencies": "qt.59.win64_msvc2013_64", 282 | "Virtual": "true", 283 | "Script": "installscript.qs", 284 | "SortingPriority": null, 285 | "DownloadableArchives": "qtpurchasing-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 286 | "CompressedSize": "912.6K", 287 | "UncompressedSize": "7.1M", 288 | "SHA1": "0a9768e3a598a209b3975ca61e51897176efbdee" 289 | }, 290 | "qt.59.qtpurchasing.win64_msvc2015_64": { 291 | "Name": "qt.59.qtpurchasing.win64_msvc2015_64", 292 | "DisplayName": "Qt Purchasing for msvc2015 64-bit", 293 | "Description": null, 294 | "Version": "5.9.0-0-201705291821", 295 | "ReleaseDate": "2017-05-29", 296 | "AutoDependOn": "qt.59.qtpurchasing, qt.59.win64_msvc2015_64", 297 | "Dependencies": "qt.59.win64_msvc2015_64", 298 | "Virtual": "true", 299 | "Script": "installscript.qs", 300 | "SortingPriority": null, 301 | "DownloadableArchives": "qtpurchasing-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 302 | "CompressedSize": "972.5K", 303 | "UncompressedSize": "7.7M", 304 | "SHA1": "8561ff98616f87b7582a3daf73397c916b663e72" 305 | }, 306 | "qt.59.qtpurchasing.win64_msvc2017_64": { 307 | "Name": "qt.59.qtpurchasing.win64_msvc2017_64", 308 | "DisplayName": "Qt Purchasing for msvc2017 64-bit", 309 | "Description": null, 310 | "Version": "5.9.0-0-201705291821", 311 | "ReleaseDate": "2017-05-29", 312 | "AutoDependOn": "qt.59.qtpurchasing, qt.59.win64_msvc2017_64", 313 | "Dependencies": "qt.59.win64_msvc2017_64", 314 | "Virtual": "true", 315 | "Script": "installscript.qs", 316 | "SortingPriority": null, 317 | "DownloadableArchives": "qtpurchasing-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 318 | "CompressedSize": "1008.2K", 319 | "UncompressedSize": "7.9M", 320 | "SHA1": "56403ad3d8ef36943c64dc3e8deeb6ec70496c61" 321 | }, 322 | "qt.59.qtremoteobjects.win32_mingw53": { 323 | "Name": "qt.59.qtremoteobjects.win32_mingw53", 324 | "DisplayName": "Qt Remote Objects for MinGW 5.3.0 32-bit", 325 | "Description": null, 326 | "Version": "5.9.0-0-201705291821", 327 | "ReleaseDate": "2017-05-29", 328 | "AutoDependOn": "qt.59.qtremoteobjects, qt.59.win32_mingw53", 329 | "Dependencies": "qt.59.win32_mingw53", 330 | "Virtual": "true", 331 | "Script": "installscript.qs", 332 | "SortingPriority": null, 333 | "DownloadableArchives": "qtremoteobjects-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 334 | "CompressedSize": "2.8M", 335 | "UncompressedSize": "16.7M", 336 | "SHA1": "daa1c72c29be14df8b71bfe3d9fdd17dbc3d1e58" 337 | }, 338 | "qt.59.qtremoteobjects.win32_msvc2015": { 339 | "Name": "qt.59.qtremoteobjects.win32_msvc2015", 340 | "DisplayName": "Qt Remote Objects for msvc2015 32-bit", 341 | "Description": null, 342 | "Version": "5.9.0-0-201705291821", 343 | "ReleaseDate": "2017-05-29", 344 | "AutoDependOn": "qt.59.qtremoteobjects, qt.59.win32_msvc2015", 345 | "Dependencies": "qt.59.win32_msvc2015", 346 | "Virtual": "true", 347 | "Script": "installscript.qs", 348 | "SortingPriority": null, 349 | "DownloadableArchives": "qtremoteobjects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 350 | "CompressedSize": "2.1M", 351 | "UncompressedSize": "14.9M", 352 | "SHA1": "8fffa1464b8aeb5c9a7c8c45c0f17b0cee6c6a0b" 353 | }, 354 | "qt.59.qtremoteobjects.win64_msvc2013_64": { 355 | "Name": "qt.59.qtremoteobjects.win64_msvc2013_64", 356 | "DisplayName": "Qt Remote Objects for msvc2013 64-bit", 357 | "Description": null, 358 | "Version": "5.9.0-0-201705291821", 359 | "ReleaseDate": "2017-05-29", 360 | "AutoDependOn": "qt.59.qtremoteobjects, qt.59.win64_msvc2013_64", 361 | "Dependencies": "qt.59.win64_msvc2013_64", 362 | "Virtual": "true", 363 | "Script": "installscript.qs", 364 | "SortingPriority": null, 365 | "DownloadableArchives": "qtremoteobjects-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 366 | "CompressedSize": "1.9M", 367 | "UncompressedSize": "13.6M", 368 | "SHA1": "f8400da51da132794e6ae840334460d3d850b933" 369 | }, 370 | "qt.59.qtremoteobjects.win64_msvc2015_64": { 371 | "Name": "qt.59.qtremoteobjects.win64_msvc2015_64", 372 | "DisplayName": "Qt Remote Objects for msvc2015_64-bit", 373 | "Description": null, 374 | "Version": "5.9.0-0-201705291821", 375 | "ReleaseDate": "2017-05-29", 376 | "AutoDependOn": "qt.59.qtremoteobjects, qt.59.win64_msvc2015_64", 377 | "Dependencies": "qt.59.win64_msvc2015_64", 378 | "Virtual": "true", 379 | "Script": "installscript.qs", 380 | "SortingPriority": null, 381 | "DownloadableArchives": "qtremoteobjects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 382 | "CompressedSize": "2.2M", 383 | "UncompressedSize": "15.3M", 384 | "SHA1": "621c5626a6771125459692ef00795c339ad3d222" 385 | }, 386 | "qt.59.qtremoteobjects.win64_msvc2017_64": { 387 | "Name": "qt.59.qtremoteobjects.win64_msvc2017_64", 388 | "DisplayName": "Qt Remote Objects for msvc2017_64-bit", 389 | "Description": null, 390 | "Version": "5.9.0-0-201705291821", 391 | "ReleaseDate": "2017-05-29", 392 | "AutoDependOn": "qt.59.qtremoteobjects, qt.59.win64_msvc2017_64", 393 | "Dependencies": "qt.59.win64_msvc2017_64", 394 | "Virtual": "true", 395 | "Script": "installscript.qs", 396 | "SortingPriority": null, 397 | "DownloadableArchives": "qtremoteobjects-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 398 | "CompressedSize": "2.3M", 399 | "UncompressedSize": "15.6M", 400 | "SHA1": "b11d1055027f820f1746afa43af32136549f63fc" 401 | }, 402 | "qt.59.qtscript.win32_mingw53": { 403 | "Name": "qt.59.qtscript.win32_mingw53", 404 | "DisplayName": "Qt Script for MinGW 5.3.0 32-bit", 405 | "Description": null, 406 | "Version": "5.9.0-0-201705291821", 407 | "ReleaseDate": "2017-05-29", 408 | "AutoDependOn": "qt.59.qtscript, qt.59.win32_mingw53", 409 | "Dependencies": "qt.59.win32_mingw53", 410 | "Virtual": "true", 411 | "Script": "installscript.qs", 412 | "SortingPriority": null, 413 | "DownloadableArchives": "qtscript-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 414 | "CompressedSize": "21.8M", 415 | "UncompressedSize": "149.9M", 416 | "SHA1": "120121e0878c65a64542fd55bd08690c0a609d5a" 417 | }, 418 | "qt.59.qtscript.win32_msvc2015": { 419 | "Name": "qt.59.qtscript.win32_msvc2015", 420 | "DisplayName": "Qt Script for msvc2015 32-bit", 421 | "Description": null, 422 | "Version": "5.9.0-0-201705291821", 423 | "ReleaseDate": "2017-05-29", 424 | "AutoDependOn": "qt.59.qtscript, qt.59.win32_msvc2015", 425 | "Dependencies": "qt.59.win32_msvc2015", 426 | "Virtual": "true", 427 | "Script": "installscript.qs", 428 | "SortingPriority": null, 429 | "DownloadableArchives": "qtscript-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 430 | "CompressedSize": "7.1M", 431 | "UncompressedSize": "53.9M", 432 | "SHA1": "4f5ec769aa116cbbb4d66436f0bb6e8c001335c4" 433 | }, 434 | "qt.59.qtscript.win64_msvc2013_64": { 435 | "Name": "qt.59.qtscript.win64_msvc2013_64", 436 | "DisplayName": "Qt Script for msvc2013 64-bit", 437 | "Description": null, 438 | "Version": "5.9.0-0-201705291821", 439 | "ReleaseDate": "2017-05-29", 440 | "AutoDependOn": "qt.59.qtscript, qt.59.win64_msvc2013_64", 441 | "Dependencies": "qt.59.win64_msvc2013_64", 442 | "Virtual": "true", 443 | "Script": "installscript.qs", 444 | "SortingPriority": null, 445 | "DownloadableArchives": "qtscript-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 446 | "CompressedSize": "5.8M", 447 | "UncompressedSize": "48.6M", 448 | "SHA1": "44cb6c507791507a0987b2aac3b40c37bd06f98f" 449 | }, 450 | "qt.59.qtscript.win64_msvc2015_64": { 451 | "Name": "qt.59.qtscript.win64_msvc2015_64", 452 | "DisplayName": "Qt Script for msvc2015 64-bit", 453 | "Description": null, 454 | "Version": "5.9.0-0-201705291821", 455 | "ReleaseDate": "2017-05-29", 456 | "AutoDependOn": "qt.59.qtscript, qt.59.win64_msvc2015_64", 457 | "Dependencies": "qt.59.win64_msvc2015_64", 458 | "Virtual": "true", 459 | "Script": "installscript.qs", 460 | "SortingPriority": null, 461 | "DownloadableArchives": "qtscript-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 462 | "CompressedSize": "7.0M", 463 | "UncompressedSize": "51.8M", 464 | "SHA1": "579312a33994bd2649defaa3786171955ff116e5" 465 | }, 466 | "qt.59.qtscript.win64_msvc2017_64": { 467 | "Name": "qt.59.qtscript.win64_msvc2017_64", 468 | "DisplayName": "Qt Script for msvc2017 64-bit", 469 | "Description": null, 470 | "Version": "5.9.0-0-201705291821", 471 | "ReleaseDate": "2017-05-29", 472 | "AutoDependOn": "qt.59.qtscript, qt.59.win64_msvc2017_64", 473 | "Dependencies": "qt.59.win64_msvc2017_64", 474 | "Virtual": "true", 475 | "Script": "installscript.qs", 476 | "SortingPriority": null, 477 | "DownloadableArchives": "qtscript-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 478 | "CompressedSize": "6.8M", 479 | "UncompressedSize": "50.1M", 480 | "SHA1": "915bfcf078c7d5412709f24e6f56072829fed740" 481 | }, 482 | "qt.59.qtspeech.win32_mingw53": { 483 | "Name": "qt.59.qtspeech.win32_mingw53", 484 | "DisplayName": "Qt Speech for MinGW 5.3.0 32-bit", 485 | "Description": null, 486 | "Version": "5.9.0-0-201705291821", 487 | "ReleaseDate": "2017-05-29", 488 | "AutoDependOn": "qt.59.qtspeech, qt.59.win32_mingw53", 489 | "Dependencies": "qt.59.win32_mingw53", 490 | "Virtual": "true", 491 | "Script": "installscript.qs", 492 | "SortingPriority": null, 493 | "DownloadableArchives": "qtspeech-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 494 | "CompressedSize": "738.3K", 495 | "UncompressedSize": "4.4M", 496 | "SHA1": "1ef5b02779c1a7ed4641be15d324c8739d64eae1" 497 | }, 498 | "qt.59.qtspeech.win32_msvc2015": { 499 | "Name": "qt.59.qtspeech.win32_msvc2015", 500 | "DisplayName": "Qt Speech for msvc2015 32-bit", 501 | "Description": null, 502 | "Version": "5.9.0-0-201705291821", 503 | "ReleaseDate": "2017-05-29", 504 | "AutoDependOn": "qt.59.qtspeech, qt.59.win32_msvc2015", 505 | "Dependencies": "qt.59.win32_msvc2015", 506 | "Virtual": "true", 507 | "Script": "installscript.qs", 508 | "SortingPriority": null, 509 | "DownloadableArchives": "qtspeech-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 510 | "CompressedSize": "1.3M", 511 | "UncompressedSize": "9.6M", 512 | "SHA1": "d1f79fcd98d9a6a531d49d384c18f84a593af97a" 513 | }, 514 | "qt.59.qtspeech.win64_msvc2013_64": { 515 | "Name": "qt.59.qtspeech.win64_msvc2013_64", 516 | "DisplayName": "Qt Speech for msvc2013 64-bit", 517 | "Description": null, 518 | "Version": "5.9.0-0-201705291821", 519 | "ReleaseDate": "2017-05-29", 520 | "AutoDependOn": "qt.59.qtspeech, qt.59.win64_msvc2013_64", 521 | "Dependencies": "qt.59.win64_msvc2013_64", 522 | "Virtual": "true", 523 | "Script": "installscript.qs", 524 | "SortingPriority": null, 525 | "DownloadableArchives": "qtspeech-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 526 | "CompressedSize": "1.2M", 527 | "UncompressedSize": "9.2M", 528 | "SHA1": "e70c42ff5b81945850ae4bf9b4feb65a9ee6f5e0" 529 | }, 530 | "qt.59.qtspeech.win64_msvc2015_64": { 531 | "Name": "qt.59.qtspeech.win64_msvc2015_64", 532 | "DisplayName": "Qt Speech for msvc2015_64-bit", 533 | "Description": null, 534 | "Version": "5.9.0-0-201705291821", 535 | "ReleaseDate": "2017-05-29", 536 | "AutoDependOn": "qt.59.qtspeech, qt.59.win64_msvc2015_64", 537 | "Dependencies": "qt.59.win64_msvc2015_64", 538 | "Virtual": "true", 539 | "Script": "installscript.qs", 540 | "SortingPriority": null, 541 | "DownloadableArchives": "qtspeech-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 542 | "CompressedSize": "1.3M", 543 | "UncompressedSize": "9.7M", 544 | "SHA1": "5d61fbfdfe35c80ab0e86afd774e9020ca8d52dc" 545 | }, 546 | "qt.59.qtspeech.win64_msvc2017_64": { 547 | "Name": "qt.59.qtspeech.win64_msvc2017_64", 548 | "DisplayName": "Qt Speech for msvc2017_64-bit", 549 | "Description": null, 550 | "Version": "5.9.0-0-201705291821", 551 | "ReleaseDate": "2017-05-29", 552 | "AutoDependOn": "qt.59.qtspeech, qt.59.win64_msvc2017_64", 553 | "Dependencies": "qt.59.win64_msvc2017_64", 554 | "Virtual": "true", 555 | "Script": "installscript.qs", 556 | "SortingPriority": null, 557 | "DownloadableArchives": "qtspeech-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 558 | "CompressedSize": "1.4M", 559 | "UncompressedSize": "10.0M", 560 | "SHA1": "6d9d88bdbc796495107a2f4e5f587250ef9c1d93" 561 | }, 562 | "qt.59.qtvirtualkeyboard.win32_mingw53": { 563 | "Name": "qt.59.qtvirtualkeyboard.win32_mingw53", 564 | "DisplayName": "Qt Virtual Keyboard for MinGW 5.3.0 32-bit", 565 | "Description": null, 566 | "Version": "5.9.0-0-201705291821", 567 | "ReleaseDate": "2017-05-29", 568 | "AutoDependOn": "qt.59.qtvirtualkeyboard, qt.59.win32_mingw53", 569 | "Dependencies": "qt.59.win32_mingw53", 570 | "Virtual": "true", 571 | "Script": "installscript.qs", 572 | "SortingPriority": null, 573 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z", 574 | "CompressedSize": "3.2M", 575 | "UncompressedSize": "19.6M", 576 | "SHA1": "15861bdd0addc263b76794ffe07aa2fee2fbced2" 577 | }, 578 | "qt.59.qtvirtualkeyboard.win32_msvc2015": { 579 | "Name": "qt.59.qtvirtualkeyboard.win32_msvc2015", 580 | "DisplayName": "Qt Virtual Keyboard for msvc2015 32-bit", 581 | "Description": null, 582 | "Version": "5.9.0-0-201705291821", 583 | "ReleaseDate": "2017-05-29", 584 | "AutoDependOn": "qt.59.qtvirtualkeyboard, qt.59.win32_msvc2015", 585 | "Dependencies": "qt.59.win32_msvc2015", 586 | "Virtual": "true", 587 | "Script": "installscript.qs", 588 | "SortingPriority": null, 589 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 590 | "CompressedSize": "2.0M", 591 | "UncompressedSize": "14.3M", 592 | "SHA1": "4e2b0d7a9101e0d3d100a33227bad4a57851e530" 593 | }, 594 | "qt.59.qtvirtualkeyboard.win64_msvc2013_64": { 595 | "Name": "qt.59.qtvirtualkeyboard.win64_msvc2013_64", 596 | "DisplayName": "Qt Virtual Keyboard for msvc2013 64-bit", 597 | "Description": null, 598 | "Version": "5.9.0-0-201705291821", 599 | "ReleaseDate": "2017-05-29", 600 | "AutoDependOn": "qt.59.qtvirtualkeyboard, qt.59.win64_msvc2013_64", 601 | "Dependencies": "qt.59.win64_msvc2013_64", 602 | "Virtual": "true", 603 | "Script": "installscript.qs", 604 | "SortingPriority": null, 605 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z", 606 | "CompressedSize": "2.0M", 607 | "UncompressedSize": "14.3M", 608 | "SHA1": "cc7b16ceee5e58797a89381db2cd4d6bfc625472" 609 | }, 610 | "qt.59.qtvirtualkeyboard.win64_msvc2015_64": { 611 | "Name": "qt.59.qtvirtualkeyboard.win64_msvc2015_64", 612 | "DisplayName": "Qt Virtual Keyboard for msvc2015 64-bit", 613 | "Description": null, 614 | "Version": "5.9.0-0-201705291821", 615 | "ReleaseDate": "2017-05-29", 616 | "AutoDependOn": "qt.59.qtvirtualkeyboard, qt.59.win64_msvc2015_64", 617 | "Dependencies": "qt.59.win64_msvc2015_64", 618 | "Virtual": "true", 619 | "Script": "installscript.qs", 620 | "SortingPriority": null, 621 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 622 | "CompressedSize": "2.0M", 623 | "UncompressedSize": "14.6M", 624 | "SHA1": "09a2feda890084398cd6bbb971273956af125f8a" 625 | }, 626 | "qt.59.qtvirtualkeyboard.win64_msvc2017_64": { 627 | "Name": "qt.59.qtvirtualkeyboard.win64_msvc2017_64", 628 | "DisplayName": "Qt Virtual Keyboard for msvc2017 64-bit", 629 | "Description": null, 630 | "Version": "5.9.0-0-201705291821", 631 | "ReleaseDate": "2017-05-29", 632 | "AutoDependOn": "qt.59.qtvirtualkeyboard, qt.59.win64_msvc2017_64", 633 | "Dependencies": "qt.59.win64_msvc2017_64", 634 | "Virtual": "true", 635 | "Script": "installscript.qs", 636 | "SortingPriority": null, 637 | "DownloadableArchives": "qtvirtualkeyboard-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 638 | "CompressedSize": "2.1M", 639 | "UncompressedSize": "14.9M", 640 | "SHA1": "bbcf50e66a49ce7ac8105d083adc8e72cb8d6165" 641 | }, 642 | "qt.59.qtwebengine.win32_msvc2015": { 643 | "Name": "qt.59.qtwebengine.win32_msvc2015", 644 | "DisplayName": "Qt WebEngine for msvc2015 32-bit", 645 | "Description": null, 646 | "Version": "5.9.0-0-201705291821", 647 | "ReleaseDate": "2017-05-29", 648 | "AutoDependOn": "qt.59.qtwebengine, qt.59.win32_msvc2015", 649 | "Dependencies": "qt.59.win32_msvc2015", 650 | "Virtual": "true", 651 | "Script": "installscript.qs", 652 | "SortingPriority": null, 653 | "DownloadableArchives": "qtwebengine-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z", 654 | "CompressedSize": "121.7M", 655 | "UncompressedSize": "1.4G", 656 | "SHA1": "b4132d6ac7bc6faebc537294ab287eb8441f197d" 657 | }, 658 | "qt.59.qtwebengine.win64_msvc2015_64": { 659 | "Name": "qt.59.qtwebengine.win64_msvc2015_64", 660 | "DisplayName": "Qt WebEngine for msvc2015 64-bit", 661 | "Description": null, 662 | "Version": "5.9.0-0-201705291821", 663 | "ReleaseDate": "2017-05-29", 664 | "AutoDependOn": "qt.59.qtwebengine, qt.59.win64_msvc2015_64", 665 | "Dependencies": "qt.59.win64_msvc2015_64", 666 | "Virtual": "true", 667 | "Script": "installscript.qs", 668 | "SortingPriority": null, 669 | "DownloadableArchives": "qtwebengine-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z", 670 | "CompressedSize": "225.8M", 671 | "UncompressedSize": "2.4G", 672 | "SHA1": "55cc6f1335f0b01380ebe6713c80cdb3be57d394" 673 | }, 674 | "qt.59.qtwebengine.win64_msvc2017_64": { 675 | "Name": "qt.59.qtwebengine.win64_msvc2017_64", 676 | "DisplayName": "Qt WebEngine for msvc2017 64-bit", 677 | "Description": null, 678 | "Version": "5.9.0-0-201705291821", 679 | "ReleaseDate": "2017-05-29", 680 | "AutoDependOn": "qt.59.qtwebengine, qt.59.win64_msvc2017_64", 681 | "Dependencies": "qt.59.win64_msvc2017_64", 682 | "Virtual": "true", 683 | "Script": "installscript.qs", 684 | "SortingPriority": null, 685 | "DownloadableArchives": "qtwebengine-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z", 686 | "CompressedSize": "220.2M", 687 | "UncompressedSize": "2.3G", 688 | "SHA1": "aab17296859736d5c1b570ca663115d23dc15452" 689 | }, 690 | "qt.59.win32_mingw53": { 691 | "Name": "qt.59.win32_mingw53", 692 | "DisplayName": "MinGW 5.3.0 32 bit", 693 | "Description": "Qt 5.9.0 Prebuilt Components for MinGW 5.3.0 32-bit", 694 | "Version": "5.9.0-0-201705291821", 695 | "ReleaseDate": "2017-05-29", 696 | "Dependencies": "qt.tools.qtcreator, qt.tools.win32_mingw530, qt.59.doc, qt.59.examples", 697 | "Default": "false", 698 | "Script": "installscript.qs", 699 | "SortingPriority": "590", 700 | "DownloadableArchives": "qtbase-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtconnectivity-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtactiveqt-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtmultimedia-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qttranslations-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtgraphicaleffects-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtsvg-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtdeclarative-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtwinextras-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtimageformats-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qttools-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtxmlpatterns-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtsensors-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtwebsockets-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtwebchannel-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtlocation-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtserialport-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtquickcontrols-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtquickcontrols2-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qt3d-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtcanvas3d-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtserialbus-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtscxml-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, qtgamepad-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z, i686-5.3.0-release-posix-dwarf-rt_v4-rev0-runtime.7z, opengl32sw-32-mesa_12_0_rc2.7z", 701 | "CompressedSize": "494.1M", 702 | "UncompressedSize": "3.1G", 703 | "SHA1": "79ebbd6f95a356875f98edd7aee99b219db411eb", 704 | "ArchiveSizes": { 705 | "qtxmlpatterns-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "29M", 706 | "qtwinextras-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "2.0M", 707 | "qtwebsockets-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "1.7M", 708 | "qtwebchannel-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "765K", 709 | "qttranslations-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "1.4M", 710 | "qttools-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "46M", 711 | "qtsvg-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "2.2M", 712 | "qtserialport-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "316K", 713 | "qtserialbus-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "2.3M", 714 | "qtsensors-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "3.8M", 715 | "qtscxml-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "3.2M", 716 | "qtquickcontrols2-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "19M", 717 | "qtquickcontrols-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "8.4M", 718 | "qtmultimedia-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "14M", 719 | "qtlocation-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "45M", 720 | "qtimageformats-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "1.7M", 721 | "qtgraphicaleffects-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "579K", 722 | "qtgamepad-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "907K", 723 | "qtdeclarative-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "74M", 724 | "qtconnectivity-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "4.9M", 725 | "qtcanvas3d-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "6.3M", 726 | "qtbase-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "140M", 727 | "qtactiveqt-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "3.3M", 728 | "qt3d-Windows-Windows_7-Mingw53-Windows-Windows_7-X86.7z": "79M", 729 | "opengl32sw-32-mesa_12_0_rc2.7z": "3.8M", 730 | "i686-5.3.0-release-posix-dwarf-rt_v4-rev0-runtime.7z": "367K" 731 | } 732 | }, 733 | "qt.59.win32_msvc2015": { 734 | "Name": "qt.59.win32_msvc2015", 735 | "DisplayName": "msvc2015 32-bit", 736 | "Description": "Qt 5.9.0 Prebuilt Components for msvc2015 32-bit", 737 | "Version": "5.9.0-0-201705291821", 738 | "ReleaseDate": "2017-05-29", 739 | "Dependencies": "qt.tools.qtcreator, qt.59.doc, qt.59.examples", 740 | "Default": "false", 741 | "Script": "installscript.qs", 742 | "SortingPriority": "588", 743 | "DownloadableArchives": "qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtconnectivity-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtactiveqt-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtmultimedia-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qttranslations-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtgraphicaleffects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtsvg-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtdeclarative-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtimageformats-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qttools-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtxmlpatterns-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtsensors-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtwebsockets-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtwebchannel-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtlocation-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtserialport-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtquickcontrols-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtquickcontrols2-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qt3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtcanvas3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtwebview-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtserialbus-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtscxml-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, qtgamepad-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z, d3dcompiler_47-x86.7z, opengl32sw-32-mesa_12_0_rc2.7z", 744 | "CompressedSize": "319.4M", 745 | "UncompressedSize": "2.4G", 746 | "SHA1": "196bea4eea8eef3055cffb4d64a4936bc3070e8e", 747 | "ArchiveSizes": { 748 | "qtxmlpatterns-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "7.0M", 749 | "qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.8M", 750 | "qtwebview-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.5M", 751 | "qtwebsockets-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.5M", 752 | "qtwebchannel-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.1M", 753 | "qttranslations-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.4M", 754 | "qttools-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "30M", 755 | "qtsvg-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "3.0M", 756 | "qtserialport-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "504K", 757 | "qtserialbus-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.1M", 758 | "qtsensors-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.6M", 759 | "qtscxml-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "3.0M", 760 | "qtquickcontrols2-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "13M", 761 | "qtquickcontrols-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "5.5M", 762 | "qtmultimedia-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "12M", 763 | "qtlocation-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "16M", 764 | "qtimageformats-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.7M", 765 | "qtgraphicaleffects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.3M", 766 | "qtgamepad-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "1.3M", 767 | "qtdeclarative-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "49M", 768 | "qtconnectivity-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.4M", 769 | "qtcanvas3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "2.0M", 770 | "qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "95M", 771 | "qtactiveqt-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "5.2M", 772 | "qt3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86.7z": "52M", 773 | "opengl32sw-32-mesa_12_0_rc2.7z": "3.8M", 774 | "d3dcompiler_47-x86.7z": "1.1M" 775 | } 776 | }, 777 | "qt.59.win64_msvc2013_64": { 778 | "Name": "qt.59.win64_msvc2013_64", 779 | "DisplayName": "msvc2013 64-bit", 780 | "Description": "Qt 5.9.0 Prebuilt Components for msvc2013 64-bit", 781 | "Version": "5.9.0-0-201705291821", 782 | "ReleaseDate": "2017-05-29", 783 | "Dependencies": "qt.tools.qtcreator, qt.59.doc, qt.59.examples", 784 | "Default": "false", 785 | "Script": "installscript.qs", 786 | "SortingPriority": "588", 787 | "DownloadableArchives": "qtbase-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtconnectivity-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtactiveqt-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtmultimedia-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qttranslations-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtgraphicaleffects-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtsvg-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtdeclarative-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtwinextras-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtimageformats-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qttools-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtxmlpatterns-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtsensors-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtwebsockets-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtwebchannel-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtlocation-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtserialport-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtquickcontrols-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtquickcontrols2-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qt3d-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtcanvas3d-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtserialbus-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtscxml-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, qtgamepad-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z, d3dcompiler_47-x64.7z, opengl32sw-64-mesa_12_0_rc2.7z", 788 | "CompressedSize": "292.1M", 789 | "UncompressedSize": "2.3G", 790 | "SHA1": "cdc54936453aae4872ce60b6246923ba0f8cec64", 791 | "ArchiveSizes": { 792 | "qtxmlpatterns-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "7.2M", 793 | "qtwinextras-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.7M", 794 | "qtwebsockets-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "1.5M", 795 | "qtwebchannel-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "1.2M", 796 | "qttranslations-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "1.4M", 797 | "qttools-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "28M", 798 | "qtsvg-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "3.0M", 799 | "qtserialport-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "482K", 800 | "qtserialbus-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.1M", 801 | "qtsensors-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.6M", 802 | "qtscxml-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.9M", 803 | "qtquickcontrols2-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "13M", 804 | "qtquickcontrols-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "5.5M", 805 | "qtmultimedia-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "11M", 806 | "qtlocation-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "13M", 807 | "qtimageformats-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.4M", 808 | "qtgraphicaleffects-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "1.3M", 809 | "qtgamepad-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "1.3M", 810 | "qtdeclarative-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "44M", 811 | "qtconnectivity-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.4M", 812 | "qtcanvas3d-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "2.1M", 813 | "qtbase-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "84M", 814 | "qtactiveqt-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "5.1M", 815 | "qt3d-Windows-Windows_8_1-MSVC2013-Windows-Windows_8_1-X86_64.7z": "48M", 816 | "opengl32sw-64-mesa_12_0_rc2.7z": "4.9M", 817 | "d3dcompiler_47-x64.7z": "1.3M" 818 | } 819 | }, 820 | "qt.59.win64_msvc2015_64": { 821 | "Name": "qt.59.win64_msvc2015_64", 822 | "DisplayName": "msvc2015 64-bit", 823 | "Description": "Qt 5.9.0 Prebuilt Components for msvc2015 64-bit", 824 | "Version": "5.9.0-0-201705291821", 825 | "ReleaseDate": "2017-05-29", 826 | "Dependencies": "qt.tools.qtcreator, qt.59.doc, qt.59.examples", 827 | "Default": "false", 828 | "Script": "installscript.qs", 829 | "SortingPriority": "588", 830 | "DownloadableArchives": "qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtconnectivity-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtactiveqt-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtmultimedia-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qttranslations-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtgraphicaleffects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtsvg-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtdeclarative-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtimageformats-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qttools-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtxmlpatterns-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtsensors-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtwebsockets-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtwebchannel-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtlocation-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtserialport-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtquickcontrols-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtquickcontrols2-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qt3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtcanvas3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtwebview-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtserialbus-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtscxml-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, qtgamepad-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z, d3dcompiler_47-x64.7z, opengl32sw-64-mesa_12_0_rc2.7z", 831 | "CompressedSize": "339.7M", 832 | "UncompressedSize": "2.5G", 833 | "SHA1": "fd910b579971cfd983a295bda5bfd298f448042a", 834 | "ArchiveSizes": { 835 | "qtxmlpatterns-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "8.1M", 836 | "qtwinextras-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.9M", 837 | "qtwebview-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.6M", 838 | "qtwebsockets-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.6M", 839 | "qtwebchannel-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.3M", 840 | "qttranslations-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.4M", 841 | "qttools-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "31M", 842 | "qtsvg-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "3.2M", 843 | "qtserialport-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "515K", 844 | "qtserialbus-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.5M", 845 | "qtsensors-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.7M", 846 | "qtscxml-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "3.2M", 847 | "qtquickcontrols2-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "14M", 848 | "qtquickcontrols-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "5.7M", 849 | "qtmultimedia-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "13M", 850 | "qtlocation-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "16M", 851 | "qtimageformats-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.7M", 852 | "qtgraphicaleffects-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.4M", 853 | "qtgamepad-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "1.3M", 854 | "qtdeclarative-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "52M", 855 | "qtconnectivity-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.9M", 856 | "qtcanvas3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "2.1M", 857 | "qtbase-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "100M", 858 | "qtactiveqt-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "5.5M", 859 | "qt3d-Windows-Windows_10-MSVC2015-Windows-Windows_10-X86_64.7z": "57M", 860 | "opengl32sw-64-mesa_12_0_rc2.7z": "4.9M", 861 | "d3dcompiler_47-x64.7z": "1.3M" 862 | } 863 | }, 864 | "qt.59.win64_msvc2017_64": { 865 | "Name": "qt.59.win64_msvc2017_64", 866 | "DisplayName": "msvc2017 64-bit", 867 | "Description": "Qt 5.9.0 Prebuilt Components for msvc2017 64-bit", 868 | "Version": "5.9.0-0-201705291821", 869 | "ReleaseDate": "2017-05-29", 870 | "Dependencies": "qt.tools.qtcreator, qt.59.doc, qt.59.examples", 871 | "Default": "false", 872 | "Script": "installscript.qs", 873 | "SortingPriority": "588", 874 | "DownloadableArchives": "qtbase-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtconnectivity-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtactiveqt-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtmultimedia-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qttranslations-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtgraphicaleffects-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtsvg-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtdeclarative-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtwinextras-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtimageformats-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qttools-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtxmlpatterns-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtsensors-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtwebsockets-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtwebchannel-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtlocation-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtserialport-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtquickcontrols-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtquickcontrols2-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qt3d-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtcanvas3d-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtwebview-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtserialbus-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtscxml-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, qtgamepad-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z, d3dcompiler_47-x64.7z, opengl32sw-64-mesa_12_0_rc2.7z", 875 | "CompressedSize": "345.4M", 876 | "UncompressedSize": "2.5G", 877 | "SHA1": "77f5105a6b22ddeb20dd1c5854a7bb69d07e086d", 878 | "ArchiveSizes": { 879 | "qtxmlpatterns-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "8.3M", 880 | "qtwinextras-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "3.2M", 881 | "qtwebview-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.6M", 882 | "qtwebsockets-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.7M", 883 | "qtwebchannel-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.3M", 884 | "qttranslations-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.4M", 885 | "qttools-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "32M", 886 | "qtsvg-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "3.3M", 887 | "qtserialport-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "535K", 888 | "qtserialbus-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "2.5M", 889 | "qtsensors-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "2.8M", 890 | "qtscxml-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "3.4M", 891 | "qtquickcontrols2-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "14M", 892 | "qtquickcontrols-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "5.8M", 893 | "qtmultimedia-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "13M", 894 | "qtlocation-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "16M", 895 | "qtimageformats-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "2.8M", 896 | "qtgraphicaleffects-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.4M", 897 | "qtgamepad-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "1.4M", 898 | "qtdeclarative-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "52M", 899 | "qtconnectivity-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "3.0M", 900 | "qtcanvas3d-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "2.1M", 901 | "qtbase-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "101M", 902 | "qtactiveqt-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "5.7M", 903 | "qt3d-Windows-Windows_10-MSVC2017-Windows-Windows_10-X86_64.7z": "58M", 904 | "opengl32sw-64-mesa_12_0_rc2.7z": "4.9M", 905 | "d3dcompiler_47-x64.7z": "1.3M" 906 | } 907 | } 908 | } --------------------------------------------------------------------------------