mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-21 03:51:15 -08:00
208 lines
6.1 KiB
TypeScript
208 lines
6.1 KiB
TypeScript
/**
|
|
* Trim unused git commands and components from dugite to reduce package size.
|
|
*
|
|
* dugite bundles a full git distribution, but TidGi only uses a subset of git commands
|
|
* through git-sync-js. Most git-xxx symlinks point to the main 'git' binary and are
|
|
* only needed when directly invoking 'git-add' instead of 'git add'. Since dugite
|
|
* always calls 'git/bin/git' with subcommand arguments, these symlinks are unnecessary.
|
|
*
|
|
* Additionally, Git Credential Manager (.NET runtime) and git-lfs are large components
|
|
* that TidGi doesn't need because:
|
|
* - Credentials are embedded directly in URLs (https://user:token@github.com/...)
|
|
* - LFS is not used for TiddlyWiki wikis
|
|
*
|
|
* This can reduce package size by ~40-60MB depending on platform.
|
|
*/
|
|
import fs from 'fs-extra';
|
|
import path from 'path';
|
|
|
|
/** Unused standalone git commands (shell scripts and binaries) that TidGi doesn't use */
|
|
const UNUSED_GIT_COMMANDS = [
|
|
// CVS/Arch integration (legacy VCS)
|
|
'git-archimport',
|
|
'git-cvsexportcommit',
|
|
'git-cvsimport',
|
|
'git-cvsserver',
|
|
// Server/daemon functionality (desktop app doesn't need)
|
|
'git-daemon',
|
|
'git-http-backend',
|
|
'git-http-fetch',
|
|
'git-http-push',
|
|
'git-shell',
|
|
'git-upload-archive',
|
|
// Email integration (not used)
|
|
'git-imap-send',
|
|
'git-send-email',
|
|
// Web UI (not used)
|
|
'git-instaweb',
|
|
'git-web--browse',
|
|
// Interactive merge tools (TidGi handles conflicts differently)
|
|
'git-difftool--helper',
|
|
'git-mergetool',
|
|
'git-mergetool--lib',
|
|
// Advanced features not used
|
|
'git-filter-branch',
|
|
'git-quiltimport',
|
|
'git-request-pull',
|
|
// Shell helpers (not needed for programmatic use)
|
|
'git-sh-i18n',
|
|
'git-sh-i18n--envsubst',
|
|
'git-sh-setup',
|
|
// Merge strategy scripts (git binary has these built-in)
|
|
'git-merge-octopus',
|
|
'git-merge-one-file',
|
|
'git-merge-resolve',
|
|
// Large repo optimization (TiddlyWiki repos are small)
|
|
'scalar',
|
|
];
|
|
|
|
/** Patterns matching Git Credential Manager and .NET runtime files */
|
|
const GCM_FILE_PATTERNS = [
|
|
/\.dll$/,
|
|
/\.dylib$/,
|
|
/^git-credential-manager/,
|
|
/^gcmcore\./,
|
|
/^createdump$/,
|
|
/^Avalonia\./,
|
|
/^Microsoft\./,
|
|
/^System\./,
|
|
/^GitHub\.dll$/,
|
|
/^GitLab\.dll$/,
|
|
/^Atlassian\./,
|
|
/^HarfBuzzSharp\./,
|
|
/^SkiaSharp\./,
|
|
/^MicroCom\./,
|
|
/^Tmds\./,
|
|
/^netstandard\.dll$/,
|
|
/^mscorlib\.dll$/,
|
|
/^WindowsBase\.dll$/,
|
|
/^NOTICE$/,
|
|
/^uninstall\.sh$/,
|
|
];
|
|
|
|
/**
|
|
* Remove all symlinks from a directory
|
|
* @returns Number of symlinks removed
|
|
*/
|
|
function removeSymlinks(directory: string): number {
|
|
let removed = 0;
|
|
const entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
|
|
for (const entry of entries) {
|
|
if (entry.isSymbolicLink()) {
|
|
const fullPath = path.join(directory, entry.name);
|
|
try {
|
|
fs.unlinkSync(fullPath);
|
|
removed++;
|
|
} catch {
|
|
console.warn(`Failed to remove symlink: ${entry.name}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
return removed;
|
|
}
|
|
|
|
/**
|
|
* Remove a list of files/commands from a directory
|
|
* @returns Object with count and bytes removed
|
|
*/
|
|
function removeFiles(directory: string, files: string[]): { count: number; bytes: number } {
|
|
let count = 0;
|
|
let bytes = 0;
|
|
|
|
for (const file of files) {
|
|
const filePath = path.join(directory, file);
|
|
const filePathExe = path.join(directory, `${file}.exe`);
|
|
|
|
for (const p of [filePath, filePathExe]) {
|
|
if (fs.existsSync(p)) {
|
|
try {
|
|
const stats = fs.statSync(p);
|
|
bytes += stats.size;
|
|
fs.unlinkSync(p);
|
|
count++;
|
|
} catch {
|
|
console.warn(`Failed to remove: ${path.basename(p)}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return { count, bytes };
|
|
}
|
|
|
|
/**
|
|
* Remove files matching patterns from a directory
|
|
* @returns Object with count and bytes removed
|
|
*/
|
|
function removeMatchingFiles(directory: string, patterns: RegExp[]): { count: number; bytes: number } {
|
|
let count = 0;
|
|
let bytes = 0;
|
|
|
|
const entries = fs.readdirSync(directory);
|
|
for (const entry of entries) {
|
|
if (patterns.some(pattern => pattern.test(entry))) {
|
|
const fullPath = path.join(directory, entry);
|
|
try {
|
|
const stats = fs.statSync(fullPath);
|
|
if (stats.isFile()) {
|
|
bytes += stats.size;
|
|
fs.unlinkSync(fullPath);
|
|
count++;
|
|
}
|
|
} catch {
|
|
// Ignore errors
|
|
}
|
|
}
|
|
}
|
|
|
|
return { count, bytes };
|
|
}
|
|
|
|
/**
|
|
* Main function to trim unused git commands from dugite
|
|
*/
|
|
export function trimUnusedGitCommands(dugitePath: string, platform: string): void {
|
|
const gitCoreDirectory = platform === 'win32'
|
|
? path.join(dugitePath, 'git', 'mingw64', 'libexec', 'git-core')
|
|
: path.join(dugitePath, 'git', 'libexec', 'git-core');
|
|
|
|
if (!fs.existsSync(gitCoreDirectory)) {
|
|
console.warn(`git-core directory not found: ${gitCoreDirectory}`);
|
|
return;
|
|
}
|
|
|
|
let totalFilesRemoved = 0;
|
|
let totalBytesRemoved = 0;
|
|
|
|
// 1. Remove all symlinks - they're not needed when using dugite's exec()
|
|
// dugite calls 'git' binary directly with subcommand arguments
|
|
const symlinksRemoved = removeSymlinks(gitCoreDirectory);
|
|
totalFilesRemoved += symlinksRemoved;
|
|
console.log(` Removed ${symlinksRemoved} symlinks`);
|
|
|
|
// 2. Remove unused standalone git commands
|
|
const commandsResult = removeFiles(gitCoreDirectory, UNUSED_GIT_COMMANDS);
|
|
totalFilesRemoved += commandsResult.count;
|
|
totalBytesRemoved += commandsResult.bytes;
|
|
|
|
// 3. Remove Git LFS (13MB) - TiddlyWiki wikis don't use LFS
|
|
const lfsResult = removeFiles(gitCoreDirectory, ['git-lfs']);
|
|
if (lfsResult.count > 0) {
|
|
totalFilesRemoved += lfsResult.count;
|
|
totalBytesRemoved += lfsResult.bytes;
|
|
console.log(` Removed git-lfs (${(lfsResult.bytes / 1024 / 1024).toFixed(0)}MB)`);
|
|
}
|
|
|
|
// 4. Remove Git Credential Manager and .NET runtime (~26MB on macOS)
|
|
// TidGi embeds credentials directly in URLs, so GCM is not needed
|
|
const gcmResult = removeMatchingFiles(gitCoreDirectory, GCM_FILE_PATTERNS);
|
|
if (gcmResult.count > 0) {
|
|
totalFilesRemoved += gcmResult.count;
|
|
totalBytesRemoved += gcmResult.bytes;
|
|
console.log(` Removed Git Credential Manager and .NET runtime (${gcmResult.count} files)`);
|
|
}
|
|
|
|
console.log(` Total: removed ${totalFilesRemoved} files, saved ${(totalBytesRemoved / 1024 / 1024).toFixed(1)}MB`);
|
|
}
|