mirror of
https://github.com/ivuorinen/dotfiles.git
synced 2026-02-04 02:48:39 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
267c54aa56 | ||
|
|
d72409efc0 | ||
| 3d9e0477b0 | |||
| cfab48eee0 | |||
| 624920b2ab | |||
|
|
fd82f1e36c |
45
.gitattributes
vendored
45
.gitattributes
vendored
@@ -1,4 +1,4 @@
|
|||||||
## GITATTRIBUTES FOR WEB PROJECTS
|
## GITATTRIBUTES
|
||||||
#
|
#
|
||||||
# These settings are for any web project.
|
# These settings are for any web project.
|
||||||
#
|
#
|
||||||
@@ -20,20 +20,23 @@
|
|||||||
*.bat text eol=crlf
|
*.bat text eol=crlf
|
||||||
*.cmd text eol=crlf
|
*.cmd text eol=crlf
|
||||||
*.coffee text
|
*.coffee text
|
||||||
*.css text diff=css
|
*.css text diff=css eol=lf
|
||||||
*.htm text diff=html
|
*.fish text diff=shell eol=lf
|
||||||
*.html text diff=html
|
*.htm text diff=html eol=lf
|
||||||
|
*.html text diff=html eol=lf
|
||||||
*.inc text
|
*.inc text
|
||||||
*.ini text
|
*.ini text
|
||||||
*.js text
|
*.js text
|
||||||
*.json text
|
*.json text
|
||||||
*.jsx text
|
*.jsx text
|
||||||
*.less text
|
*.less text
|
||||||
|
*.lua text diff=lua eol=lf
|
||||||
*.ls text
|
*.ls text
|
||||||
*.map text -diff
|
*.map text -diff
|
||||||
*.od text
|
*.od text
|
||||||
*.onlydata text
|
*.onlydata text
|
||||||
*.php text diff=php
|
*.php text diff=php
|
||||||
|
*.plist text eol=lf
|
||||||
*.pl text
|
*.pl text
|
||||||
*.ps1 text eol=crlf
|
*.ps1 text eol=crlf
|
||||||
*.py text diff=python
|
*.py text diff=python
|
||||||
@@ -41,15 +44,18 @@
|
|||||||
*.sass text
|
*.sass text
|
||||||
*.scm text
|
*.scm text
|
||||||
*.scss text diff=css
|
*.scss text diff=css
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf diff=shell
|
||||||
.husky/* text eol=lf
|
.husky/* text eol=lf
|
||||||
*.sql text
|
*.sql text
|
||||||
*.styl text
|
*.styl text
|
||||||
*.tag text
|
*.tag text
|
||||||
|
*.tmux text eol=lf diff=tmux
|
||||||
*.ts text
|
*.ts text
|
||||||
*.tsx text
|
*.tsx text
|
||||||
|
*.vim text eol=lf
|
||||||
*.xml text
|
*.xml text
|
||||||
*.xhtml text diff=html
|
*.xhtml text diff=html
|
||||||
|
*.zsh text diff=zsh eol=lf
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
Dockerfile text
|
Dockerfile text
|
||||||
@@ -68,6 +74,7 @@ Dockerfile text
|
|||||||
AUTHORS text
|
AUTHORS text
|
||||||
CHANGELOG text
|
CHANGELOG text
|
||||||
CHANGES text
|
CHANGES text
|
||||||
|
CODEOWNERS text
|
||||||
CONTRIBUTING text
|
CONTRIBUTING text
|
||||||
COPYING text
|
COPYING text
|
||||||
copyright text
|
copyright text
|
||||||
@@ -105,6 +112,8 @@ TODO text
|
|||||||
*.config text
|
*.config text
|
||||||
.editorconfig text
|
.editorconfig text
|
||||||
.env text
|
.env text
|
||||||
|
*.env text
|
||||||
|
*.env.* text
|
||||||
.gitattributes text
|
.gitattributes text
|
||||||
.gitconfig text
|
.gitconfig text
|
||||||
.htaccess text
|
.htaccess text
|
||||||
@@ -208,15 +217,37 @@ Procfile text
|
|||||||
|
|
||||||
*.gitignore text
|
*.gitignore text
|
||||||
*.gitkeep text
|
*.gitkeep text
|
||||||
.gitattributes export-ignore
|
.gitattributes text export-ignore
|
||||||
|
*.gitattributes text export-ignore
|
||||||
|
.gitmodules text export-ignore
|
||||||
|
*.gitmodules text export-ignore
|
||||||
**/.gitignore export-ignore
|
**/.gitignore export-ignore
|
||||||
**/.gitkeep export-ignore
|
**/.gitkeep export-ignore
|
||||||
|
|
||||||
# Repo specials
|
# Repo specials
|
||||||
local/bin/* text eol=lf
|
local/bin/* text eol=lf diff=shell
|
||||||
|
local/bin/*.md text eol=lf diff=markdown
|
||||||
config/antigen.zsh text
|
config/antigen.zsh text
|
||||||
git/* text
|
git/* text
|
||||||
**/git/* text
|
**/git/* text
|
||||||
**/alias text
|
**/alias text
|
||||||
ssh/* text
|
ssh/* text
|
||||||
|
ssh/shared.d/* text
|
||||||
|
ssh/local.d/* text
|
||||||
|
|
||||||
|
# Auto-generated rules - 2025-04-16 10:28:04
|
||||||
|
# Shell scripts detected by content
|
||||||
|
install text eol=lf diff=shell
|
||||||
|
|
||||||
|
# File extension-based rules
|
||||||
|
*.1 text eol=lf
|
||||||
|
*.applescript text eol=lf
|
||||||
|
*.d/work-git text eol=lf
|
||||||
|
*.dirs text eol=lf
|
||||||
|
*.example text eol=lf
|
||||||
|
*.itermcolors text eol=lf
|
||||||
|
*.locale text eol=lf
|
||||||
|
*.python-version text eol=lf
|
||||||
|
*.snippets text eol=lf
|
||||||
|
*.theme text eol=lf
|
||||||
|
*.yamlfmt text eol=lf
|
||||||
|
|||||||
@@ -49,12 +49,12 @@ repos:
|
|||||||
- id: actionlint
|
- id: actionlint
|
||||||
|
|
||||||
- repo: https://github.com/renovatebot/pre-commit-hooks
|
- repo: https://github.com/renovatebot/pre-commit-hooks
|
||||||
rev: 39.248.1
|
rev: 39.257.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: renovate-config-validator
|
- id: renovate-config-validator
|
||||||
|
|
||||||
- repo: https://github.com/JohnnyMorganz/StyLua
|
- repo: https://github.com/JohnnyMorganz/StyLua
|
||||||
rev: v2.0.2
|
rev: v2.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: stylua # or stylua-system / stylua-github
|
- id: stylua # or stylua-system / stylua-github
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ return {
|
|||||||
-- A collection of small QoL plugins for Neovim
|
-- A collection of small QoL plugins for Neovim
|
||||||
-- https://github.com/folke/snacks.nvim
|
-- https://github.com/folke/snacks.nvim
|
||||||
{
|
{
|
||||||
|
---@module 'snacks'
|
||||||
'folke/snacks.nvim',
|
'folke/snacks.nvim',
|
||||||
priority = 1000,
|
priority = 1000,
|
||||||
lazy = false,
|
lazy = false,
|
||||||
@@ -42,6 +43,7 @@ return {
|
|||||||
-- replaces the UI for messages, cmdline and the popupmenu.
|
-- replaces the UI for messages, cmdline and the popupmenu.
|
||||||
-- https://github.com/folke/noice.nvim
|
-- https://github.com/folke/noice.nvim
|
||||||
{
|
{
|
||||||
|
---@module 'noice'
|
||||||
'folke/noice.nvim',
|
'folke/noice.nvim',
|
||||||
event = 'VeryLazy',
|
event = 'VeryLazy',
|
||||||
dependencies = {
|
dependencies = {
|
||||||
@@ -122,10 +124,12 @@ return {
|
|||||||
-- trouble your code is causing.
|
-- trouble your code is causing.
|
||||||
-- https://github.com/folke/trouble.nvim
|
-- https://github.com/folke/trouble.nvim
|
||||||
{
|
{
|
||||||
|
---@module 'trouble'
|
||||||
'folke/trouble.nvim',
|
'folke/trouble.nvim',
|
||||||
lazy = false,
|
lazy = false,
|
||||||
cmd = 'Trouble',
|
cmd = 'Trouble',
|
||||||
dependencies = { 'nvim-tree/nvim-web-devicons' },
|
dependencies = { 'nvim-tree/nvim-web-devicons' },
|
||||||
|
---@type trouble.Config
|
||||||
opts = {
|
opts = {
|
||||||
auto_preview = true,
|
auto_preview = true,
|
||||||
auto_fold = true,
|
auto_fold = true,
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ if-shell '[ "$DEBUG" = "1" ]' 'set -g debug-file ~/.cache/tmux-debug.log'
|
|||||||
|
|
||||||
set -g pane-active-border-style "fg=#7aa2f7"
|
set -g pane-active-border-style "fg=#7aa2f7"
|
||||||
set -g pane-border-style "fg=#3b4261"
|
set -g pane-border-style "fg=#3b4261"
|
||||||
|
set -g status-style "bg=default"
|
||||||
set -g status-justify "left"
|
set -g status-justify "left"
|
||||||
set -g status-left ''
|
set -g status-left ''
|
||||||
set -g status-left-length "0"
|
set -g status-left-length "0"
|
||||||
|
|||||||
@@ -17,16 +17,31 @@ config.font = wezterm.font_with_fallback {
|
|||||||
'JetBrains Mono',
|
'JetBrains Mono',
|
||||||
'Symbols Nerd Font Mono',
|
'Symbols Nerd Font Mono',
|
||||||
}
|
}
|
||||||
config.harfbuzz_features = { 'zero', 'ss01', 'cv05' }
|
config.font_shaper = 'Harfbuzz'
|
||||||
|
config.harfbuzz_features = { 'calt=1', 'clig=1', 'liga=1' }
|
||||||
|
|
||||||
-- Make the window a bit transparent
|
config.selection_word_boundary = ' \t\n{[}]()"\'`,;:'
|
||||||
config.window_background_opacity = 0.96
|
|
||||||
|
-- Window configuration
|
||||||
|
config.window_background_opacity = 0.95
|
||||||
|
config.window_decorations = 'RESIZE'
|
||||||
|
config.macos_window_background_blur = 10
|
||||||
|
config.window_padding = {
|
||||||
|
left = 5,
|
||||||
|
right = 5,
|
||||||
|
top = 5,
|
||||||
|
bottom = 5,
|
||||||
|
}
|
||||||
|
|
||||||
-- Don't show tab bar
|
-- Don't show tab bar
|
||||||
config.enable_tab_bar = false
|
config.enable_tab_bar = false
|
||||||
|
|
||||||
-- Fix alt on macOS
|
-- Fix alt on macOS
|
||||||
config.send_composed_key_when_left_alt_is_pressed = true
|
config.send_composed_key_when_left_alt_is_pressed = true
|
||||||
|
config.send_composed_key_when_right_alt_is_pressed = true
|
||||||
|
|
||||||
|
-- Scrolling deactivated, using tmux for that
|
||||||
|
config.scrollback_lines = 0
|
||||||
|
|
||||||
-- Function to detect the theme based on appearance
|
-- Function to detect the theme based on appearance
|
||||||
function Scheme_for_appearance(appearance)
|
function Scheme_for_appearance(appearance)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"assistant": {
|
"assistant": {
|
||||||
"default_model": {
|
"default_model": {
|
||||||
"provider": "copilot_chat",
|
"provider": "copilot_chat",
|
||||||
"model": "claude-3-7-sonnet"
|
"model": "claude-3.7-sonnet-thought"
|
||||||
},
|
},
|
||||||
"version": "2"
|
"version": "2"
|
||||||
},
|
},
|
||||||
|
|||||||
675
local/bin/git-attributes
Executable file
675
local/bin/git-attributes
Executable file
@@ -0,0 +1,675 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Check git repo's files .gitattributes and ensure all of them are mapped.
|
||||||
|
#
|
||||||
|
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2022
|
||||||
|
# License: MIT
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Default configuration
|
||||||
|
VERBOSE=0
|
||||||
|
CHECK_PATTERN="text: auto"
|
||||||
|
EXIT_ON_MISSING=0
|
||||||
|
SUGGEST_RULES=1 # Suggestions enabled by default
|
||||||
|
WRITE_RULES=0 # Writing to file is opt-in
|
||||||
|
FORMAT_WIDTH=0 # Auto-width by default (0 means auto)
|
||||||
|
MIN_FORMAT_WIDTH=20 # Minimum format width
|
||||||
|
|
||||||
|
DEBUG="${DEBUG:-0}"
|
||||||
|
|
||||||
|
if [ "$DEBUG" -eq 1 ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output functions
|
||||||
|
msg_err() {
|
||||||
|
echo -e "\e[31m$@\e[0m" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_success() {
|
||||||
|
echo -e "\e[32m$@\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_warn() {
|
||||||
|
echo -e "\e[33m$@\e[0m" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_info() {
|
||||||
|
echo -e "\e[36m$@\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_debug() {
|
||||||
|
[[ $VERBOSE -eq 1 ]] && echo -e "\e[35m$@\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_help() {
|
||||||
|
cat << EOF
|
||||||
|
Usage: $(basename "$0") [OPTIONS]
|
||||||
|
|
||||||
|
Check if all git-tracked files have corresponding rules in .gitattributes
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help Display this help message
|
||||||
|
-v, --verbose Enable verbose output
|
||||||
|
-e, --exit Exit with error code if missing attributes found
|
||||||
|
-p, --pattern Pattern to check (default: "text: auto")
|
||||||
|
-n, --no-suggest Don't suggest .gitattributes rules (suggestions are on by default)
|
||||||
|
-w, --write Write suggested rules to .gitattributes file
|
||||||
|
-f, --format-width Specify width for formatting rule patterns (default: auto, min: $MIN_FORMAT_WIDTH)
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help)
|
||||||
|
show_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
VERBOSE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-e|--exit)
|
||||||
|
EXIT_ON_MISSING=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-p|--pattern)
|
||||||
|
CHECK_PATTERN="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-n|--no-suggest)
|
||||||
|
SUGGEST_RULES=0
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-w|--write)
|
||||||
|
WRITE_RULES=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-f|--format-width)
|
||||||
|
if [[ $2 =~ ^[0-9]+$ ]]; then
|
||||||
|
FORMAT_WIDTH=$2
|
||||||
|
shift 2
|
||||||
|
else
|
||||||
|
msg_err "Error: --format-width requires a numeric argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
msg_err "Unknown option: $1"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Function to check if git is installed
|
||||||
|
check_git_installed() {
|
||||||
|
if ! command -v git &> /dev/null; then
|
||||||
|
msg_err "git could not be found, please install it first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if we're in a git repository
|
||||||
|
check_git_repo() {
|
||||||
|
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
||||||
|
msg_err "Not inside a git repository"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if we're in the git root directory
|
||||||
|
check_git_root() {
|
||||||
|
local git_root
|
||||||
|
git_root=$(git rev-parse --show-toplevel)
|
||||||
|
local current_dir
|
||||||
|
current_dir=$(pwd)
|
||||||
|
|
||||||
|
if [[ "$git_root" != "$current_dir" ]]; then
|
||||||
|
msg_err "Not in git repository root directory"
|
||||||
|
msg_warn "Please run this command from: $git_root"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if .gitattributes exists
|
||||||
|
check_gitattributes_exists() {
|
||||||
|
if [[ ! -f ".gitattributes" ]]; then
|
||||||
|
msg_err ".gitattributes file not found in the repository root"
|
||||||
|
msg_warn "Create a .gitattributes file before running this command"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Format rule with proper alignment
|
||||||
|
format_rule() {
|
||||||
|
local pattern="$1"
|
||||||
|
local attributes="$2"
|
||||||
|
local width="$3"
|
||||||
|
|
||||||
|
# If pattern starts with "#", it's a comment, don't format
|
||||||
|
if [[ "$pattern" == "#"* ]]; then
|
||||||
|
echo "$pattern"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If pattern is empty, return empty
|
||||||
|
if [[ -z "$pattern" ]]; then
|
||||||
|
echo ""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%-${width}s %s\n" "$pattern" "$attributes"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the file extension properly, handling special cases
|
||||||
|
get_file_extension() {
|
||||||
|
local file="$1"
|
||||||
|
local basename=$(basename "$file")
|
||||||
|
local extension=""
|
||||||
|
|
||||||
|
# Check if file has no extension or is a dotfile
|
||||||
|
if [[ "$basename" == .* && ! "$basename" =~ \..+$ ]]; then
|
||||||
|
# It's a dotfile without extension (like .gitignore)
|
||||||
|
extension="$basename"
|
||||||
|
elif [[ "$basename" =~ \..+$ ]]; then
|
||||||
|
# Normal file with extension
|
||||||
|
extension="${basename##*.}"
|
||||||
|
|
||||||
|
# Check for special cases like .d/ directories
|
||||||
|
if [[ "$extension" == "d" ]]; then
|
||||||
|
# This is likely a .d directory - use the full filename as pattern
|
||||||
|
if [[ -f "$file" ]]; then
|
||||||
|
# For files in .d directories, use the complete path as pattern
|
||||||
|
extension=$(basename "$file")
|
||||||
|
else
|
||||||
|
# For .d directory itself, use *.d
|
||||||
|
extension="d"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No extension at all
|
||||||
|
extension="$basename"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$extension"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Suggest appropriate gitattributes rules based on file extension
|
||||||
|
suggest_rule() {
|
||||||
|
local file="$1"
|
||||||
|
local extension=""
|
||||||
|
local pattern=""
|
||||||
|
local attributes=""
|
||||||
|
|
||||||
|
msg_debug "Checking file: $file"
|
||||||
|
|
||||||
|
# Skip directories
|
||||||
|
if [[ -d "$file" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get proper file extension
|
||||||
|
extension=$(get_file_extension "$file")
|
||||||
|
|
||||||
|
# If file path contains .d/ pattern, we need special handling
|
||||||
|
if [[ "$file" =~ \.d/ ]]; then
|
||||||
|
# Extract the pattern part that includes the .d/ directory
|
||||||
|
local dir_part=$(dirname "$file")
|
||||||
|
local base_name=$(basename "$file")
|
||||||
|
|
||||||
|
# Check if it's a config directory pattern worth capturing
|
||||||
|
if [[ "$dir_part" =~ /(\.d|[^/]+\.d)$ ]]; then
|
||||||
|
pattern="$dir_part/*"
|
||||||
|
msg_debug "Detected .d directory pattern: $pattern"
|
||||||
|
else
|
||||||
|
# Use standard extension pattern
|
||||||
|
pattern="*.${extension}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Standard file with extension
|
||||||
|
pattern="*.${extension}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Common text files
|
||||||
|
case "$extension" in
|
||||||
|
# Shell scripts
|
||||||
|
sh|bash|zsh|fish)
|
||||||
|
attributes="text eol=lf diff=shell"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Web development
|
||||||
|
html|htm|xhtml|css|scss|sass|less)
|
||||||
|
attributes="text eol=lf diff=html"
|
||||||
|
;;
|
||||||
|
js|jsx|ts|tsx|json|json5)
|
||||||
|
attributes="text eol=lf diff=javascript"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Programming languages
|
||||||
|
php)
|
||||||
|
attributes="text eol=lf diff=php"
|
||||||
|
;;
|
||||||
|
py)
|
||||||
|
attributes="text eol=lf diff=python"
|
||||||
|
;;
|
||||||
|
rb)
|
||||||
|
attributes="text eol=lf diff=ruby"
|
||||||
|
;;
|
||||||
|
go)
|
||||||
|
attributes="text eol=lf diff=golang"
|
||||||
|
;;
|
||||||
|
java|kt|scala)
|
||||||
|
attributes="text eol=lf diff=java"
|
||||||
|
;;
|
||||||
|
c|cpp|h|hpp)
|
||||||
|
attributes="text eol=lf diff=cpp"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
md|markdown|txt)
|
||||||
|
attributes="text eol=lf"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Configuration files
|
||||||
|
yml|yaml|toml|ini|cfg|conf)
|
||||||
|
attributes="text eol=lf"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Git config files and similar patterns
|
||||||
|
git)
|
||||||
|
attributes="text eol=lf"
|
||||||
|
;;
|
||||||
|
gitignore|gitattributes)
|
||||||
|
attributes="text eol=lf"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Binary files
|
||||||
|
png|jpg|jpeg|gif|ico|svg|webp|avif)
|
||||||
|
attributes="binary"
|
||||||
|
;;
|
||||||
|
pdf|doc|docx|xls|xlsx|ppt|pptx)
|
||||||
|
attributes="binary"
|
||||||
|
;;
|
||||||
|
zip|tar|gz|7z|rar)
|
||||||
|
attributes="binary"
|
||||||
|
;;
|
||||||
|
mp3|mp4|avi|mov|wav|ogg)
|
||||||
|
attributes="binary"
|
||||||
|
;;
|
||||||
|
ttf|otf|woff|woff2|eot)
|
||||||
|
attributes="binary"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# Default for unknown extensions
|
||||||
|
*)
|
||||||
|
# Try to guess if it's text by checking if it contains null bytes
|
||||||
|
if file "$file" | grep -q text; then
|
||||||
|
attributes="text eol=lf"
|
||||||
|
else
|
||||||
|
attributes="binary"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
msg_debug "...suggesting $pattern $attributes"
|
||||||
|
|
||||||
|
echo "$pattern:$attributes"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check for missing .gitattributes
|
||||||
|
check_gitattributes() {
|
||||||
|
local missing_attributes
|
||||||
|
msg_info "Checking for pattern: $CHECK_PATTERN"
|
||||||
|
|
||||||
|
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "$CHECK_PATTERN" || true)
|
||||||
|
|
||||||
|
if [[ -n "$missing_attributes" ]]; then
|
||||||
|
msg_warn "Missing .gitattributes rules detected"
|
||||||
|
|
||||||
|
if [[ $SUGGEST_RULES -eq 1 ]]; then
|
||||||
|
# Generate suggestions
|
||||||
|
local suggestions
|
||||||
|
|
||||||
|
# Generate the suggestions
|
||||||
|
suggestions=$(suggest_gitattributes "$missing_attributes")
|
||||||
|
|
||||||
|
# Display the suggestions
|
||||||
|
echo ""
|
||||||
|
echo "$suggestions"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ $WRITE_RULES -eq 1 ]]; then
|
||||||
|
msg_debug "...writing to .gitattributes"
|
||||||
|
write_to_gitattributes "$suggestions"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
msg_err ".gitattributes rule missing for the following files:"
|
||||||
|
echo "$missing_attributes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $EXIT_ON_MISSING -eq 1 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
msg_success "All files have a corresponding rule in .gitattributes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse rule string and extract pattern and attributes
|
||||||
|
parse_rule() {
|
||||||
|
local rule="$1"
|
||||||
|
|
||||||
|
if [[ "$rule" == "#"* ]]; then
|
||||||
|
# This is a comment line
|
||||||
|
echo "$rule::"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$rule" =~ ^([^[:space:]]+)[[:space:]]+(.*)$ ]]; then
|
||||||
|
echo "${BASH_REMATCH[1]}:${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
echo "$rule::"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check shell scripts by name regardless of extension
|
||||||
|
detect_shell_scripts() {
|
||||||
|
msg_debug "Detecting shell scripts by name regardless of extension..."
|
||||||
|
|
||||||
|
local shell_scripts_rules=""
|
||||||
|
local shell_scripts_found=0
|
||||||
|
local patterns=()
|
||||||
|
local attributes=()
|
||||||
|
|
||||||
|
# Get already defined rules in .gitattributes
|
||||||
|
local existing_rules
|
||||||
|
existing_rules=$(grep -v "^#" .gitattributes || true)
|
||||||
|
|
||||||
|
# Get all shell scripts regardless of extension
|
||||||
|
local shell_scripts
|
||||||
|
shell_scripts=$(git ls-files | xargs file | grep "shell script" | cut -d: -f1)
|
||||||
|
|
||||||
|
if [[ -n "$shell_scripts" ]]; then
|
||||||
|
shell_scripts_found=$(echo "$shell_scripts" | wc -l | tr -d ' ')
|
||||||
|
msg_debug "Found $shell_scripts_found potential shell scripts."
|
||||||
|
|
||||||
|
# Track scripts that need rules
|
||||||
|
declare -A scripts_by_dir=()
|
||||||
|
local need_rule_count=0
|
||||||
|
|
||||||
|
# Process each script
|
||||||
|
while IFS= read -r script; do
|
||||||
|
local rel_path="${script#./}"
|
||||||
|
|
||||||
|
# Skip if exact path already in .gitattributes
|
||||||
|
if grep -q "^${rel_path} " <<< "$existing_rules"; then
|
||||||
|
msg_debug "Script already in .gitattributes: $rel_path"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Skip if file extension already covered
|
||||||
|
local extension=$(get_file_extension "$rel_path")
|
||||||
|
if [[ "$extension" != "$rel_path" ]] && grep -q "^\*\.$extension " <<< "$existing_rules"; then
|
||||||
|
msg_debug "Script covered by extension rule: $rel_path (*.$extension)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if any parent directory is already covered
|
||||||
|
local is_covered=0
|
||||||
|
local dir_path="$rel_path"
|
||||||
|
while [[ "$dir_path" != "." && "$dir_path" != "/" ]]; do
|
||||||
|
dir_path=$(dirname "$dir_path")
|
||||||
|
if [[ "$dir_path" == "." ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if directory or any of its contents are covered
|
||||||
|
if grep -q "^${dir_path}/\?" <<< "$existing_rules" || grep -q "^${dir_path}/\*" <<< "$existing_rules"; then
|
||||||
|
msg_debug "Script covered by directory rule: $rel_path (${dir_path})"
|
||||||
|
is_covered=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $is_covered -eq 1 ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Group by directory
|
||||||
|
local dir=$(dirname "$rel_path")
|
||||||
|
if [[ "$dir" == "." ]]; then
|
||||||
|
dir="root"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add to appropriate group
|
||||||
|
if [[ -z "${scripts_by_dir[$dir]:-}" ]]; then
|
||||||
|
scripts_by_dir[$dir]="$rel_path"
|
||||||
|
else
|
||||||
|
scripts_by_dir[$dir]="${scripts_by_dir[$dir]}\n$rel_path"
|
||||||
|
fi
|
||||||
|
|
||||||
|
((need_rule_count++))
|
||||||
|
done <<< "$shell_scripts"
|
||||||
|
|
||||||
|
# Output grouped results
|
||||||
|
if [[ $need_rule_count -gt 0 ]]; then
|
||||||
|
patterns+=("# Shell scripts detected by content")
|
||||||
|
attributes+=("")
|
||||||
|
|
||||||
|
# Check if we can use directory-based rules instead of individual files
|
||||||
|
for dir in "${!scripts_by_dir[@]}"; do
|
||||||
|
local files_in_dir=$(echo -e "${scripts_by_dir[$dir]}" | wc -l)
|
||||||
|
local dir_path="$dir"
|
||||||
|
|
||||||
|
if [[ "$dir" == "root" ]]; then
|
||||||
|
# For root directory files, list each individually
|
||||||
|
while IFS= read -r file; do
|
||||||
|
patterns+=("$file")
|
||||||
|
attributes+=("text eol=lf diff=shell")
|
||||||
|
done <<< "$(echo -e "${scripts_by_dir[$dir]}")"
|
||||||
|
elif [[ $files_in_dir -gt 2 ]]; then
|
||||||
|
# If directory has multiple scripts, suggest a directory pattern
|
||||||
|
patterns+=("# Found $files_in_dir scripts in $dir_path")
|
||||||
|
attributes+=("")
|
||||||
|
|
||||||
|
# Special handling for .d directories
|
||||||
|
if [[ "$dir_path" =~ \.d$ || "$dir_path" =~ \.d/ ]]; then
|
||||||
|
patterns+=("$dir_path/*")
|
||||||
|
else
|
||||||
|
patterns+=("$dir_path/*")
|
||||||
|
fi
|
||||||
|
attributes+=("text eol=lf diff=shell")
|
||||||
|
|
||||||
|
# List the files as comments for reference
|
||||||
|
while IFS= read -r file; do
|
||||||
|
patterns+=("# - ${file}")
|
||||||
|
attributes+=("")
|
||||||
|
done <<< "$(echo -e "${scripts_by_dir[$dir]}" | sort)"
|
||||||
|
else
|
||||||
|
# For directories with few scripts, list them individually
|
||||||
|
while IFS= read -r file; do
|
||||||
|
patterns+=("$file")
|
||||||
|
attributes+=("text eol=lf diff=shell")
|
||||||
|
done <<< "$(echo -e "${scripts_by_dir[$dir]}")"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
msg_debug "Adding $need_rule_count shell scripts to suggestions (grouped by directory)."
|
||||||
|
else
|
||||||
|
msg_debug "All detected shell scripts already have rules."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
msg_debug "No shell scripts detected."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Return the formatted arrays
|
||||||
|
local rules_count=${#patterns[@]}
|
||||||
|
for ((i=0; i<rules_count; i++)); do
|
||||||
|
echo "${patterns[$i]}:${attributes[$i]}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to suggest gitattributes rules
|
||||||
|
suggest_gitattributes() {
|
||||||
|
local missing_attributes="$1"
|
||||||
|
local files
|
||||||
|
local extension_suggestions=()
|
||||||
|
local formatted_suggestions=""
|
||||||
|
local all_patterns=()
|
||||||
|
local all_attributes=()
|
||||||
|
local max_pattern_length=0
|
||||||
|
|
||||||
|
# Add header to suggestions
|
||||||
|
all_patterns+=("# Auto-generated rules - $(date +"%Y-%m-%d %H:%M:%S")")
|
||||||
|
all_attributes+=("")
|
||||||
|
|
||||||
|
msg_info "Suggested .gitattributes rules:"
|
||||||
|
|
||||||
|
# First, detect shell scripts and add them to suggestions
|
||||||
|
msg_info "Detecting shell scripts by content..."
|
||||||
|
local shell_scripts_rules
|
||||||
|
shell_scripts_rules=$(detect_shell_scripts)
|
||||||
|
|
||||||
|
# Add shell script rules to patterns and attributes arrays
|
||||||
|
if [[ -n "$shell_scripts_rules" ]]; then
|
||||||
|
while IFS=':' read -r pattern attributes; do
|
||||||
|
if [[ -n "$pattern" ]]; then
|
||||||
|
all_patterns+=("$pattern")
|
||||||
|
all_attributes+=("$attributes")
|
||||||
|
|
||||||
|
# Update max pattern length (skip comments)
|
||||||
|
if [[ "$pattern" != "#"* ]] && [[ ${#pattern} -gt $max_pattern_length ]]; then
|
||||||
|
max_pattern_length=${#pattern}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$shell_scripts_rules"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract filenames from git check-attr output
|
||||||
|
files=$(echo "$missing_attributes" | awk -F': ' '{print $1}')
|
||||||
|
|
||||||
|
# Get suggestions for each file
|
||||||
|
declare -A seen_patterns=()
|
||||||
|
|
||||||
|
while IFS= read -r file; do
|
||||||
|
local suggestion=$(suggest_rule "$file")
|
||||||
|
if [[ -n "$suggestion" ]]; then
|
||||||
|
IFS=':' read -r pattern attributes <<< "$suggestion"
|
||||||
|
|
||||||
|
# Only add each pattern once
|
||||||
|
if [[ -z "${seen_patterns[$pattern]:-}" ]]; then
|
||||||
|
extension_suggestions+=("$suggestion")
|
||||||
|
seen_patterns[$pattern]=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$files"
|
||||||
|
|
||||||
|
# Remove duplicates and sort
|
||||||
|
local unique_extensions=()
|
||||||
|
mapfile -t unique_extensions < <(printf '%s\n' "${extension_suggestions[@]}" | sort -u)
|
||||||
|
|
||||||
|
# Add extension-based suggestions header if we have any
|
||||||
|
if [[ ${#unique_extensions[@]} -gt 0 ]]; then
|
||||||
|
all_patterns+=("")
|
||||||
|
all_attributes+=("")
|
||||||
|
|
||||||
|
all_patterns+=("# File extension-based rules")
|
||||||
|
all_attributes+=("")
|
||||||
|
|
||||||
|
# Add extension rules to patterns and attributes arrays
|
||||||
|
for suggestion in "${unique_extensions[@]}"; do
|
||||||
|
IFS=':' read -r pattern attributes <<< "$suggestion"
|
||||||
|
|
||||||
|
all_patterns+=("$pattern")
|
||||||
|
all_attributes+=("$attributes")
|
||||||
|
|
||||||
|
# Update max pattern length
|
||||||
|
if [[ ${#pattern} -gt $max_pattern_length ]]; then
|
||||||
|
max_pattern_length=${#pattern}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use user-specified format width if provided, otherwise use max_pattern_length
|
||||||
|
# But ensure it's at least MIN_FORMAT_WIDTH
|
||||||
|
local format_width=$max_pattern_length
|
||||||
|
if [[ $FORMAT_WIDTH -gt 0 ]]; then
|
||||||
|
format_width=$FORMAT_WIDTH
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure minimum width
|
||||||
|
if [[ $format_width -lt $MIN_FORMAT_WIDTH ]]; then
|
||||||
|
format_width=$MIN_FORMAT_WIDTH
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_debug "Using format width: $format_width"
|
||||||
|
|
||||||
|
# Format and output all suggestions with proper alignment
|
||||||
|
local rule_count=${#all_patterns[@]}
|
||||||
|
|
||||||
|
for ((i=0; i<rule_count; i++)); do
|
||||||
|
local pattern="${all_patterns[$i]}"
|
||||||
|
local attributes="${all_attributes[$i]}"
|
||||||
|
|
||||||
|
# Handle comments separately
|
||||||
|
if [[ "$pattern" == "#"* ]] || [[ -z "$attributes" ]]; then
|
||||||
|
formatted_suggestions+="$pattern\n"
|
||||||
|
echo "$pattern"
|
||||||
|
else
|
||||||
|
local formatted_rule=$(printf "%-${format_width}s %s\n" "$pattern" "$attributes")
|
||||||
|
formatted_suggestions+="$formatted_rule\n"
|
||||||
|
echo "$formatted_rule"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add final message
|
||||||
|
echo ""
|
||||||
|
msg_info "Add these rules to your .gitattributes file to resolve missing attributes."
|
||||||
|
|
||||||
|
# Return the full suggestion text so it can be both displayed and written to file
|
||||||
|
echo -e "$formatted_suggestions"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write suggestions to .gitattributes file
|
||||||
|
write_to_gitattributes() {
|
||||||
|
local suggestions="$1"
|
||||||
|
local gitattributes=".gitattributes"
|
||||||
|
|
||||||
|
# Check if file exists and is writable
|
||||||
|
if [[ ! -w "$gitattributes" ]]; then
|
||||||
|
msg_err "Cannot write to $gitattributes. Check permissions."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add a newline at the end of the file if it doesn't have one
|
||||||
|
if [[ -s "$gitattributes" ]] && [[ $(tail -c 1 "$gitattributes" | wc -l) -eq 0 ]]; then
|
||||||
|
echo "" >> "$gitattributes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Append suggestions to the file
|
||||||
|
echo -e "$suggestions" >> "$gitattributes"
|
||||||
|
|
||||||
|
msg_success "Added suggested rules to $gitattributes"
|
||||||
|
|
||||||
|
# Remind to check the file
|
||||||
|
msg_warn "Please review the changes to ensure they're appropriate for your project."
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main function
|
||||||
|
main() {
|
||||||
|
check_git_installed
|
||||||
|
check_git_repo
|
||||||
|
check_git_root
|
||||||
|
check_gitattributes_exists
|
||||||
|
check_gitattributes
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Check git repo's files .gitattributes and ensure all of them are mapped.
|
|
||||||
# Ismo Vuorinen <https://github.com/ivuorinen> 2022
|
|
||||||
source "${DOTFILES}/config/shared.sh"
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Enable verbosity with VERBOSE=1
|
|
||||||
VERBOSE="${VERBOSE:-0}"
|
|
||||||
|
|
||||||
# Function to check if git is installed
|
|
||||||
check_git_installed()
|
|
||||||
{
|
|
||||||
if ! command -v git &> /dev/null; then
|
|
||||||
msg_err "git could not be found, please install it first"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to check for missing .gitattributes
|
|
||||||
check_gitattributes()
|
|
||||||
{
|
|
||||||
local missing_attributes
|
|
||||||
missing_attributes=$(git ls-files | git check-attr -a --stdin | grep "text: auto" || true)
|
|
||||||
|
|
||||||
if [[ -n "$missing_attributes" ]]; then
|
|
||||||
echo ".gitattributes rule missing for the following files:"
|
|
||||||
echo "$missing_attributes"
|
|
||||||
else
|
|
||||||
echo "All files have a corresponding rule in .gitattributes"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main function
|
|
||||||
main()
|
|
||||||
{
|
|
||||||
check_git_installed
|
|
||||||
check_gitattributes
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
Reference in New Issue
Block a user