牢獄機械文書群 目次 » 計算機 » 現在地
バージョン違いのバックアップ
2011-09-07 23:58

2011年01月に牢獄機械文書群に書いたものを再掲。

ねらいは、

1. 関数 tempname() を使用して ls! でのバッファ欄に痕跡を残さない

2. 行番号を指定して部分的にバックアップも可

3. 保存した日時と保存後のファイル名をログファイルに出力(追記)

let g:logname = "$TEMP/VIM/backup.log"
" ログファイル名...変更してください

function! Backup2UsbMemory(dir, compress, ...)
    if a:dir =~ '/$'
       let l:dirroot = a:dir
    else
       let l:dirroot = a:dir .'/'
    endif
    let l:dirname = l:dirroot .strftime("%Y/%Y_%m/%d")
    if isdirectory(l:dirname) == 0
        if isdirectory(l:dirroot .strftime("%Y/%Y_%m")) == 0
            if isdirectory(l:dirroot .strftime("%Y/")) == 0
                call mkdir(l:dirroot .strftime("%Y/"))
            endif
            call mkdir(l:dirroot .strftime("%Y/%Y_%m"))
        endif
        call mkdir(l:dirname)
        if expand('%') == ''
            echo 'Vim only made a directory named "' .l:dirname .'/"'
            return
        endif
    elseif expand('%') == ''
        echohl ErrorMsg
        echo 'Error: No file name'
        echo 'Directory ' .l:dirname ." is already made."
        echohl None
        return
    endif
    let l:compformat = ''
    if a:compress == 'gzip'
        let l:compformat = '.gz'
    elseif a:compress == 'bzip2'
        let l:compformat = '.bz2'
    endif
    let l:extend = expand("%:e")
    if l:extend != ""
        let l:extend = "." .l:extend
    endif

    let l:partsign = (len(a:000) > 0) ? "_part" : ""

    let l:filename = expand("%:t:r")
    let l:filepath = expand("%:p:h")

    if l:filepath != getcwd() && l:filepath != "/"
        let l:filename = substitute(substitute(l:filepath,'\','_','g'),'^\D:.','','g') ."_" .filename
    endif

    let l:filenamefull = l:dirname .'/' .l:filename .l:partsign ."_"
\ .strftime("%y%m%d_%H%M") .l:extend .l:compformat

    if filereadable(l:filenamefull)
        return "filename is already exists."
    endif

    let l:tmp = tempname()

    let l:lnum = (len(a:000) > 0) ? a:1 : '^'
    let l:end  = (len(a:000) > 1) ? a:2 : '$'

    call writefile(getline(l:lnum, l:end), l:tmp)
    call system(a:compress ." " .l:tmp)
    let l:fsize = ArrangeNumber(getfsize(l:tmp .l:compformat))
    call rename(l:tmp .l:compformat, l:filenamefull)

    " add information to logfile
    let l:inform =
\ ["@ " .strftime("%Y-%m-%d %a %H:%M :%S"), "Name: " .l:filenamefull, "Size: " .l:fsize]
    call AppendBackupLog(l:inform, g:logname)
    " ----
    return '"' .split(l:filenamefull,'/')[-1] .'" Size: ' .l:fsize .' saved'
endfunction

function! AppendBackupLog(inform, logname)
    let l:loginform = []
    if filereadable(a:logname)
        let l:loginform = readfile(a:logname)
    endif
    call writefile(l:loginform + a:inform, a:logname)
endfunction

" flag... ''ならログファイル表示, 'promptdel'なら削除ダイアログ, 'del'なら確認せず削除
function! ViewBackupLog(logname, flag)
    let l:blankmax = 10
    if filereadable(a:logname)
        let l:loginform = readfile(a:logname)
    else
        echo "logfile not found."
        return
    endif
    if a:flag =~ "del"
        if a:flag =~ "promptdel"
            while 1
                let l:answer = input("delete logfile? (y/n):")
                if l:answer =~ '^y\>'
                    break
                elseif l:answer =~ '^n\>'
                    return
                endif
            endwhile
        endif
        call delete(a:logname)
        echo "deleted."
        return
    endif
    echohl Title
    echo "--- Backup Log --- "
    echohl None
    for l:i in range(0, len(loginform) -1, 3)
        let l:date = split(l:loginform[l:i])[1]
        let l:time = split(l:loginform[l:i])[3]
        let l:filename = split(l:loginform[l:i +1], '/')[-1]
        let l:fsize = split(l:loginform[l:i +2])[1]
        echo l:date ." " .l:time .Blank(l:blankmax - len(l:fsize)) .l:fsize ." " .l:filename
    endfor
        return
endfunction

function! ArrangeNumber(num)
    if a:num < 1
        return a:num
    endif
    let l:len = strlen(a:num)
    if l:len <= 3
        return a:num
    endif
    let l:result = ""
    let l:modulo = l:len % 3
    if l:modulo != 0
        let l:result .= a:num[0:(l:modulo -1)] .','
    endif
    for l:i in range(l:modulo, l:len -1, 3)
        let l:result .= a:num[(l:i):(l:i +2)] .','
    endfor
    return l:result[:-2]
endfunction

function! Blank(limit)
    if a:limit < 1
        return ""
    endif
    let l:blank = ""
    for l:count in range(a:limit)
        let l:blank .= " "
    endfor
    return l:blank
endfunction

ユーザーが実際にいじる関数/変数は以下の3つ。

Backup2UsbMemory(dir, compress, ...)
ViewBackupLog(logname, flag)
g:logname

Backup2UsbMemory() の引数の dir は保存先の親ディレクトリ、compress は圧縮方法をそれぞれ文字列で指定する。


ViewBackupLog() はログファイルの作成、閲覧、削除のための関数。

引数の logname はログファイル名(フルパス)を文字列で指定する。

flag は '' (空文字)ならログをコマンドバッファに表示、'promptdel' ならログファイルの削除(確認あり)、'del' なら確認無しの削除。


g:logname はログファイル名をフルパスで指定。

ログが必要なければ 64, 65行目をコメントアウトしてください。


Backup2UsbMemory() は、ほかに2つ引数を指定することができる。

Backup2UsbMemory(dir, compress, lnum, end)
" あるいは
Backup2UsbMemory(dir, compress)

lnum は保存対象の開始行、end は終了行。lnum と end は省略することができる。省略した場合は、バッファ全体がバックアップ対象になる。

lnum と end は、たとえば以下のように指定できる。

Backup2UsbMemory
\ (g:backupdirUsb, 'bzip2', (search('{{{', 'Wbn') - 1), search('}}}', 'Wn'))

この例だと、カーソル前の文字列 {{{ の一行前から、カーソル後の文字列 }}} までの行をバックアップの対象にする。

( {{{ , }}} は Vim のオプションの foldmethod 値が 'marker' のとき、fold のマーカーとして扱われる。)

グローバル変数(この例だと g:backupdirUsb )にバックアップ用の親ディレクトリを文字列で代入しておいて :command やキーマップを使うと楽。

« もどる
inserted by FC2 system