diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index dd31ba3f..dd0dba45 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -68,6 +68,18 @@ jobs: run: brew install gtk4 pkg-config if: matrix.os == 'macos-latest' + - name: Install cargo-wix (Windows) + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-wix + if: matrix.os == 'windows-latest' + + - name: Install cargo-license (Windows) + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: cargo-license + if: matrix.os == 'windows-latest' + - name: Install dependencies (Windows) uses: lukka/run-vcpkg@v11 with: @@ -99,10 +111,41 @@ jobs: with: run: cargo test - - uses: actions/upload-artifact@v2 + - name: Compile glib schemas (Windows) + run: | + & "$env:VCPKG_INSTALLED_DIR/x64-windows/tools/glib/glib-compile-schemas.exe" "$env:VCPKG_INSTALLED_DIR/x64-windows/share/glib-2.0/schemas" + if: matrix.os == 'windows-latest' + + - name: Gather licenses (Windows) + run: | + pip install license-expression + python wix/rust_licenses.py > wix/LICENSE-static-libraries.txt + python wix/vcpkg_licenses.py > wix/LICENSE-dynamic-libraries.txt + if: matrix.os == 'windows-latest' + + - name: Generate components (Windows) + run: | + python wix/generate_components.py + if: matrix.os == 'windows-latest' + + - name: Build installer (Windows) + run: cargo wix --no-build --nocapture -v + if: matrix.os == 'windows-latest' + + - name: Upload binary + uses: actions/upload-artifact@v2 with: - name: Packetry ${{ matrix.os }} + name: Binary for ${{ matrix.os }} path: | target/release/packetry target/release/packetry.exe + if-no-files-found: error + - name: Upload installer (Windows) + uses: actions/upload-artifact@v2 + with: + name: Windows installer + path: | + target/wix/*.msi + if-no-files-found: error + if: runner.os == 'Windows' diff --git a/.gitignore b/.gitignore index e328fab3..7429e4bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ /target /tests/*/output.txt /tests/ui/*/output.txt +/wix/full-licenses +/wix/dll-components.wxi +/wix/dll-references.wxi +/wix/license-components.wxi +/wix/license-references.wxi +/wix/LICENSE-packetry.txt +/wix/LICENSE-static-libraries.txt +/wix/LICENSE-dynamic-libraries.txt +/vcpkg diff --git a/Cargo.lock b/Cargo.lock index 06164f23..f1cc659e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,12 +75,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bisection" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e079a1bab0ecce6cf4b4b74c0c37afa4a697136eb3b127875c84a8f04a8c3" - [[package]] name = "bitfield" version = "0.14.0" @@ -99,12 +93,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" -[[package]] -name = "bufreaderwriter" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece5ad97cde626d9fb807bf2dd4b4c4d13d7317a93a2ee0f8f9ef6389850a49e" - [[package]] name = "bytemuck" version = "1.16.0" @@ -969,9 +957,7 @@ version = "0.1.0" dependencies = [ "anyhow", "arc-swap", - "bisection", "bitfield", - "bufreaderwriter", "bytemuck", "bytemuck_derive", "ctor", diff --git a/Cargo.toml b/Cargo.toml index bb3b98b2..30efe28e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ include = [ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bufreaderwriter = "0.2.4" bytemuck = "1.14.1" bytemuck_derive = "1.5.0" gtk = { version = "0.8.0", package = "gtk4" } @@ -35,7 +34,6 @@ tempfile = "3.9.0" bitfield = "0.14.0" num-format = "0.4.4" humansize = "2.1.3" -bisection = "0.1.0" derive_more = "0.99.17" nusb = "0.1.9" futures-lite = "2.0.1" diff --git a/LICENSE b/LICENSE index fbc2a37d..ccd94375 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2022, Great Scott Gadgets +Copyright (c) 2022-2024, Great Scott Gadgets All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/src/backend/cynthion.rs b/src/backend/cynthion.rs index 76a6264e..ac6eb82d 100644 --- a/src/backend/cynthion.rs +++ b/src/backend/cynthion.rs @@ -416,7 +416,7 @@ impl CynthionQueue { async fn process(&mut self, mut stop: oneshot::Receiver<()>) -> Result<(), Error> { - use TransferError::Cancelled; + use TransferError::{Cancelled, Unknown}; loop { select_biased!( _ = stop => { @@ -434,7 +434,13 @@ impl CynthionQueue { self.queue.submit(RequestBuffer::new(READ_LEN)); } }, - Err(Cancelled) if stop.is_terminated() => { + // + // As of nusb 0.1.9, TransferError::Unknown may be + // returned instead of TransferError::Cancelled when + // Windows returns ERROR_OPERATION_ABORTED. This should + // be fixed in a future nusb release; see nusb PR #63. + // + Err(Cancelled | Unknown) if stop.is_terminated() => { // Transfer cancelled during shutdown. Drop it. drop(completion); if self.queue.pending() == 0 { diff --git a/src/compact_index.rs b/src/compact_index.rs index 030d965e..0f36f40e 100644 --- a/src/compact_index.rs +++ b/src/compact_index.rs @@ -7,7 +7,6 @@ use std::sync::atomic::{AtomicU64, Ordering::{Acquire, Release}}; use std::sync::Arc; use anyhow::{Error, bail}; -use bisection::bisect_left; use itertools::multizip; use crate::data_stream::{data_stream, DataReader, DataWriter}; @@ -382,8 +381,17 @@ where values.push(base_value + delta); } // Bisect the values to find the position. - let offset = bisect_left(&values, value) as u64; - let position = delta_range.start + offset; + let mut lower_bound = 0; + let mut upper_bound = values.len(); + while lower_bound < upper_bound { + let midpoint = (lower_bound + upper_bound) / 2; + if &values[midpoint] < value { + lower_bound = midpoint + 1; + } else { + upper_bound = midpoint; + } + } + let position = delta_range.start + lower_bound as u64; Ok(position) } } diff --git a/src/index_stream.rs b/src/index_stream.rs index 0ea3b404..8aaa3935 100644 --- a/src/index_stream.rs +++ b/src/index_stream.rs @@ -3,7 +3,6 @@ use std::marker::PhantomData; use std::ops::Range; use anyhow::Error; -use bisection::{bisect_left, bisect_right}; use crate::data_stream::{data_stream, DataReader, DataWriter}; use crate::id::Id; @@ -173,7 +172,17 @@ where Position: Copy + From + Into, midpoint = (block_end + search_end) / 2 } } else { - break block_start + bisect_left(&block_values, &value) as u64; + let mut lower_bound = 0; + let mut upper_bound = block_values.len(); + while lower_bound < upper_bound { + let midpoint = (lower_bound + upper_bound) / 2; + if block_values[midpoint] < value { + lower_bound = midpoint + 1; + } else { + upper_bound = midpoint; + } + } + break block_start + lower_bound as u64; }; }; Ok(Position::from(position)) @@ -217,7 +226,17 @@ where Position: Copy + From + Into, midpoint = block_end + length_after / 2; } } else { - break block_start + bisect_right(&block_values, &value) as u64; + let mut lower_bound = 0; + let mut upper_bound = block_values.len(); + while lower_bound < upper_bound { + let midpoint = (lower_bound + upper_bound) / 2; + if value < block_values[midpoint] { + upper_bound = midpoint; + } else { + lower_bound = midpoint + 1; + } + } + break block_start + lower_bound as u64; }; }; Ok(Position::from(position)) diff --git a/wix/generate_components.py b/wix/generate_components.py new file mode 100644 index 00000000..f769b955 --- /dev/null +++ b/wix/generate_components.py @@ -0,0 +1,50 @@ +from contextlib import redirect_stdout +import os + +dll_components = open('wix/dll-components.wxi', 'w') +dll_references = open('wix/dll-references.wxi', 'w') +license_components = open('wix/license-components.wxi', 'w') +license_references = open('wix/license-references.wxi', 'w') + +output_files = [ + dll_components, + dll_references, + license_components, + license_references +] + +def component_name(filename): + return filename.replace('-', '_').replace('+', '_') + +for file in output_files: + print("", file=file) + +bin_dir = '$(env.VCPKG_INSTALLED_DIR)/x64-windows/bin' + +for line in open('wix/required-dlls.txt', 'r'): + filename, guid = line.rstrip().split(' ') + component = component_name(filename) + with redirect_stdout(dll_components): + print(f" ") + print(f" ") + print(f" ") + with redirect_stdout(dll_references): + print(f" ") + +for filename in os.listdir('wix/full-licenses'): + component = component_name(filename) + with redirect_stdout(license_components): + print(f" ") + print(f" ") + print(f" ") + with redirect_stdout(license_references): + print(f" ") + +for file in output_files: + print("", file=file) diff --git a/wix/main.wxs b/wix/main.wxs new file mode 100644 index 00000000..7b5d3230 --- /dev/null +++ b/wix/main.wxs @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + + + + + + + + + + diff --git a/wix/manual-licenses/LICENSE-byteorder_slice-3.0.0.txt b/wix/manual-licenses/LICENSE-byteorder_slice-3.0.0.txt new file mode 100644 index 00000000..f6ad48b3 --- /dev/null +++ b/wix/manual-licenses/LICENSE-byteorder_slice-3.0.0.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2022 courvoif + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-convert_case-0.4.0.txt b/wix/manual-licenses/LICENSE-convert_case-0.4.0.txt new file mode 100644 index 00000000..aea2ac60 --- /dev/null +++ b/wix/manual-licenses/LICENSE-convert_case-0.4.0.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 David Purdum + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-derive-into-owned-0.2.0.txt b/wix/manual-licenses/LICENSE-derive-into-owned-0.2.0.txt new file mode 100644 index 00000000..010bc4b6 --- /dev/null +++ b/wix/manual-licenses/LICENSE-derive-into-owned-0.2.0.txt @@ -0,0 +1,7 @@ +Copyright 2022 Joonas Koivunen and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-kernel32-sys-0.2.2.txt b/wix/manual-licenses/LICENSE-kernel32-sys-0.2.2.txt new file mode 100644 index 00000000..60d12ac7 --- /dev/null +++ b/wix/manual-licenses/LICENSE-kernel32-sys-0.2.2.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Atashian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-ryu-1.0.18.txt b/wix/manual-licenses/LICENSE-ryu-1.0.18.txt new file mode 100644 index 00000000..36b7cd93 --- /dev/null +++ b/wix/manual-licenses/LICENSE-ryu-1.0.18.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-winapi-build-0.1.1.txt b/wix/manual-licenses/LICENSE-winapi-build-0.1.1.txt new file mode 100644 index 00000000..60d12ac7 --- /dev/null +++ b/wix/manual-licenses/LICENSE-winapi-build-0.1.1.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Atashian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-winapi-i686-pc-windows-gnu-0.4.0.txt b/wix/manual-licenses/LICENSE-winapi-i686-pc-windows-gnu-0.4.0.txt new file mode 100644 index 00000000..60d12ac7 --- /dev/null +++ b/wix/manual-licenses/LICENSE-winapi-i686-pc-windows-gnu-0.4.0.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Atashian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-winapi-x86_64-pc-windows-gnu-0.4.0.txt b/wix/manual-licenses/LICENSE-winapi-x86_64-pc-windows-gnu-0.4.0.txt new file mode 100644 index 00000000..60d12ac7 --- /dev/null +++ b/wix/manual-licenses/LICENSE-winapi-x86_64-pc-windows-gnu-0.4.0.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Atashian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wix/manual-licenses/LICENSE-ws2_32-sys-0.2.1.txt b/wix/manual-licenses/LICENSE-ws2_32-sys-0.2.1.txt new file mode 100644 index 00000000..60d12ac7 --- /dev/null +++ b/wix/manual-licenses/LICENSE-ws2_32-sys-0.2.1.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Peter Atashian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/wix/required-dlls.txt b/wix/required-dlls.txt new file mode 100644 index 00000000..1760e518 --- /dev/null +++ b/wix/required-dlls.txt @@ -0,0 +1,48 @@ +atk-1.0-0.dll 5edbbda4-db12-4e43-8f0c-218ebab94d93 +brotlicommon.dll 0be65eb3-8928-4817-925a-5550e666683b +brotlidec.dll a1aa709a-a611-47bf-91d4-2f655270bec5 +brotlienc.dll ef53d54e-d61b-4e7f-8a2b-c8347bd0884e +bz2.dll 4a8a184b-11a9-4493-a709-7d0ec8614f14 +cairo-2.dll d8ce6c10-20fc-4128-a9ac-6ef047cb96e2 +cairo-gobject-2.dll 9992fb8f-f693-4dcd-a387-1f86b4b41aac +cairo-script-interpreter-2.dll 75cc1bb6-d916-4f82-aea3-1179f5eb7ba5 +charset-1.dll 56827d0e-68e1-4e4b-8278-659184d9e570 +epoxy-0.dll 9aeef0ec-6c93-480d-a44c-ced8dfabfb2f +ffi-8.dll 7c63276a-0848-4f46-96fa-8df568a2bb61 +fontconfig-1.dll aa8ad7de-59cc-435c-97cb-e328bbff8460 +freetype.dll 74abc4a2-df13-48bb-8696-96f92a2c0be0 +fribidi-0.dll e462dcd8-2226-4f73-9f7e-d2b3b58eba49 +gdk_pixbuf-2.0-0.dll c24a4c43-def6-4c24-8cb8-54ece1b6bb9c +getopt.dll f7d09e7c-fccc-4558-b478-5f8a3e88e4e4 +gio-2.0-0.dll a91cae44-99b8-4d47-9682-7985abc3bbe1 +glib-2.0-0.dll 9c81fa23-c96b-4802-aab0-3401300d7bc3 +gmodule-2.0-0.dll 6bf333ce-3f3a-49ba-b035-fc952b63725b +gobject-2.0-0.dll 7bc6b550-918a-4d1b-91d9-358f02a242ba +graphene-1.0-0.dll 2874cda9-9885-4495-9763-38a51a37b9d8 +gthread-2.0-0.dll 4c314fb1-7224-48e2-af39-81984fa6c19e +gtk-4-1.dll 6fe10843-e106-4883-bf29-a6a94cd2b1cd +harfbuzz.dll a12abb2a-7edf-40d6-adb2-39cd5a9d8ef8 +harfbuzz-gobject.dll 202cb447-b82f-47c0-9356-c353b675fd3d +harfbuzz-subset.dll 58296888-07a8-4258-9054-5fa089e3c855 +iconv-2.dll 18abffeb-462a-4186-8b8a-0149c8b9f062 +intl-8.dll 628852d1-0ccd-40cc-84f4-ae6fee75db16 +jpeg62.dll 086f589c-d8af-474d-9564-8d65ef6f4401 +libexpat.dll b7c975d0-6e53-49b4-b7ed-c75daad6616e +liblzma.dll abd4caa2-4acd-4ec1-85a1-8d621c672529 +libpng16.dll b489d04b-74d9-4001-b185-0573968a6da2 +pango-1.0-0.dll 9e6b8c45-d189-4b8a-aaa9-1f83c92421c2 +pangocairo-1.0-0.dll fde9897b-09a2-4201-94f7-2284dcc7246f +pangoft2-1.0-0.dll d1b0f76f-747a-4e81-9c98-24c91d7c7e21 +pangowin32-1.0-0.dll 1e350ffc-f0e7-4739-aeb4-2c0f93616259 +pcre2-16.dll 34b8d08a-979f-41be-a894-0ac7ec47e670 +pcre2-32.dll 86190ec9-596b-412b-b005-d24256086457 +pcre2-8.dll 32f1711c-a8f7-4f09-890e-eb3a69347b7d +pcre2-posix.dll c153933b-e57e-432a-9a29-ff8a4889615e +pixman-1-0.dll 1c88f629-1474-4dd5-9b23-7b6dcfb4143c +pthreadVC3.dll 88992acc-c1bd-4d6c-8155-ce1e07cd66af +pthreadVCE3.dll efeab01d-ac1e-42be-8cb1-75b0a419503f +pthreadVSE3.dll 09cc7e5d-ebc3-42bb-9bd9-26a9bdac449e +sass-1.dll e67bbd5b-edf9-4f2b-a04a-241e628ba95f +tiff.dll f181c65d-b7fc-41ab-9fcf-49b3a5996ba3 +turbojpeg.dll 8cfa1139-79e4-4e80-9c76-fbe5d404d9c5 +zlib1.dll e10ca69b-ce5e-4368-bc78-5109ba0e6b75 diff --git a/wix/rust_licenses.py b/wix/rust_licenses.py new file mode 100644 index 00000000..cfde1263 --- /dev/null +++ b/wix/rust_licenses.py @@ -0,0 +1,147 @@ +from license_expression import get_spdx_licensing, LicenseSymbol, OR, AND +from tempfile import TemporaryDirectory +import subprocess +import shutil +import os + +licensing = get_spdx_licensing() + +# We accept these licenses unconditionally. +accepted_license_strings = ( + 'MIT', + 'BSD-3-Clause', + 'BSL-1.0', + 'Unicode-DFS-2016', +) + +# We accept these licenses with manual validation. +conditional_license_strings = ( + # For Apache-2.0, we need to check for NOTICE requirements. + 'Apache-2.0', + 'Apache-2.0 WITH LLVM-exception', +) + +# These packages have been validated for conditionally accepted licenses. +validated = ( + ('target-lexicon', '0.12.14'), + ('unicode-ident', '1.0.12'), +) + +# We don't believe these packages are actually linked into Packetry. +excluded = ( + 'fuchsia-zircon', + 'fuchsia-zircon-sys', +) + +accepted_licenses = [licensing.parse(s) for s in accepted_license_strings] +conditional_licenses = [licensing.parse(s) for s in conditional_license_strings] + +# Validate a license expression is acceptable to us. +def validate_license(package, version, expr): + + # If there is a single license, and it's acceptable, accept it. + if expr in accepted_licenses: + return True + + # If there is a single conditionally accepted license, and we've validated + # it for this specific package version, accept it. + elif expr in conditional_licenses and (package, version) in validated: + return True + + # If the expression is an OR, and some option is acceptable, accept it. + elif isinstance(expr, OR): + for option in expr.get_symbols(): + if validate_license(package, version, option): + return True + else: + return False + + # If the expression is an AND, and all elements are acceptable, accept it. + elif isinstance(expr, AND): + for element in expr.get_symbols(): + if not validate_license(package, version, element): + return False + else: + return True + else: + # Otherwise, return false. + return False + +# Get license information with 'cargo license'. +cargo_result = subprocess.run( + ('cargo', 'license', '--authors', '--do-not-bundle', '--color=never'), + capture_output=True) + +cargo_result.check_returncode() + +# Unpack sources into temporary directory with 'cargo vendor'. +deps = TemporaryDirectory() +subprocess.run( + ('cargo', 'vendor', '--versioned-dirs', deps.name)).check_returncode() + +# Manually collected licenses. +manual_dir = 'wix/manual-licenses' +manual_licenses = os.listdir(manual_dir) + +# Output path for license files. +dest_dir = 'wix/full-licenses' + +try: + os.mkdir(dest_dir) +except FileExistsError: + pass + +print("The following Rust packages are statically linked into Packetry:") + +for line in cargo_result.stdout.decode().rstrip().split("\n"): + package, remainder = line.split(": ") + if package == 'packetry' or package in excluded: + continue + version, license_quoted, by, authors_quoted = remainder.split(", ") + authors = authors_quoted[1:-1].split("|") + license_str = license_quoted[1:-1] + + # Check the license is acceptable for us. + if not validate_license(package, version, licensing.parse(license_str)): + raise ValueError( + f"License '{license_str}' not accepted for {package} {version}.") + + # Where we will write the full license file to. + dest_filename = f'LICENSE-{package}-{version}.txt' + dest_path = os.path.join(dest_dir, dest_filename) + + # Look for a manually collected license. + if dest_filename in manual_licenses: + src_path = os.path.join(manual_dir, dest_filename) + else: + # Look for a license file. + src_filenames = ( + 'LICENSE-MIT', + 'license-mit', + 'LICENSE', + 'LICENSE.md', + ) + src_dir = os.path.join(deps.name, f'{package}-{version}') + src_files = os.listdir(src_dir) + for filename in src_filenames: + if filename in src_files: + src_path = os.path.join(src_dir, filename) + break + else: + raise ValueError( + f"No license file found for {package} {version}.") + + # Copy license file to output. + shutil.copyfile(src_path, dest_path) + + print() + print(f"{package} version {version}") + if len(authors) == 1: + print(f"Author: {str.join(', ', authors)}") + else: + print("Authors:") + for author in authors: + print(f" {author}") + print(f"License type: {license_str}") + print(f"License file: full-licenses/{dest_filename}") + print(f"Link: https://crates.io/crates/{package}") diff --git a/wix/vcpkg_licenses.py b/wix/vcpkg_licenses.py new file mode 100644 index 00000000..adf5f33a --- /dev/null +++ b/wix/vcpkg_licenses.py @@ -0,0 +1,87 @@ +import subprocess +import shutil +import json +import re +import os + +dest_dir = 'wix/full-licenses' + +vcpkg_result = subprocess.run( + ['./vcpkg/vcpkg', 'depend-info', 'gtk', '--triplet=x64-windows'], + capture_output=True) + +vcpkg_result.check_returncode() + +packages = set() + +# Find all packages we depend on. +for line in vcpkg_result.stderr.decode().rstrip().split('\n'): + header, remainder = line.split(': ') + package = header.split('[')[0] + packages.add(package) + dependencies = remainder.split(', ') + packages |= set(dependencies) + +# Discard empty package names. +packages.discard('') + +# Discard vcpkg build tools. +packages = set(p for p in packages if not p.startswith('vcpkg-')) + +# gperf is needed to build fontconfig, but is not linked to. +packages.discard('gperf') + +# gettext is needed to build many dependencies, but is not linked to. +packages.discard('gettext') + +# getopt and pthread are virtual packages. +packages.discard('getopt') +packages.discard('pthread') + +# sassc is used to build GTK, but is not linked to. +packages.discard('sassc') + +versions = {} + +# These packages are missing license information in vcpkg. +licenses = { + 'libiconv': 'LGPL-2.1-or-later', + 'egl-registry': 'Apache-2.0 OR MIT', + 'liblzma': 'BSD-0-Clause', + 'libsass': 'MIT', +} + +# These packages are missing homepage information in vcpkg. +homepages = { + 'fribidi': 'https://github.com/fribidi/fribidi', +} + +for package in packages: + metadata = json.load(open(f'vcpkg/ports/{package}/vcpkg.json')) + version = metadata.get('version-semver', + metadata.get('version', + metadata.get('version-date'))) + if version is None: + raise ValueError(f"Couldn't find a version for package {package}") + versions[package] = version + if metadata.get('homepage') is not None: + homepages[package] = metadata['homepage'] + if metadata.get('license') is not None: + licenses[package] = metadata['license'] + +try: + os.mkdir(dest_dir) +except FileExistsError: + pass + +print("The following libraries are dynamically linked into Packetry:") + +for package in sorted(packages): + license_src = f'vcpkg/installed/x64-windows/share/{package}/copyright' + license_dest = os.path.join(dest_dir, f'LICENSE-{package}.txt') + shutil.copyfile(license_src, license_dest) + print() + print(f"{package} version {versions[package]}") + print(f"Homepage: {homepages[package]}") + print(f"License type: {licenses[package]}") + print(f"License text: {license_dest}")