diff --git a/README.md b/README.md index a81712f..0203ca6 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,9 @@ But why do I re-implement it by scripts, because I hope the wslgit tools could s ## Usage 1. Please ensure `git` is installed in your WSL. -2. Copy `wslgit.sh` to the `/usr/bin/` directory in your WSL. -3. Add the following config into yout VSCode Settings (Remember to replace the path) - -``` json -{ - "git.path": "C:\\path\\to\\git.bat" -} -``` +2. Copy `wslgit.sh` to the `/usr/bin/` or `~/bin` directory in your WSL. +3. Add the following config into your VSCode Settings. + - `{ "git.path": "C:\\path\\to\\git.bat" }` ### 🐢 Feeling slowly? (Disable interactive shell) diff --git a/scripts/gen-wslgit-sh.sh b/scripts/gen-wslgit-sh.sh new file mode 100755 index 0000000..8070f13 --- /dev/null +++ b/scripts/gen-wslgit-sh.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +# =========================================== +# This script is used for generating +# `wslgit.sh` from `wslgit.dev.sh`. +# And this script will remove its comments, +# log logic and debug logic. +# =========================================== + +INPUT="wslgit.dev.sh"; +OUTPUT="wslgit.sh"; + +throw() { echo -e "fatal: $1"; exit 1; } + +cd "$( dirname "${BASH_SOURCE[0]}" )/.." || throw "goto project directory failed!"; +[[ -n "$(which gawk)" ]] || throw "gawk is not installed!"; +[[ -f "$INPUT" ]] || throw "${INPUT} is not a file!"; + +AWK_REMOVE_LOG=' + BEGIN { keep_line=1; } + /#region[ \t]+log/ { keep_line=0; next; } + /#endregion[ \t]+log/ { keep_line=1; next; } + /WSLGIT_SH_LOG/ { next; } + keep_line { print; } +'; + +AWK_REMOVE_COMMENTS=' + BEGIN { keep_line=0; } + /^#!/ { print; next; } # keep shebang comment + keep_line==1 { print; } + /^[ \t]*#[ \t]+[=]+/ { if(!keep_line) print; keep_line++; next; } + /^[ \t]*#/ { next; } + { print; } +' + +AWK_REMOVE_MUTLIPLE_EMPTY_LINES=' + /^$/ { i++; if(i>=2) next; } + !/^$/ { i=0; } + { print; } +'; + +AWK_ADD_WARNING=' + function warning(info) { print "# WARNING: " info; } + NR == 3 { + warning("DO NOT EDIT THIS FILE MANUALLY!"); + warning("Because This file is generated from '$INPUT' by ./script/gen-wslgit-sh.sh"); + print(""); + } + { print; } +' + + +cat "$INPUT" | + gawk "$AWK_REMOVE_LOG" | + gawk "$AWK_REMOVE_COMMENTS" | + gawk "$AWK_REMOVE_MUTLIPLE_EMPTY_LINES" | + gawk "$AWK_ADD_WARNING" \ + > "$OUTPUT" || throw "generate failed!"; + +echo "success: ${INPUT} -> ${OUTPUT}"; diff --git a/wslgit.sh b/wslgit.sh new file mode 100644 index 0000000..d1e346d --- /dev/null +++ b/wslgit.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +# WARNING: DO NOT EDIT THIS FILE MANUALLY! +# WARNING: Because This file is generated from wslgit.dev.sh by ./script/gen-wslgit-sh.sh + +# ========================================= +# Name: wslgit.sh +# Update: 2019-06-01 +# License: GPL-3.0 +# Author: Liu Yue (hangxingliu@gmail.com) +# +# Description: +# Convert the Windows path contained in the arguments to Linux(WSL) path, +# and convert the Linux(WSL) path in output of git to Windows path. +# This script use `mount` command, awk scripts to implement above features. +# I retained the implementation via `wslpath` codes in this script for +# reference purposes only. (because wslpath has some shortcomings to +# implement it) +# ========================================== + +AWK="$(which gawk)"; +[[ -z "$AWK" ]] && AWK="$(which awk)"; +[[ -z "$AWK" ]] && echo "fatal: \"awk\" is not installed in WSL!" >&2 && exit 1; + +function get_mounted_drvfs() { + mount -t drvfs | "$AWK" ' + function trim(s) { gsub(/^[ \t]+/, "", s); gsub(/[ \t]+$/, "", s); return s; } + { + if(split($0, lr, "type drvfs") < 2) next; + if(split(lr[1], part, "on") < 2) next; + + drive = trim(substr(part[1],1,2)); + mount_to = trim(part[2]); + + print toupper(drive) "\n" mount_to; + }'; +} +MOUNTED_DRVFS="$(get_mounted_drvfs)"; + +function to_unix_path_by_wslpath() { + local unix_path; + unix_path="$(wslpath "$1" 2>/dev/null)"; # empty output means it is not a Linux path + [[ -n "$unix_path" ]] && printf "%s" "$unix_path" || printf "%s" "$1"; +} +function to_win_path_by_wslpath() { + local win_path; + win_path="$(wslpath -w "$1" 2>/dev/null)"; # empty output means it is not a Linux path + [[ -n "$win_path" ]] && printf "%s" "$win_path"; +} + +function to_unix_path_by_awk() { + printf "%s" "$1" | + "$AWK" -v _mount="$MOUNTED_DRVFS" 'BEGIN { mount_len = split(_mount, mount_list, "\n"); } + { + if(index($0, ":\\") == 2) { + driver = toupper(substr($0, 1, 2)); + for(i = 1; i <= mount_len ; i += 2 ) { + if(driver != mount_list[i]) continue; + suffix = substr($0, 3); gsub(/\\/, "/", suffix); gsub("//", "/", suffix); + print mount_list[i+1] suffix; + exit; + } + } + print $0; + exit; + }'; +} +function to_win_path_by_awk() { + "$AWK" -v _mount="$MOUNTED_DRVFS" 'BEGIN { mount_len = split(_mount, mount_list, "\n"); } + { + for(i = 1; i <= mount_len ; i += 2 ) { + if(sub(mount_list[i+1], mount_list[i]) > 0) { + gsub("/", "\\"); + break; + } + } + print $0; + }'; +} + +if [[ -n "$WSLGIT_SH_CWD" ]]; then + correct_cwd="$(to_unix_path_by_awk "$WSLGIT_SH_CWD")"; + cd "$correct_cwd"; + [[ "$?" != 0 ]] && echo "fatal: can not cd to ${WSLGIT_SH_CWD} ($correct_cwd)" >&2 && exit 1; +fi + +argv=0; +convert_output=false; +after_double_dash=false; +for arg in "$@"; do + if [[ "$after_double_dash" != true ]]; then + if [[ "$arg" == "rev-parse" ]] || [[ "$arg" == "remote" ]] || [[ "$arg" == "init" ]]; then + convert_output=true; + fi + if [[ "$arg" == --*=* ]]; then + prefix="${arg%%=*}"; + file_path="${arg#*=}"; + git_args[$argv]="${prefix}=$(to_unix_path_by_awk "$file_path")"; + argv=$(($argv+1)); + continue; + fi + fi + [[ "$arg" == "--" ]] && after_double_dash=true; + + git_args[$argv]="$(to_unix_path_by_awk "$arg")"; + argv=$(($argv+1)); +done + +function execut_git() { git "${git_args[@]}" <&0; return $?; } +if [[ "$convert_output" == true ]]; then + execut_git | to_win_path_by_awk; +else + execut_git; +fi + +exit $?;