SOTONO / ZSHCMDS

SOTONO / DOTFILES / ZSH

04 / 06

new

作成zsh/new.zsh

ABOUT

YYMM プレフィックス付きの作業ディレクトリを作って即 cd。git URL からの clone も。

WORK_DIR 配下に「年月_名前」形式(例: 2608_sotono_hogefuga)のディレクトリを作成して cd する。-g で git URL(https / ssh / owner/repo 形式に対応)を渡すと、URL を解釈して 2608_owner_repo 形式のディレクトリへ clone する。月別プレフィックスのおかげで作業ディレクトリが時系列に整列し、あとから見返しやすい。

USAGE

new <name> [name ...]
new -g <git-url>

OPTIONS

-g, --git <url>
git URL を解釈して clone。https / ssh / owner/repo に対応

EXAMPLES

$ new sotono zshcmds

$WORK_DIR/2608_sotono_zshcmds を作成して cd

$ new -g https://github.com/cloudflare/kumo

2608_cloudflare_kumo へ clone して cd

$ new -g cloudflare/kumo

owner/repo 形式でも OK

DEMO

DEMO GIF SLOT

src/assets/gifs/new.gif を追加するとここに表示されます

SOURCE

# git URL / owner/repo から clone 用 URL・owner・repo を取り出す。
# 成功時は _new_git_reply=(clone_url owner repo) をセットする。
_new_git_spec() {
    local spec="$1"
    spec="${spec#"${spec%%[![:space:]]*}"}"
    spec="${spec%"${spec##*[![:space:]]}"}"
    spec="${spec%%[?#]*}"
    spec="${spec%/}"

    if [[ -z "$spec" ]]; then
        echo "git URL が空です" >&2
        return 1
    fi

    local host="github.com"
    local path=""

    if [[ "$spec" == git@*:* ]]; then
        host="${spec#git@}"
        host="${host%%:*}"
        path="${spec#*:}"
    elif [[ "$spec" == ssh://* ]]; then
        local ssh_rest="${spec#ssh://}"
        ssh_rest="${ssh_rest#*@}"
        host="${ssh_rest%%/*}"
        path="${ssh_rest#*/}"
    elif [[ "$spec" == http://* || "$spec" == https://* ]]; then
        local rest="${spec#http://}"
        rest="${rest#https://}"
        host="${rest%%/*}"
        path="${rest#*/}"
    elif [[ "$spec" == github.com/* ]]; then
        path="${spec#github.com/}"
    elif [[ "$spec" == */* && "$spec" != *://* ]]; then
        path="$spec"
    else
        echo "git URL を解釈できません: $1" >&2
        return 1
    fi

    path="${path#/}"
    path="${path%/}"
    path="${path%.git}"

    local owner="${path%%/*}"
    local rest="${path#*/}"
    local repo="${rest%%/*}"
    repo="${repo%.git}"

    if [[ -z "$owner" || -z "$repo" || "$owner" == "$path" ]]; then
        echo "owner/repo を解釈できません: $1" >&2
        return 1
    fi

    if [[ "$owner" == *[^A-Za-z0-9._-]* || "$repo" == *[^A-Za-z0-9._-]* ]]; then
        echo "owner/repo に使えない文字があります: $owner/$repo" >&2
        return 1
    fi

    local clone_url
    if [[ "$spec" == git@*:* || "$spec" == ssh://* ]]; then
        clone_url="git@${host}:${owner}/${repo}.git"
    elif [[ "$spec" == http://* ]]; then
        clone_url="http://${host}/${owner}/${repo}.git"
    else
        clone_url="https://${host}/${owner}/${repo}.git"
    fi

    typeset -g -a _new_git_reply
    _new_git_reply=("$clone_url" "$owner" "$repo")
}

new() {
    local git_spec=""

    if [[ "${1:-}" == "-g" || "${1:-}" == "--git" ]]; then
        shift
        if (( $# != 1 )); then
            echo "usage: new -g <git-url>" >&2
            return 1
        fi
        git_spec="$1"
    elif (( $# == 0 )); then
        echo "usage: new <name> [name ...]" >&2
        echo "       new -g <git-url>" >&2
        return 1
    else
        local part
        for part in "$@"; do
            if [[ -z "$part" || "$part" == */* ]]; then
                echo "名前に空文字や / は使えません: $part" >&2
                return 1
            fi
        done
    fi

    local work_dir="${WORK_DIR:-$HOME/Documents/_work}"
    local directory_name target_path

    if [[ -n "$git_spec" ]]; then
        local clone_url owner repo
        _new_git_spec "$git_spec" || return 1
        clone_url="${_new_git_reply[1]}"
        owner="${_new_git_reply[2]}"
        repo="${_new_git_reply[3]}"
        directory_name="$(date +%y%m)_${owner}_${repo}"
        target_path="$work_dir/$directory_name"

        mkdir -p -- "$work_dir" || return 1
        git clone -- "$clone_url" "$target_path" || return 1
        cd "$target_path" || return 1
        echo "$target_path"
        return
    fi

    directory_name="$(date +%y%m)_${(j:_:)@}"
    target_path="$work_dir/$directory_name"

    mkdir -p -- "$work_dir" || return 1
    mkdir -- "$target_path" || return 1
    cd "$target_path" || return 1
    echo "$target_path"
}
zsh/new.zsh