en / de
AI
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Editor Scripting

One of the problems of larger Project is the dependency management. A great help here is Maven. Maven can also be used in Android development so that both server and mobile client can use the same build and dependency management. In one of our Project we used this set-up.

However, there was still one drawback: The version number which needed to be kept in sync in the various xml files: pom.xml, AndroidManifest.xml, strings.xml, persistence.xml, application.xml to name a few

This is best done using some Script because Script will ensure fast, consistent and repeatable result. The are many languages which could perform the task. But I suggest an Editor-Script. That is a use of an Editor with its own scripting language like VI or EMACS.

The example I will present is written in VIM-Script the language of the VIM Editor. VIM is part of the POSIX family of editors:

Editor

Description

ed

A simple line editor.

ex

An extended line editor.

sed

Stream Editor. A programming language based ed / ex command to perform text transformations.

vi

A screen orientated editor based on ex.

VIM

VI-Improved. An enhanced version of VI. Most notably VIM has a full features graphical user interface. On most unix and unix like operating systems ed, ex and vi are symbolic links to vim.

In this Blog I will not speak about the merits of VIM as an editor but about VIM abilities as a programming language. The main advantage if VIM-Script is the ability to operate on a text at a hole. Most classic languages for text processing like SED, AWK or Perl usually operate on one line at at time. With VIM-Script the hole file is loaded into a text buffer and you can operate or navigate on the whole text.

But enough of the theory. Lets get into a real live example:

Set-Version-Number.vim

Variables

Lists of modules

First we define a few variables with the list of maven modules we are planning to work on. The first module of each list is the parent module:

26 let s:Noser_Modules = [«Noser», «Noser-apklib», «Noser-apktest», «Noser-ejb», «Noser-glassfish», «Noser-Scala-apktest», «Noser-web»]
27 let s:Zeiterfassung_Modules = [«Zeiterfassung», «Zeiterfassung-apk», «Zeiterfassung-ear», «Zeiterfassung-ejb», «Zeiterfassung-lib», «Zeiterfassung-rar», «Zeiterfassung-web», «Noser-Scala-apktest»]

Search pattern

Next a few search patterns. s:Version_Pattern searches three times one or two digits separated by dots. s:Version_Name_Pattern is similar but the set of digits are surrounded by brackets. s:POM_Version_Pattern looks for s:Version_Pattern between the the xml tags as used by pom.xml.

32 let s:Version_Pattern = ‚d{1,2}.d{1,2}.d{1,2}‘
33 let s:Version_Name_Pattern = ‚d{1,2}.d{1,2}(d{1,2})‘
34 let s:POM_Version_Pattern = » . s:Version_Pattern . »

Functions

The function I am now describing are mostly independent from the actual project. That is you can reuse the in other projects as well.

Integer_Version

All the different xml files need the version number in different formats. The following function will Convert Version number from «1.2.3» to integer form «010203» as used by the AndroidManifest.xml.

Interesting here is the use of the substitute function. Substitute searches for pattern in the string passed and replaces the string passed a third parameter. In this case we replace the whole string with the 1st, 2nd and 3rd (1 2 and 3) sub-expression (between ( and )).

39 function Integer_Version (Version)
40 let l:Mayor=substitute (a:Version, ‚(d{1,2}).(d{1,2}).(d{1,2})‘, ‚1‘, »)
41 let l:Minor=substitute (a:Version, ‚(d{1,2}).(d{1,2}).(d{1,2})‘, ‚2‘, »)
42 let l:Fix=substitute (a:Version, ‚(d{1,2}).(d{1,2}).(d{1,2})‘, ‚3‘, »)
44 if strlen (l:Minor) < 2
45 let l:Minor=«0» . l:Minor
46 endif
48 if strlen (l:Fix) < 2
49 let l:Fix=«0» . l:Fix
50 endif
52 return l:Mayor . l:Minor . l:Fix
53 endfunction Integer_Version

Display_Version

The next function convert a version number from «1.2.3» to display form «1.2(3)». This can be done with a single substitute.

58 function Display_Version (Version)
59 return substitute (a:Version, ‚(d{1,2}).(d{1,2}).(d{1,2})‘, ‚1.2(3)‘, »)
60 endfunction Display_Version

Set_Module_Version

Set the module version number inside the pom.xml. On the line following the first line containing and the Project_Name replace the version number found between and .

Interesting here the use of execute command. It evaluates a string expression and then executes the result a a new command. execute is needed quite often as Vim-Script is optimized for interactive use where literal expression are more important then variables or arithmetic expressions.

66 function Set_Module_Version (Project_Name, Project_Version)
67 1
68 execute ‚/V‘ . a:Project_Name . ‚/+1 substitute /‘ . s:POM_Version_Pattern . ‚/‘ . a:Project_Version . ‚/‘
70 return
71 endfunction Set_Module_Version

Set_Parent_Version

Set the parent-module version number inside the pom.xml. On the lines between and replace on the version number found between and .

Interesting here the use of search pattern as range. the given command is then executed for each line inside the range.

77 function Set_Parent_Version (Parent_Version)
78 1
79 execute ‚/V/,/V/ substitute /‘ . s:POM_Version_Pattern . ‚/‘ . a:Parent_Version . ‚/e‘
81 return
82 endfunction Set_Parent_Version

Set_Depended_Version

Set the dependent version numbers inside the pom.xml. For all lines between and / replace on all lines following and the Project_Pattern the version number found between and . Repeat once for the lines following for EBJ dependencies.

Interesting here the ability to directly jump to any line of the text as shown in line 92 and 94. In line 95 we first search for and then jump to the following line.

91 function Set_Depended_Version (Project_Pattern, Project_Version)
92 1
93 execute ‚/V/,/V/ global /V‘ . a:Project_Pattern . ‚/+1 substitute /‘ . s:POM_Version_Pattern . ‚/‘ . a:Project_Version . ‚/‘
94 //+1
95 execute ‚/V/,/V/ global /V‘ . a:Project_Pattern . ‚/+1 substitute /‘ . s:POM_Version_Pattern . ‚/‘ . a:Project_Version . ‚/‘
97 return
98 endfunction Set_Depended_Version

Set_Property_Version_Number

Set the version numbers inside the property section of the pom.xml. Replaces the version number between the XML tags a:Module.

This is just a simple substitute on the hole file as indicated by the % range.

103 function Set_Property_Version_Number (Module, Version)
104 execute ‚% substitute /(<‚ . a:Module . ‚>)‘ . s:Version_Pattern . ‚( . a:Module . ‚>)/1‘ . a:Version . ‚2/e‘
106 return
107 endfunction Set_Property_Version_Number

Set_Droid_Version_Number

Replaces the version number in the AndroidManifest.xml replacing all version number after android:versionCode=" and android:versionName=".

112 function! Set_Droid_Version_Number (Version)
113 let l:Version=Integer_Version (a:Version)
114 let l:Name=Display_Version (a:Version)
116 % substitute /’/«/ge
118 execute ‚% substitute /(android:versionCode=»)d*(«)/1‘ . l:Version . ‚2/e‘
119 execute ‚% substitute /(android:versionName=»)‘ . s:Version_Name_Pattern . ‚(«)/1‘ . l:Name . ‚2/e‘
120 endfunction Set_Droid_Version_Number

Set_HTML_Version_Number

Replaces version numbers in html help files by replacing everything which might be an old version number with the current version number

125 function Set_HTML_Version_Number (Version)
126 let l:Version=Display_Version (a:Version)
128 if strlen (l:Version) > 0
129 execute ‚% substitute /‘ . s:Version_Name_Pattern . ‚/‘ . l:Version . ‚/e‘
130 endif
131 endfunction Set_HTML_Version_Number

Set_PO_Version_Number

Replaces the version number in a Java EE persistent modules. This is done by replacing anything that looks like a version number on line which contain followed by the pattern given as parameter.

Interesting the use of global command which executes a command for all line where a specific search pattern matches a regular expression. global has also given the well known command grep its name. grep stands for «global /regular expression/ print» and g/hello/p will indeed print all lines containing “hello”. with Vim-Script.

136 function Set_PO_Version_Number (Pattern, Version)
137 execute ‚global /.*‘ . a:Pattern . ‚/ substitute /‘ . s:Version_Pattern . ‚/‘ . a:Version . ‚/e‘
139 return
140 endfunction Set_PO_Version_Number

Set_App_Version_Number

replaces the version number in Java EE application modules. This is done by replacing anything that looks like a version number on line which contain , or followed by the pattern given as parameter.

Again global is used.

149 function Set_App_Version_Number (Pattern, Version)
150 execute ‚global /‘ . a:Pattern . ‚/ substitute /‘ . s:Version_Pattern . ‚/‘ . a:Version . ‚/e‘
151 execute ‚global /‘ . a:Pattern . ‚/ substitute /‘ . s:Version_Pattern . ‚/‘ . a:Version . ‚/e‘
152 execute ‚global /‘ . a:Pattern . ‚/ substitute /‘ . s:Version_Pattern . ‚/‘ . a:Version . ‚/e‘
154 return
155 endfunction Set_AppL_Version_Number

Set_String_Version_Number

Replaces the version number in android string.xmlfiles. Provided they are places inside….

160 function Set_String_Version_Number (Version)
161 let l:Version=Display_Version (a:Version)
163 % substitute /’/«/ge
165 if strlen (l:Version) > 0
166 execute ‚% substitute /V()[0-9.()]*()/1‘ . l:Version . ‚2/e‘
167 endif
169 return
170 endfunction Set_String_Version_Number

The actual work

After having defined all functions needed we can start the actual work. First we change to the project directory.

Interesting here the use of shell variables. They can be easyly accessed by using a $ sign.

172 cd $PROJECT_HOME

Noser Library parent-module

Set the property version and module version on the first of the Noser modules.

Note the the module names and the directory names co-relate which makes it possible to open the pom file by concatenating the module name and «/pom.xml».

178 execute «edit» s:Noser_Modules[0] . «/pom.xml»
179 0,$ foldopen!
180 call Set_Property_Version_Number («NOSER_VERSION», $NOSER_VERSION)
181 call Set_Module_Version ( s:Noser_Modules[0], $NOSER_VERSION)
182 update

Noser Library child-module

Set the parent-module, module and dependent module names.

Note that when no depended module name is found no error is reported.

184 for s:Module in s:Noser_Modules[1:]
185 execute «edit» s:Module . «/pom.xml»
186 0,$ foldopen!
187 call Set_Parent_Version ($NOSER_VERSION)
188 call Set_Module_Version (s:Module, $NOSER_VERSION)
189 call Set_Depended_Version («Noser», $NOSER_VERSION)
190 update

Set the version name in any AndroidManifest*.xml found. If none a found then the loop is skipped. Since the search is rather fast no additional optimizations are performed.

Interesting the use if split and glob to get a list a files matching a wild card pattern.

192 for s:File in split (glob (s:Module .«/**/AndroidManifest*.xml»))
193 execute «edit» s:File
194 call Set_Droid_Version_Number ($NOSER_VERSION)
195 update
196 endfor
197 endfor

Application parent-module

Similar to Noser parent-module. Only this time we set both the own version number and the version number of the Noser library as we depend on the library.

199 execute «edit» s:Zeiterfassung_Modules[0] . «/pom.xml»
200 0,$ foldopen!
201 call Set_Property_Version_Number («NOSER_VERSION», $NOSER_VERSION)
202 call Set_Property_Version_Number («ZEITERFASSUNG_VERSION», $ZEITERFASSUNG_VERSION)
203 call Set_Module_Version (s:Zeiterfassung_Modules[0], $ZEITERFASSUNG_VERSION)
204 call Set_Depended_Version («Zeiterfassung», $ZEITERFASSUNG_VERSION)
205 call Set_Depended_Version («Noser», $NOSER_VERSION)
206 update

Application child-modules

Same as before but again with two calls to Set_Depended_Version.

211 for s:Module in s:Zeiterfassung_Modules[1:]
212 execute «edit» s:Module . «/pom.xml»
213 0,$ foldopen!
214 call Set_Parent_Version ($ZEITERFASSUNG_VERSION)
215 call Set_Module_Version (s:Module, $ZEITERFASSUNG_VERSION)
216 call Set_Depended_Version («Zeiterfassung», $ZEITERFASSUNG_VERSION)
217 call Set_Depended_Version («Noser», $NOSER_VERSION)
218 update

Test if a strings.xml file exist and replace the version number.

220 if filewritable (s:Module . «/res/values/strings.xml»)
221 execute «edit» s:Module . «/res/values/strings.xml»
222 call Set_String_Version_Number ($ZEITERFASSUNG_VERSION)
223 update
224 endif

Replace the version number in all html files found.

226 for s:File in split (glob (s:Module . «/src/**/*.html»))
227 execute «edit» s:File
228 call Set_HTML_Version_Number ($ZEITERFASSUNG_VERSION)
229 update
230 endfor

Replace the version number in all Java EE persistent modules found.

232 for s:File in split (glob (s:Module . «/src/**/persistence.xml»))
233 execute «edit» s:File
234 call Set_PO_Version_Number («Zeiterfassung», $ZEITERFASSUNG_VERSION)
235 update
236 endfor

Replace the version number in all Java EE application definitions found.

238 for s:File in split (glob (s:Module . «/src/**/application.xml»))
239 execute «edit» s:File
240 call Set_App_Version_Number («Noser», $NOSER_VERSION)
241 call Set_App_Version_Number («Zeiterfassung», $ZEITERFASSUNG_VERSION)
242 update
243 endfor

Set the version name in any AndroidManifest*.xml found.

250 for s:File in split (glob (s:Module .«/**/AndroidManifest*.xml»))
251 execute «edit» s:File
252 call Set_Droid_Version_Number ($ZEITERFASSUNG_VERSION)
253 update
254 endfor
255 endfor

Finish off

The wall command saves all unsaved changes and finish ends parsing of the script. That’s all folks. But wait, not quite. You need to execute the script as well.

350 wall
351 finish

Set-Version-Number.command

One can either call the script from within VIM using the source command or remote control vim with a shell script and vim remote control feature. Here an example for Z-Shell on Mac OS X:

1 #!/opt/local/bin/zsh
28
29 source ${PROJECT_HOME}/Utilities/Setup.command
30
31 setopt No_X_Trace;
32 setopt CSH_Null_Glob;
33
34 alias gvim_command=‚/opt/local/bin/gvim –servername «Set-Version-Number» –remote-send‘
35
36 pushd ${PROJECT_HOME}
40 /opt/local/bin/gvim –servername «Set-Version-Number» &
41
42 sleep 5
43
44 gvim_command «:source Utilities/src/main/scripts/Set-Version-Number.vim»
45 gvim_command «:exit»
46 popd;

Set-Version-Number.cmd

For Windows we use TakeCommand (http://jpsoft.com) for our daily scripting needs. Here the same start script for Windows:

11 @ECHO OFF
12
13 IF NOT «%@eval[2 + 2]%» == «4» ( echo ^e[42mYou need TakeCommand [http://www.jpsoft.com] to execute this batch file.^e[m & EXIT /B 1)
14
15 SETLOCAL
22 ALIAS gvim_command=%[opt]vimvim73gvim.exe —servername «Set-Version-Number» —remote–send
23
24 PUSHD «%[PROJECT_HOME]«
25 REM Start needs the real path and not an alias
26 REM
27 START /PGM %[opt]vimvim73gvim.exe —servername «Set-Version-Number»
28 DELAY 5
29 gvim_command «:source Zeiterfassung/src/main/scripts/Set-Version-Number.vim»
30 gvim_command «:exit»
31 POPD
32 ENDLOCAL
33 QUIT 0

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden

Copyright © 2025 Noser Engineering AG – Alle Rechte vorbehalten.

NACH OBEN
Privacy Policy Cookie Policy
Zur Webcast Übersicht