Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡ Optimize package size: Avoid bundling chrome-driver and chrome-headless-shell #1698

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
0216143
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 16, 2024
a97f7f1
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 17, 2024
85e3ca7
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 17, 2024
49f9384
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 17, 2024
4a3f8e9
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 18, 2024
8f47343
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 18, 2024
640e1db
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 18, 2024
32af997
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
620e6bc
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
d0660e1
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
9209fa0
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
39f5943
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
4b2a1ae
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
6b5f765
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
c6141ef
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
ae6112a
:zap: Optimize package size: Avoid bundling chrome-driver and chrome-…
guiyanakuang Aug 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/scripts/updateKnownGoodVersionsWithDownloads.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const fs = require('fs');
const axios = require('axios');

function convertUrl(url) {
const match = url.match(/\/(\d+\.\d+\.\d+\.\d+)\/(.+)\/(.+\.zip)/);
if (match) {
const [, version, platform, filename] = match;
return `https://cdn.npmmirror.com/binaries/chrome-for-testing/${version}/${platform}/${filename}`;
}
return url;
}

function processJson(inputJson) {
const processedJson = JSON.parse(JSON.stringify(inputJson));

processedJson.versions.forEach(version => {
if (version.downloads && version.downloads.chromedriver) {
version.downloads.chromedriver.forEach(item => {
item.url = convertUrl(item.url);
});
}
if (version.downloads) {
version.downloads = { chromedriver: version.downloads.chromedriver || [] };
}
});

return processedJson;
}

async function fetchAndProcessJson() {
const url = "https://raw.githubusercontent.com/GoogleChromeLabs/chrome-for-testing/main/data/known-good-versions-with-downloads.json";

try {
console.log(`Fetching JSON from: ${url}`);
const response = await axios.get(url, { timeout: 10000 });
console.log(`Status Code: ${response.status}`);

const inputJson = response.data;
const processedJson = processJson(inputJson);

fs.writeFileSync('known-good-versions-with-downloads.json', JSON.stringify(processedJson, null, 2));
console.log("JSON processing complete. Output saved to known-good-versions-with-downloads.json");
} catch (error) {
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.error(`HTTP error! status: ${error.response.status}`);
} else if (error.request) {
// The request was made but no response was received
console.error('No response received:', error.message);
} else {
// Something happened in setting up the request that triggered an Error
console.error('Error:', error.message);
}
throw error;
}
}

// If the script is run directly, execute the processing
if (require.main === module) {
fetchAndProcessJson().catch(error => {
console.error("Script failed:", error);
process.exit(1);
});
}

module.exports = { processJson, fetchAndProcessJson };
17 changes: 15 additions & 2 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,20 @@ jobs:
node-version: '16'

- name: Install dependencies
run: npm install semver fs-extra
run: npm install semver fs-extra axios

- name: Update known-good-versions-with-downloads.json
run: node .github/scripts/updateKnownGoodVersionsWithDownloads.js

- name: Upload known-good-versions-with-downloads.json
id: upload_release_app
uses: CrossPaste/oss-upload-action@main
with:
key-id: ${{ secrets.ALIYUN_ACCESSKEY_ID }}
key-secret: ${{ secrets.ALIYUN_ACCESSKEY_SECRET }}
region: oss-cn-shenzhen
bucket: crosspaste-desktop
assets: known-good-versions-with-downloads.json:known-good-versions-with-downloads.json

- name: Validate and update version
run: node .github/scripts/validateAndUpdateVersion.js
Expand Down Expand Up @@ -188,7 +201,7 @@ jobs:

- name: Upload release app
id: upload_release_app
uses: JohnGuan/oss-upload-action@main
uses: CrossPaste/oss-upload-action@main
with:
key-id: ${{ secrets.ALIYUN_ACCESSKEY_ID }}
key-secret: ${{ secrets.ALIYUN_ACCESSKEY_SECRET }}
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ development.properties
local.properties
local.conveyor.conf
package*.json
selenium-manager
selenium-manager.exe
!src/**/build/
build
buildSrc/build/
Expand All @@ -17,8 +19,6 @@ composeApp/GPUCache/
composeApp/build/
composeApp/dylib/
composeApp/jbr/
chrome-headless-shell-*/
chromedriver-*/
logs/
node_modules/
output*/
124 changes: 74 additions & 50 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.constructor.Constructor
import java.io.FileReader
import java.util.Properties
import java.util.zip.ZipFile

val versionProperties = Properties()
versionProperties.load(
Expand Down Expand Up @@ -265,6 +266,12 @@ compose.desktop {
}
}

val seleniumManagerJar: File =
configurations.detachedConfiguration(dependencies.create("org.seleniumhq.selenium:selenium-manager:4.23.1"))
.resolve().first()

extract(seleniumManagerJar, appResourcesRootDir.get().asFile)

// Add download info of jbr on all platforms
val jbrYamlFile = project.projectDir.toPath().resolve("jbr.yaml").toFile()
val jbrReleases = loadJbrReleases(jbrYamlFile)
Expand All @@ -273,11 +280,6 @@ compose.desktop {
jbrDir.mkdirs()
}

// Add download info of chrome-driver and chrome-headless-shell on all platforms
val webDriverProperties = Properties()
val webDriverFile = project.projectDir.toPath().resolve("webDriver.properties").toFile()
webDriverProperties.load(FileReader(webDriverFile))

if (os.isMacOsX || buildFullPlatform) {
targetFormats(TargetFormat.Dmg)

Expand Down Expand Up @@ -305,26 +307,18 @@ compose.desktop {
val result = process.inputStream.bufferedReader().use { it.readText() }.trim()

if (result == "x86_64" || buildFullPlatform) {
getAllDependencies(
getJbrReleases(
"osx-x64",
jbrReleases,
jbrDir,
webDriverProperties,
appResourcesRootDir.get(),
"osx-x64",
"mac-x64",
"macos-x64",
)
}

if (result == "arm64" || buildFullPlatform) {
getAllDependencies(
getJbrReleases(
"osx-aarch64",
jbrReleases,
jbrDir,
webDriverProperties,
appResourcesRootDir.get(),
"osx-aarch64",
"mac-arm64",
"macos-arm64",
)
}
}
Expand All @@ -337,14 +331,10 @@ compose.desktop {
val architecture = System.getProperty("os.arch")

if (architecture.contains("64")) {
getAllDependencies(
getJbrReleases(
"windows-x64",
jbrReleases,
jbrDir,
webDriverProperties,
appResourcesRootDir.get(),
"windows-x64",
"win64",
"windows-x64",
)
} else {
throw IllegalArgumentException("Unsupported architecture: $architecture")
Expand All @@ -356,14 +346,10 @@ compose.desktop {
linux {
targetFormats(TargetFormat.Deb)

getAllDependencies(
getJbrReleases(
"linux-x64",
jbrReleases,
jbrDir,
webDriverProperties,
appResourcesRootDir.get(),
"linux-x64",
"linux64",
"linux-x64",
)
}
}
Expand Down Expand Up @@ -391,27 +377,6 @@ configurations.all {
}
}

fun getAllDependencies(
jbrReleases: JbrReleases,
jbrDir: File,
webDriverProperties: Properties,
chromeDir: Directory,
jbrArch: String,
chromeArch: String,
chromeDirName: String,
) {
getJbrReleases(
jbrArch,
jbrReleases,
jbrDir,
)
getChromeDriver(
chromeArch,
webDriverProperties,
chromeDir.dir(chromeDirName),
)
}

fun getJbrReleases(
arch: String,
jbrReleases: JbrReleases,
Expand Down Expand Up @@ -484,6 +449,23 @@ fun loadJbrReleases(file: File): JbrReleases {
}
}

fun extractFile(
zip: ZipFile,
entry: java.util.zip.ZipEntry,
targetDir: Directory,
) {
val targetFile = targetDir.file(entry.name.substringAfterLast("/"))
targetFile.asFile.parentFile.mkdirs()
zip.getInputStream(entry).use { input ->
targetFile.asFile.outputStream().use { output ->
input.copyTo(output)
}
}
// Make the file executable
targetFile.asFile.setExecutable(true, false)
println("Extracted: ${targetFile.asFile.absolutePath}")
}

data class JbrReleases(
var jbr: Map<String, JbrDetails> = mutableMapOf(),
)
Expand All @@ -492,3 +474,45 @@ data class JbrDetails(
var url: String = "",
var sha512: String = "",
)

fun extract(
jar: File,
outDir: File,
) {
ZipFile(jar).use { zip ->
zip.entries().asSequence().forEach { entry ->
when (entry.name) {
"org/openqa/selenium/manager/linux/selenium-manager" -> {
extractFile(zip, entry, outDir.resolve("linux-x64"))
}
"org/openqa/selenium/manager/macos/selenium-manager" -> {
extractFile(zip, entry, outDir.resolve("macos-x64"))
extractFile(zip, entry, outDir.resolve("macos-arm64"))
}
"org/openqa/selenium/manager/windows/selenium-manager.exe" -> {
extractFile(zip, entry, outDir.resolve("windows-x64"))
}
}
}
}
}

fun extractFile(
zip: ZipFile,
entry: java.util.zip.ZipEntry,
targetDir: File,
) {
val targetFile = targetDir.resolve(entry.name.substringAfterLast("/"))
targetFile.parentFile.mkdirs()
if (!targetFile.exists() || targetFile.lastModified() < entry.lastModifiedTime.toMillis()) {
zip.getInputStream(entry).use { input ->
targetFile.outputStream().use { output ->
input.copyTo(output)
}
}
targetFile.setExecutable(true, false)
println("Extracted: ${targetFile.absolutePath}")
} else {
println("Skipped (up to date): ${targetFile.absolutePath}")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ enum class AppFileType {
USER,
LOG,
ENCRYPT,
MODULE,
DATA,
HTML,
ICON, // use for app icon
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.crosspaste.paste
package com.crosspaste.html

interface ChromeService {

var startSuccess: Boolean

fun html2Image(html: String): ByteArray?

fun quit()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.crosspaste.image

import com.crosspaste.utils.Loader
import okio.Path

interface ImageLoader<T, R> {
interface FaviconLoader : Loader<String, Path>

fun load(value: T): R?
}

interface FaviconLoader : ImageLoader<String, Path>

interface FileExtImageLoader : ImageLoader<Path, Path>
interface FileExtImageLoader : Loader<Path, Path>

interface ThumbnailLoader : ImageLoader<Path, Path> {
interface ThumbnailLoader : Loader<Path, Path> {

// Based on the original path, calculate the thumbnail path
fun getThumbnailPath(path: Path): Path
Expand Down
Loading
Loading