1" Plugin to update the %changelog section of RPM spec files 2" Filename: spec.vim 3" Maintainer: Igor Gnatenko [email protected] 4" Former Maintainer: Gustavo Niemeyer <[email protected]> (until March 2014) 5" Last Change: Mon Jun 01 21:15 MSK 2015 Igor Gnatenko 6 7if exists("b:did_ftplugin") 8 finish 9endif 10let b:did_ftplugin = 1 11 12let s:cpo_save = &cpo 13set cpo&vim 14 15if !exists("no_plugin_maps") && !exists("no_spec_maps") 16 if !hasmapto("<Plug>SpecChangelog") 17 map <buffer> <LocalLeader>c <Plug>SpecChangelog 18 endif 19endif 20 21if !hasmapto("call <SID>SpecChangelog(\"\")<CR>") 22 noremap <buffer> <unique> <script> <Plug>SpecChangelog :call <SID>SpecChangelog("")<CR> 23endif 24 25if !exists("*s:GetRelVer") 26 function! s:GetRelVer() 27 if has('python') 28python << PYEND 29import sys, datetime, shutil, tempfile 30import vim 31 32try: 33 import rpm 34except ImportError: 35 pass 36else: 37 specfile = vim.current.buffer.name 38 if specfile: 39 spec = rpm.spec(specfile) 40 headers = spec.packages[0].header 41 version = headers['Version'] 42 release = ".".join(headers['Release'].split(".")[:-1]) 43 vim.command("let ver = " + version) 44 vim.command("let rel = " + release) 45PYEND 46 endif 47 endfunction 48endif 49 50if !exists("*s:SpecChangelog") 51 function s:SpecChangelog(format) 52 if strlen(a:format) == 0 53 if !exists("g:spec_chglog_format") 54 let email = input("Name <email address>: ") 55 let g:spec_chglog_format = "%a %b %d %Y " . l:email 56 echo "\r" 57 endif 58 let format = g:spec_chglog_format 59 else 60 if !exists("g:spec_chglog_format") 61 let g:spec_chglog_format = a:format 62 endif 63 let format = a:format 64 endif 65 let line = 0 66 let name = "" 67 let ver = "" 68 let rel = "" 69 let nameline = -1 70 let verline = -1 71 let relline = -1 72 let chgline = -1 73 while (line <= line("$")) 74 let linestr = getline(line) 75 if (name == "" && linestr =~? '^Name:') 76 let nameline = line 77 let name = substitute(strpart(linestr,5), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 78 elseif (ver == "" && linestr =~? '^Version:') 79 let verline = line 80 let ver = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 81 elseif (rel == "" && linestr =~? '^Release:') 82 let relline = line 83 let rel = substitute(strpart(linestr,8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 84 elseif (linestr =~? '^%changelog') 85 let chgline = line 86 execute line 87 break 88 endif 89 let line = line+1 90 endwhile 91 if (nameline != -1 && verline != -1 && relline != -1) 92 let include_release_info = exists("g:spec_chglog_release_info") 93 let name = s:ParseRpmVars(name, nameline) 94 let ver = s:ParseRpmVars(ver, verline) 95 let rel = s:ParseRpmVars(rel, relline) 96 else 97 let include_release_info = 0 98 endif 99 100 call s:GetRelVer() 101 102 if (chgline == -1) 103 let option = confirm("Can't find %changelog. Create one? ","&End of file\n&Here\n&Cancel",3) 104 if (option == 1) 105 call append(line("$"),"") 106 call append(line("$"),"%changelog") 107 execute line("$") 108 let chgline = line(".") 109 elseif (option == 2) 110 call append(line("."),"%changelog") 111 normal j 112 chgline = line(".") 113 endif 114 endif 115 if (chgline != -1) 116 let parsed_format = "* ".strftime(format)." - ".ver."-".rel 117 let release_info = "+ ".name."-".ver."-".rel 118 let wrong_format = 0 119 let wrong_release = 0 120 let insert_line = 0 121 if (getline(chgline+1) != parsed_format) 122 let wrong_format = 1 123 endif 124 if (include_release_info && getline(chgline+2) != release_info) 125 let wrong_release = 1 126 endif 127 if (wrong_format || wrong_release) 128 if (include_release_info && !wrong_release && !exists("g:spec_chglog_never_increase_release")) 129 let option = confirm("Increase release? ","&Yes\n&No",1) 130 if (option == 1) 131 execute relline 132 normal 133 let rel = substitute(strpart(getline(relline),8), '^[ ]*\([^ ]\+\)[ ]*$','\1','') 134 let release_info = "+ ".name."-".ver."-".rel 135 endif 136 endif 137 let n = 0 138 call append(chgline+n, parsed_format) 139 if include_release_info 140 let n = n + 1 141 call append(chgline+n, release_info) 142 endif 143 let n = n + 1 144 call append(chgline+n,"- ") 145 let n = n + 1 146 call append(chgline+n,"") 147 let insert_line = chgline+n 148 else 149 let line = chgline 150 if !exists("g:spec_chglog_prepend") 151 while !(getline(line+2) =~ '^\( *\|\*.*\)$') 152 let line = line+1 153 endwhile 154 endif 155 call append(line+1,"- ") 156 let insert_line = line+2 157 endif 158 execute insert_line 159 startinsert! 160 endif 161 endfunction 162endif 163 164if !exists("*s:ParseRpmVars") 165 function s:ParseRpmVars(str, strline) 166 let end = -1 167 let ret = "" 168 while (1) 169 let start = match(a:str, "\%{", end+1) 170 if (start == -1) 171 let ret = ret . strpart(a:str, end+1) 172 break 173 endif 174 let ret = ret . strpart(a:str, end+1, start-(end+1)) 175 let end = match(a:str, "}", start) 176 if (end == -1) 177 let ret = ret . strpart(a:str, start) 178 break 179 endif 180 let varname = strpart(a:str, start+2, end-(start+2)) 181 execute a:strline 182 let definestr = "^[ \t]*%define[ \t]\\+" . varname . "[ \t]\\+\\(.*\\)$" 183 let linenum = search(definestr, "bW") 184 if (linenum == 0) 185 let definestr = substitute(definestr, "%define", "%global", "") 186 let linenum = search(definestr, "bW") 187 endif 188 if (linenum != -1) 189 let ret = ret . substitute(getline(linenum), definestr, "\\1", "") 190 else 191 let ret = ret . strpart(str, start, end+1-start) 192 endif 193 endwhile 194 return ret 195 endfunction 196endif 197 198" The following lines, along with the macros/matchit.vim plugin, 199" make it easy to navigate the different sections of a spec file 200" with the % key (thanks to Max Ischenko). 201 202let b:match_ignorecase = 0 203let b:match_words = 204 \ '^Name:^%description:^%clean:^%setup:^%build:^%install:^%files:' . 205 \ '^%package:^%preun:^%postun:^%changelog' 206 207let &cpo = s:cpo_save 208unlet s:cpo_save 209 210let b:undo_ftplugin = "unlet! b:match_ignorecase b:match_words" 211