After years of experiencing countless success stories using Appy on various projects, you may end up with a plethora of POD templates. Consequently, these needs may emerge:
- searching keywords within POD templates ;
- performing find / replace operations within your templates.
This what ogrep.py is all about.
ogrep stands for "OpenDocument Grep" and is meant to perform grep-like searches within a given POD template or within all POD templates being found, recursively, in a given folder. Although it is possible, with ogrep, to grep any part of an OpenDocument template (be it an ODT or ODS template), the main focus is on searching and/or replacing keywords within POD-specific zones, ie, comments (notes) and fields.
Searching for keywords
Suppose you have this template, named Agenda.py, in the current working directory. A part of this template could look like this:
If you want to find all usages of method getShownValue in your template, you may use ogrep.py this way:
appy ogrep getShownValue Agenda.odt
The result would be:
pod/Agenda.odt matches 1 time(s).
Searching for keyword item would match more results:
appy ogrep item Agenda.odt
pod/Agenda.odt matches 5 time(s).
If you want more output, use options -v or -vv:
appy ogrep getShownValue Agenda.odt -v
:: 1 match for Agenda.odt ::
Content:
item.proposingGroup.getShownValue()
With even more verbosity, you get this result.
appy ogrep getShownValue Agenda.odt -vv
:: 1 match for Agenda.odt ::
Match::on::field (tag text:conditional-text)
Keyword(s) (regex): getShownValue
Content:
item.proposingGroup.getShownValue()
All the examples so far illustrated keywords found within fields. The following example matches a keyword in a comment. Template Agenda.py contains these comments:
Performing the following ogrep produces this result:
appy ogrep is.mpty Agenda.odt -vv
:: 6 matches for Agenda.odt ::
Match::on::note (tag office:annotation)
Keyword(s) (regex): is.mpty
By Auteur inconnu on 2014-05-01T19:05:06
Content:
do text if not tool.isEmpty('logo')
from document(at=tool.path('logo'))
Match::on::note (tag office:annotation)
Keyword(s) (regex): is.mpty
By Auteur inconnu on 2014-05-01T19:10:58
Content:
do text if not tool.isEmpty('organization')
...
This example illustrates another element: the keyword is, by default, interpreted as a regular expression. The dot matching anything, is.mpty matches isEmpty, found 6 times in the POD template (the result was truncated to the 2 first results for conciseness).
If you want the keyword to be interpreted as a strict string, use option -s:
appy ogrep is.mpty Agenda.odt -vv -s
No match found.
The hereabove examples were about searching for keywords within a single POD template. It is also possible to search (and replace, see below) for keywords, recursively, within all POD templates found in a folder hierarchy, lie in this example.
appy ogrep "search" ../../HubSessions
../../HubSessions/pod/Revenues.ods matches 1 time(s).
../../HubSessions/pod/Tasks.ods matches 2 time(s).
../../HubSessions/pod/sub/Items.ods matches 2 time(s).
../../HubSessions/pod/Items.odt matches 3 time(s).
../../HubSessions/Meetings.odt matches 3 time(s).
../../HubSessions/pod/a/b/c/Tasks.odt matches 3 time(s).
Also note that ogrep works fine with ODT as well as ODS POD templates.
Performing replacements
Performing a find / replace with ogrep is as simple as adding option -r repl to an ogrep command. Before performing such a delicate operation, a dry run mode has been implemented via option -d. Suppose you want to replace string search_title with the more elegant camelCased searchTitle. You may test it with this command:
appy ogrep search_title ../../HubSessions -r searchTitle -vv -d
Every match would look like this:
:: 1 match for ../../HubSessions/pod/Revenues.ods ::
Match::on::field (tag table:table-cell)
Keyword(s) (regex): search_title
These changes would have been done:
- '%s — Extrait du %s' % (search.translated or _('search_title'), d(now, withHour=False))
? ^^
+ '%s — Extrait du %s' % (search.translated or _('searchTitle'), d(now, withHour=False))
? ^
By default, differences between the POD zones before or after having performed the replacement are outputed using the standard diff syntax. If you prefer colors, use the -n option:
appy ogrep search_title ../../HubSessions -r searchTitle -vv -d -n
Here is the result:
In order to perform the true replacement, simply remove the -d option.
Reference
All program options are documented hereafter.
usage: ogrep.py [-h] [-r REPL] [-v] [-vv] [-d] [-c] [-s] [-n] keyword path
positional arguments:
keyword is the regular expression (or string if -s) to search
within the file(s). From the command-line, special
chars possibly included in the keyword (and also the
replacement string, if passed) must be escaped. For
example, cus(tom)_(agenda) must be written as
cus\(tom\)_\(agenda\). \2_\1 must be written as
\\2_\\1.
path is the path to a file or folder. If a file is passed,
you must pass the path to an ODF file (odt or ods).
ogrep will be run on this file only. If a folder is
passed, ogrep will be run on all ODF files found in
this folder and sub-folders.
optional arguments:
-h, --help show this help message and exit
-r REPL, --repl REPL if this replacement string is passed, within matched
ODF files, the keyword will be replaced with it. The
replacement string may contain references to groups
possibly defined within the "keyword" regular
expression, but only via the "\<nb>" notation.
-v, --verbose dump more info about the find/replace zones (only
available if option "-c" is not used).
-vv similar to -v, must with even more *v*erbosity.
-d, --dry-run in the context of a replacement, if this option is
set, no replacement will actually be performed, but
output will give info (detailed if -v, minimal if not)
about what replacements would have been performed
without this option.
-c, --in-content if unset, the find/replace process will only apply to
the POD-controlled zones of POD template(s): notes and
fields. If the option is set, it will occur in any
part of the template(s).
-s, --as-string by default, keyword is interpreted as a regular
expression. If you want it to be a plain *s*tring
instead, set this option.
-n, --nice if set in conjunction with -v or -vv, changes (being
effective or potential, depending on -d) will be
colorized. Else, changes will be rendered as standard
diff output.