Files
herolib/lib/develop/gittools/repository_lfs.v
2025-10-13 07:30:12 +04:00

196 lines
5.5 KiB
V

module gittools
import time
import incubaid.herolib.ui.console
import incubaid.herolib.core.texttools
import incubaid.herolib.core
import incubaid.herolib.osal.core as osal
import os
const binary_extensions = ['.pdf', '.docx', '.xlsx', '.pptx', '.zip', '.tar', '.gz', '.jpg', '.jpeg',
'.png', '.gif', '.bmp', '.tiff', '.ico', '.webp', '.mp4', '.mp3', '.avi', '.mov', '.wmv', '.flv',
'.mkv', '.wav', '.exe', '.dll', '.so', '.dylib', '.bin', '.dat', '.iso']
// check if repo has lfs enabled
pub fn (mut repo GitRepo) lfs_check() ! {
repo.init()!
// Get list of all files in the repository
files_result := repo.exec('ls-files')!
files := files_result.split('\n').filter(it.trim_space() != '')
// Binary file extensions that should use LFS
mut needs_lfs := false
mut large_files := []string{}
for file in files {
file_path := '${repo.path()}/${file}'
// Check if file exists (might be deleted)
if !os.exists(file_path) {
continue
}
// Check if file is in bin/ folder
if file.starts_with('bin/') {
needs_lfs = true
large_files << file
continue
}
// Check if file has binary extension
for ext in binary_extensions {
if file.to_lower().ends_with(ext) {
needs_lfs = true
large_files << file
break
}
}
// Check file size (files > 50MB should use LFS)
file_info := os.stat(file_path) or { continue }
size_mb := file_info.size / (1024 * 1024)
if size_mb > 50 {
needs_lfs = true
large_files << '${file} (${size_mb}MB)'
}
}
if needs_lfs {
console.print_header('Repository contains files that should use Git LFS:')
for file in large_files {
console.print_item(file)
}
if !repo.lfs()! {
console.print_stderr('Git LFS is not initialized. Run lfs_init() to set it up.')
}
} else {
console.print_green('No large binary files detected. Git LFS may not be needed.')
}
}
pub fn (mut repo GitRepo) lfs_init() ! {
repo.init()!
// Step 1: Check if git-lfs is installed on the system
if !osal.cmd_exists('git-lfs') {
console.print_header('Git LFS not found. Installing...')
// Install based on platform
platform := core.platform()!
match platform {
.osx {
// Use brew on macOS
if osal.cmd_exists('brew') {
osal.execute_stdout('brew install git-lfs')!
} else {
return error('Homebrew not found. Please install git-lfs manually: https://git-lfs.github.com')
}
}
.ubuntu {
osal.execute_stdout('sudo apt-get update && sudo apt-get install -y git-lfs')!
}
.arch {
osal.execute_stdout('sudo pacman -S git-lfs')!
}
else {
return error('Unsupported platform. Please install git-lfs manually: https://git-lfs.github.com')
}
}
console.print_green('Git LFS installed successfully.')
}
// Step 2: Initialize git-lfs in the repository
console.print_header('Initializing Git LFS in repository...')
repo.exec('lfs install --local')!
console.print_header('Tracking binary file extensions...')
for ext in binary_extensions {
repo.exec('lfs track "*${ext}"') or {
console.print_debug('Could not track ${ext}: ${err}')
continue
}
console.print_item('Tracking *${ext}')
}
// Step 4: Track files in bin/ folders
console.print_header('Tracking bin/ folders...')
repo.exec('lfs track "bin/**"') or { console.print_debug('Could not track bin/**: ${err}') }
// Step 5: Create and install pre-commit hook
mut check_script := '
#!/bin/bash
# Prevent committing large files without LFS
max_size=50 # MB
files=$(git diff --cached --name-only)
for file in \${files}; do
if [ -f "\${file}" ]; then
size=$(du -m "\${file}" | cut -f1)
if [ "\${size}" -gt "\${max_size}" ]; then
if ! git check-attr filter -- "\${file}" | grep -q "lfs"; then
echo " ERROR: \${file} is \${size}MB and not tracked by LFS."
echo "Please run: git lfs track \\"\${file}\\""
exit 1
fi
fi
fi
done
'
check_script = texttools.dedent(check_script)
hook_path := '${repo.path()}/.git/hooks/pre-commit'
hooks_dir := '${repo.path()}/.git/hooks'
// Ensure hooks directory exists
osal.dir_ensure(hooks_dir)!
// Write the pre-commit hook
osal.file_write(hook_path, check_script)!
// Make the hook executable
osal.exec(cmd: 'chmod +x ${hook_path}')!
console.print_green('Pre-commit hook installed at ${hook_path}')
// Step 6: Add .gitattributes to the repository
gitattributes_path := '${repo.path()}/.gitattributes'
if os.exists(gitattributes_path) {
console.print_debug('.gitattributes already exists, LFS tracks have been added to it.')
} else {
console.print_debug('.gitattributes created with LFS tracking rules.')
}
repo.commit('chore: Initialize Git LFS and track binary files')!
repo.push()!
// Step 7: Verify LFS is properly configured
if !repo.lfs()! {
return error('Git LFS initialization failed verification')
}
console.print_green('Git LFS initialized successfully for ${repo.name}')
console.print_header('Next steps:')
}
// Check if repo has lfs enabled
pub fn (mut repo GitRepo) lfs() !bool {
repo.init()!
// Check if .git/hooks/pre-commit exists and contains LFS check
hook_path := '${repo.path()}/.git/hooks/pre-commit'
if !os.exists(hook_path) {
return false
}
// Check if git lfs is initialized locally
// This checks if .git/config contains lfs filter configuration
config_result := repo.exec('config --local --get filter.lfs.clean') or { return false }
return config_result.contains('git-lfs clean')
}