Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
OpnSense
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kulya
OpnSense
Commits
8e107684
Commit
8e107684
authored
Apr 06, 2015
by
Ad Schellevis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
style fixes configd
parent
cba10171
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
104 additions
and
108 deletions
+104
-108
__init__.py
src/opnsense/service/modules/addons/__init__.py
+1
-0
template_helpers.py
src/opnsense/service/modules/addons/template_helpers.py
+7
-5
config.py
src/opnsense/service/modules/config.py
+7
-9
ph_inline_actions.py
src/opnsense/service/modules/ph_inline_actions.py
+3
-3
processhandler.py
src/opnsense/service/modules/processhandler.py
+43
-43
template.py
src/opnsense/service/modules/template.py
+43
-48
No files found.
src/opnsense/service/modules/addons/__init__.py
View file @
8e107684
...
...
@@ -29,3 +29,4 @@
--------------------------------------------------------------------------------------
package : configd
"""
src/opnsense/service/modules/addons/template_helpers.py
View file @
8e107684
...
...
@@ -30,8 +30,9 @@
package : configd
"""
class
Helpers
(
object
):
def
__init__
(
self
,
template_in_data
):
def
__init__
(
self
,
template_in_data
):
""" initialize template helpers
:param template_in_data:
...
...
@@ -39,22 +40,22 @@ class Helpers(object):
"""
self
.
_template_in_data
=
template_in_data
def
getNodeByTag
(
self
,
tag
):
def
getNodeByTag
(
self
,
tag
):
""" get tree node by tag
:param tag: tag in dot notation (section.item)
:return: dict or None if not found
"""
node
=
self
.
_template_in_data
for
item
in
tag
.
split
(
'.'
):
if
node
.
has_key
(
item
)
:
node
=
node
[
item
]
if
item
in
node
:
node
=
node
[
item
]
else
:
# not found
return
None
# path found, return
return
node
def
exists
(
self
,
tag
):
def
exists
(
self
,
tag
):
"""
check if node exists in dictionary structure
:param tag: tag in dot notation (section.item)
...
...
@@ -64,3 +65,4 @@ class Helpers(object):
return
True
else
:
return
False
src/opnsense/service/modules/config.py
View file @
8e107684
...
...
@@ -43,7 +43,7 @@ import xml.etree.cElementTree as ElementTree
class
Config
(
object
):
def
__init__
(
self
,
filename
):
def
__init__
(
self
,
filename
):
self
.
_filename
=
filename
self
.
_config_data
=
{}
self
.
_file_mod
=
0
...
...
@@ -62,25 +62,25 @@ class Config(object):
self
.
_config_data
=
self
.
_traverse
(
root
)
self
.
_file_mod
=
mod_time
def
_traverse
(
self
,
xmlNode
):
def
_traverse
(
self
,
xmlNode
):
""" traverse xml node and return ordered dictionary structure
:param xmlNode: ElementTree node
:return: collections.OrderedDict
"""
this_item
=
collections
.
OrderedDict
()
if
len
(
list
(
xmlNode
))
>
0
:
if
len
(
list
(
xmlNode
))
>
0
:
for
item
in
list
(
xmlNode
):
item_content
=
self
.
_traverse
(
item
)
if
this_item
.
has_key
(
item
.
tag
)
:
if
item
.
tag
in
this_item
:
if
type
(
this_item
[
item
.
tag
])
!=
list
:
tmp_item
=
copy
.
deepcopy
(
this_item
[
item
.
tag
])
this_item
[
item
.
tag
]
=
[]
this_item
[
item
.
tag
]
.
append
(
tmp_item
)
if
item_content
!=
None
:
if
item_content
is
not
None
:
# skip empty fields
this_item
[
item
.
tag
]
.
append
(
item_content
)
elif
item_content
!=
None
:
elif
item_content
is
not
None
:
# create a new named item
this_item
[
item
.
tag
]
=
self
.
_traverse
(
item
)
else
:
...
...
@@ -89,8 +89,7 @@ class Config(object):
return
this_item
def
indent
(
self
,
elem
,
level
=
0
):
def
indent
(
self
,
elem
,
level
=
0
):
""" indent cElementTree (prettyprint fix)
used from : http://infix.se/2007/02/06/gentlemen-indent-your-xml
@param elem: cElementTree
...
...
@@ -110,7 +109,6 @@ class Config(object):
if
level
and
(
not
elem
.
tail
or
not
elem
.
tail
.
strip
()):
elem
.
tail
=
i
def
get
(
self
):
""" get active config data, load from disc if file in memory is different
...
...
src/opnsense/service/modules/ph_inline_actions.py
View file @
8e107684
...
...
@@ -37,14 +37,14 @@ __author__ = 'Ad Schellevis'
import
syslog
def
execute
(
action
,
parameters
):
def
execute
(
action
,
parameters
):
""" wrapper for inline functions
:param action: action object ( processhandler.Action type )
:param parameters: parameter string
:return: status ( string )
"""
if
action
.
command
==
'template.reload'
:
if
action
.
command
==
'template.reload'
:
import
template
import
config
tmpl
=
template
.
Template
(
action
.
root_dir
)
...
...
@@ -54,7 +54,7 @@ def execute(action,parameters):
# send generated filenames to syslog
for
filename
in
filenames
:
syslog
.
syslog
(
syslog
.
LOG_DEBUG
,
'
%
s generated
%
s'
%
(
parameters
,
filename
)
)
syslog
.
syslog
(
syslog
.
LOG_DEBUG
,
'
%
s generated
%
s'
%
(
parameters
,
filename
)
)
del
conf
del
tmpl
...
...
src/opnsense/service/modules/processhandler.py
View file @
8e107684
...
...
@@ -47,6 +47,7 @@ import uuid
import
shlex
import
ph_inline_actions
class
Handler
(
object
):
""" Main handler class, opens unix domain socket and starts listening
- New connections are handed over to a HandlerClient type object in a new thread
...
...
@@ -58,12 +59,12 @@ class Handler(object):
-> execute ActionHandler command using Action objects
<- send back result string
"""
def
__init__
(
self
,
socket_filename
,
config_path
,
simulation_mode
=
False
):
def
__init__
(
self
,
socket_filename
,
config_path
,
simulation_mode
=
False
):
""" Constructor
:param socket_filename: filename of unix domain socket to use
:param config_path: location of configuration files
:param
emulat
e: emulation mode, do not start actual (script) commands
:param
simulation_mod
e: emulation mode, do not start actual (script) commands
:return: object
"""
self
.
socket_filename
=
socket_filename
...
...
@@ -90,7 +91,7 @@ class Handler(object):
sock
=
socket
.
socket
(
socket
.
AF_UNIX
,
socket
.
SOCK_STREAM
)
sock
.
bind
(
self
.
socket_filename
)
os
.
chmod
(
self
.
socket_filename
,
0o666
)
os
.
chmod
(
self
.
socket_filename
,
0o666
)
sock
.
listen
(
30
)
while
True
:
# wait for a connection to arrive
...
...
@@ -100,7 +101,7 @@ class Handler(object):
client_address
=
client_address
,
action_handler
=
actHandler
,
simulation_mode
=
self
.
simulation_mode
)
if
self
.
single_threaded
:
if
self
.
single_threaded
:
# run single threaded
cmd_thread
.
run
()
else
:
...
...
@@ -116,20 +117,20 @@ class Handler(object):
except
:
# something went wrong... send traceback to syslog, restart listener (wait for a short time)
print
(
traceback
.
format_exc
())
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Handler died on
%
s'
%
traceback
.
format_exc
())
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Handler died on
%
s'
%
traceback
.
format_exc
())
time
.
sleep
(
1
)
class
HandlerClient
(
threading
.
Thread
):
""" Handle commands via specified socket connection
"""
def
__init__
(
self
,
connection
,
client_address
,
action_handler
,
simulation_mode
=
False
):
def
__init__
(
self
,
connection
,
client_address
,
action_handler
,
simulation_mode
=
False
):
"""
:param connection: socket connection object
:param client_address: client address ( from socket accept )
:param action_handler: action handler object
:param
emulat
e: Emulation mode, do not start actual (script) commands
:param
simulation_mod
e: Emulation mode, do not start actual (script) commands
:return: None
"""
threading
.
Thread
.
__init__
(
self
)
...
...
@@ -180,10 +181,10 @@ class HandlerClient(threading.Thread):
# execute requested action
if
self
.
simulation_mode
:
self
.
action_handler
.
showAction
(
exec_command
,
exec_action
,
exec_params
)
self
.
action_handler
.
showAction
(
exec_command
,
exec_action
,
exec_params
)
result
=
'OK'
else
:
result
=
self
.
action_handler
.
execute
(
exec_command
,
exec_action
,
exec_params
)
result
=
self
.
action_handler
.
execute
(
exec_command
,
exec_action
,
exec_params
)
if
not
exec_in_background
:
# send response back to client( including trailing enter )
...
...
@@ -197,7 +198,7 @@ class HandlerClient(threading.Thread):
# send end of stream characters
if
not
exec_in_background
:
self
.
connection
.
sendall
(
"
%
c
%
c
%
c"
%
(
chr
(
0
),
chr
(
0
),
chr
(
0
)))
self
.
connection
.
sendall
(
"
%
c
%
c
%
c"
%
(
chr
(
0
),
chr
(
0
),
chr
(
0
)))
except
SystemExit
:
# ignore system exit related errors
pass
...
...
@@ -214,10 +215,11 @@ class HandlerClient(threading.Thread):
if
not
exec_in_background
:
self
.
connection
.
close
()
class
ActionHandler
(
object
):
""" Start/stop services and functions using configuration data defined in conf/actions_<topic>.conf
"""
def
__init__
(
self
,
config_path
):
def
__init__
(
self
,
config_path
):
""" Initialize action handler to start system functions
:param config_path: full path of configuration data
...
...
@@ -234,11 +236,12 @@ class ActionHandler(object):
"""
self
.
action_map
=
{}
for
config_filename
in
glob
.
glob
(
'
%
s/actions_*.conf'
%
(
self
.
config_path
))
+
glob
.
glob
(
'
%
s/actions.d/actions_*.conf'
%
(
self
.
config_path
)):
for
config_filename
in
glob
.
glob
(
'
%
s/actions_*.conf'
%
self
.
config_path
)
\
+
glob
.
glob
(
'
%
s/actions.d/actions_*.conf'
%
self
.
config_path
):
# this topic's name (service, filter, template, etc)
# make sure there's an action map index for this topic
topic_name
=
config_filename
.
split
(
'actions_'
)[
-
1
]
.
split
(
'.'
)[
0
]
if
self
.
action_map
.
has_key
(
topic_name
)
==
False
:
if
topic_name
not
in
self
.
action_map
:
self
.
action_map
[
topic_name
]
=
{}
# traverse config directory and open all filenames starting with actions_
...
...
@@ -248,12 +251,12 @@ class ActionHandler(object):
# map configuration data on object
action_obj
=
Action
()
for
act_prop
in
cnf
.
items
(
section
):
setattr
(
action_obj
,
act_prop
[
0
],
act_prop
[
1
])
setattr
(
action_obj
,
act_prop
[
0
],
act_prop
[
1
])
if
section
.
find
(
'.'
)
>
-
1
:
# at this moment we only support 2 levels of actions ( 3 if you count topic as well )
for
alias
in
section
.
split
(
'.'
)[
0
]
.
split
(
'|'
):
if
self
.
action_map
[
topic_name
]
.
has_key
(
alias
)
==
False
:
if
alias
not
in
self
.
action_map
[
topic_name
]
:
self
.
action_map
[
topic_name
][
alias
]
=
{}
self
.
action_map
[
topic_name
][
alias
][
section
.
split
(
'.'
)[
1
]]
=
action_obj
else
:
...
...
@@ -269,20 +272,20 @@ class ActionHandler(object):
:return: action object or None if not found
"""
action_obj
=
None
if
self
.
action_map
.
has_key
(
command
)
:
if
self
.
action_map
[
command
]
.
has_key
(
action
)
:
if
command
in
self
.
action_map
:
if
action
in
self
.
action_map
[
command
]
:
if
type
(
self
.
action_map
[
command
][
action
])
==
dict
:
if
len
(
parameters
)
>
0
and
self
.
action_map
[
command
][
action
]
.
has_key
(
parameters
[
0
])
==
True
:
if
len
(
parameters
)
>
0
and
parameters
[
0
]
in
self
.
action_map
[
command
][
action
]
:
# 3 level action ( "interface linkup start" for example )
if
isinstance
(
self
.
action_map
[
command
][
action
][
parameters
[
0
]],
Action
):
if
isinstance
(
self
.
action_map
[
command
][
action
][
parameters
[
0
]],
Action
):
action_obj
=
self
.
action_map
[
command
][
action
][
parameters
[
0
]]
action_obj
.
setParameterStartPos
(
1
)
elif
isinstance
(
self
.
action_map
[
command
][
action
],
Action
):
elif
isinstance
(
self
.
action_map
[
command
][
action
],
Action
):
action_obj
=
self
.
action_map
[
command
][
action
]
return
action_obj
def
execute
(
self
,
command
,
action
,
parameters
):
def
execute
(
self
,
command
,
action
,
parameters
):
""" execute configuration defined action
:param command: command/topic for example interface
...
...
@@ -291,27 +294,27 @@ class ActionHandler(object):
:return: OK on success, else error code
"""
action_params
=
[]
action_obj
=
self
.
findAction
(
command
,
action
,
parameters
)
action_obj
=
self
.
findAction
(
command
,
action
,
parameters
)
if
action_obj
is
not
None
:
if
parameters
is
not
None
and
len
(
parameters
)
>
action_obj
.
getParameterStartPos
():
action_params
=
parameters
[
action_obj
.
getParameterStartPos
():]
return
'
%
s
\n
'
%
action_obj
.
execute
(
action_params
)
return
'
%
s
\n
'
%
action_obj
.
execute
(
action_params
)
return
'Action not found
\n
'
def
showAction
(
self
,
command
,
action
,
parameters
):
def
showAction
(
self
,
command
,
action
,
parameters
):
""" debug/simulation mode: show action information
:return:
"""
action_obj
=
self
.
findAction
(
command
,
action
,
parameters
)
action_obj
=
self
.
findAction
(
command
,
action
,
parameters
)
print
(
'---------------------------------------------------------------------'
)
print
(
'execute
%
s.
%
s with parameters :
%
s '
%
(
command
,
action
,
parameters
)
)
print
(
'action object
%
s (
%
s)'
%
(
action_obj
,
action_obj
.
command
)
)
print
(
'execute
%
s.
%
s with parameters :
%
s '
%
(
command
,
action
,
parameters
)
)
print
(
'action object
%
s (
%
s)'
%
(
action_obj
,
action_obj
.
command
)
)
print
(
'---------------------------------------------------------------------'
)
class
Action
(
object
):
""" Action class, handles actual (system) calls.
set command, parameters (template) type and log message
...
...
@@ -327,7 +330,7 @@ class Action(object):
self
.
message
=
None
self
.
_parameter_start_pos
=
0
def
setParameterStartPos
(
self
,
pos
):
def
setParameterStartPos
(
self
,
pos
):
"""
:param pos: start position of parameter list
...
...
@@ -341,7 +344,7 @@ class Action(object):
"""
return
self
.
_parameter_start_pos
def
execute
(
self
,
parameters
):
def
execute
(
self
,
parameters
):
""" execute an action
:param parameters: list of parameters
...
...
@@ -350,15 +353,15 @@ class Action(object):
# send-out syslog message
if
self
.
message
is
not
None
:
if
self
.
message
.
count
(
'
%
s'
)
>
0
and
parameters
is
not
None
and
len
(
parameters
)
>
0
:
syslog
.
syslog
(
syslog
.
LOG_NOTICE
,
self
.
message
%
tuple
(
parameters
[
0
:
self
.
message
.
count
(
'
%
s'
)])
)
syslog
.
syslog
(
syslog
.
LOG_NOTICE
,
self
.
message
%
tuple
(
parameters
[
0
:
self
.
message
.
count
(
'
%
s'
)])
)
else
:
syslog
.
syslog
(
syslog
.
LOG_NOTICE
,
self
.
message
)
syslog
.
syslog
(
syslog
.
LOG_NOTICE
,
self
.
message
)
# validate input
if
self
.
type
is
None
:
# no action type, nothing to do here
return
'No action type'
elif
self
.
type
.
lower
()
in
(
'script'
,
'script_output'
):
elif
self
.
type
.
lower
()
in
(
'script'
,
'script_output'
):
# script type commands, basic script type only uses exit statuses, script_output sends back stdout data.
if
self
.
command
is
None
:
# no command supplied, exit
...
...
@@ -367,11 +370,11 @@ class Action(object):
# build script command to execute, shared for both types
script_command
=
self
.
command
if
self
.
parameters
is
not
None
and
type
(
self
.
parameters
)
==
str
:
script_command
=
'
%
s
%
s'
%
(
script_command
,
self
.
parameters
)
script_command
=
'
%
s
%
s'
%
(
script_command
,
self
.
parameters
)
if
script_command
.
find
(
'
%
s'
)
>
-
1
and
len
(
parameters
)
>
0
:
# use command execution parameters in action parameter template
# use quotes on parameters to prevent code injection
script_command
=
script_command
%
tuple
(
map
(
lambda
x
:
'"'
+
x
.
replace
(
'"'
,
'
\\
"'
)
+
'"'
,
script_command
=
script_command
%
tuple
(
map
(
lambda
x
:
'"'
+
x
.
replace
(
'"'
,
'
\\
"'
)
+
'"'
,
parameters
[
0
:
script_command
.
count
(
'
%
s'
)]))
if
self
.
type
.
lower
()
==
'script'
:
...
...
@@ -382,16 +385,16 @@ class Action(object):
if
exit_status
==
0
:
return
'OK'
else
:
return
'Error (
%
d)'
%
exit_status
return
'Error (
%
d)'
%
exit_status
except
:
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Script action failed at
%
s'
%
traceback
.
format_exc
())
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Script action failed at
%
s'
%
traceback
.
format_exc
())
return
'Execute error'
elif
self
.
type
.
lower
()
==
'script_output'
:
try
:
script_output
=
subprocess
.
check_output
(
script_command
,
shell
=
True
)
return
script_output
except
:
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Script action failed at
%
s'
%
traceback
.
format_exc
())
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Script action failed at
%
s'
%
traceback
.
format_exc
())
return
'Execute error'
# fallback should never get here
...
...
@@ -405,13 +408,10 @@ class Action(object):
else
:
inline_act_parameters
=
''
return
ph_inline_actions
.
execute
(
self
,
inline_act_parameters
)
return
ph_inline_actions
.
execute
(
self
,
inline_act_parameters
)
except
:
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Inline action failed at
%
s'
%
traceback
.
format_exc
())
syslog
.
syslog
(
syslog
.
LOG_ERR
,
'Inline action failed at
%
s'
%
traceback
.
format_exc
())
return
'Execute error'
return
'Unknown action type'
src/opnsense/service/modules/template.py
View file @
8e107684
...
...
@@ -41,9 +41,10 @@ import copy
import
jinja2
import
addons.template_helpers
class
Template
(
object
):
def
__init__
(
self
,
target_root_directory
=
"/"
):
def
__init__
(
self
,
target_root_directory
=
"/"
):
""" constructor
:return:
"""
...
...
@@ -55,82 +56,80 @@ class Template(object):
# setup jinja2 environment
self
.
_template_dir
=
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
))
+
'/../templates/'
self
.
_j2_env
=
jinja2
.
Environment
(
loader
=
jinja2
.
FileSystemLoader
(
self
.
_template_dir
),
trim_blocks
=
True
)
self
.
_j2_env
=
jinja2
.
Environment
(
loader
=
jinja2
.
FileSystemLoader
(
self
.
_template_dir
),
trim_blocks
=
True
)
def
_readManifest
(
self
,
filename
):
def
_readManifest
(
self
,
filename
):
"""
:param filename: manifest filename (path/+MANIFEST)
:return: dictionary containing manifest items
"""
result
=
{}
for
line
in
open
(
filename
,
'r'
)
.
read
()
.
split
(
'
\n
'
):
parts
=
line
.
split
(
':'
)
for
line
in
open
(
filename
,
'r'
)
.
read
()
.
split
(
'
\n
'
):
parts
=
line
.
split
(
':'
)
if
len
(
parts
)
>
1
:
result
[
parts
[
0
]]
=
':'
.
join
(
parts
[
1
:])
return
result
def
_readTargets
(
self
,
filename
):
def
_readTargets
(
self
,
filename
):
""" read raw target filename masks
:param filename: targets filename (path/+TARGETS)
:return: dictionary containing +TARGETS filename sets
"""
result
=
{}
for
line
in
open
(
filename
,
'r'
)
.
read
()
.
split
(
'
\n
'
):
parts
=
line
.
split
(
':'
)
for
line
in
open
(
filename
,
'r'
)
.
read
()
.
split
(
'
\n
'
):
parts
=
line
.
split
(
':'
)
if
len
(
parts
)
>
1
and
parts
[
0
]
.
strip
()[
0
]
!=
'#'
:
result
[
parts
[
0
]]
=
':'
.
join
(
parts
[
1
:])
.
strip
()
return
result
def
list_module
(
self
,
module_name
,
read_manifest
=
False
):
def
list_module
(
self
,
module_name
,
read_manifest
=
False
):
""" list single module content
:param module_name: module name in dot notation ( company.module )
:param read_manifest: boolean, read manifest file if it exists
:return: dictionary with module data
"""
result
=
{}
file_path
=
'
%
s/
%
s'
%
(
self
.
_template_dir
,
module_name
.
replace
(
'.'
,
'/'
))
if
os
.
path
.
exists
(
'
%
s/+MANIFEST'
%
file_path
)
and
read_manifest
:
result
[
'+MANIFEST'
]
=
self
.
_readManifest
(
'
%
s/+MANIFEST'
%
file_path
)
if
os
.
path
.
exists
(
'
%
s/+TARGETS'
%
file_path
)
:
result
[
'+TARGETS'
]
=
self
.
_readTargets
(
'
%
s/+TARGETS'
%
file_path
)
file_path
=
'
%
s/
%
s'
%
(
self
.
_template_dir
,
module_name
.
replace
(
'.'
,
'/'
))
if
os
.
path
.
exists
(
'
%
s/+MANIFEST'
%
file_path
)
and
read_manifest
:
result
[
'+MANIFEST'
]
=
self
.
_readManifest
(
'
%
s/+MANIFEST'
%
file_path
)
if
os
.
path
.
exists
(
'
%
s/+TARGETS'
%
file_path
)
:
result
[
'+TARGETS'
]
=
self
.
_readTargets
(
'
%
s/+TARGETS'
%
file_path
)
else
:
result
[
'+TARGETS'
]
=
{}
return
result
def
list_modules
(
self
,
read_manifest
=
False
):
def
list_modules
(
self
):
""" traverse template directory and list all modules
the template directory is structured like Manufacturer/Module/config_files
:param read_manifest: boolean, read manifest file if it exists
:return: list (dict) of registered modules
"""
result
=
{}
for
root
,
dirs
,
files
in
os
.
walk
(
self
.
_template_dir
):
if
len
(
root
)
>
len
(
self
.
_template_dir
):
module_name
=
'.'
.
join
(
root
.
replace
(
self
.
_template_dir
,
''
)
.
split
(
'/'
)[:
2
])
if
result
.
has_key
(
module_name
)
==
False
:
module_name
=
'.'
.
join
(
root
.
replace
(
self
.
_template_dir
,
''
)
.
split
(
'/'
)[:
2
])
if
module_name
not
in
result
:
result
[
module_name
]
=
self
.
list_module
(
module_name
)
return
result
def
setConfig
(
self
,
config_data
):
def
setConfig
(
self
,
config_data
):
""" set config data
:param config_data: config data as dictionary/list structure
:return: None
"""
if
type
(
config_data
)
in
(
dict
,
collections
.
OrderedDict
):
if
type
(
config_data
)
in
(
dict
,
collections
.
OrderedDict
):
self
.
_config
=
config_data
else
:
# no data given, reset
self
.
_config
=
{}
def
__findStringTags
(
self
,
instr
):
def
__findStringTags
(
self
,
instr
):
"""
:param instr: string with optional tags [field.$$]
:return:
...
...
@@ -142,7 +141,7 @@ class Template(object):
return
retval
def
__findFilters
(
self
,
tags
):
def
__findFilters
(
self
,
tags
):
""" match tags to config and construct a dictionary which we can use to construct the output filenames
:param tags: list of tags [xmlnode.xmlnode.
%
.xmlnode,xmlnode]
:return: dictionary containing key (tagname) value {existing node key, value}
...
...
@@ -155,25 +154,25 @@ class Template(object):
config_ptr
=
self
.
_config
target_keys
=
[]
for
xmlNodeName
in
tag
.
split
(
'.'
):
if
config_ptr
.
has_key
(
xmlNodeName
)
:
if
xmlNodeName
in
config_ptr
:
config_ptr
=
config_ptr
[
xmlNodeName
]
elif
xmlNodeName
==
'
%
'
:
target_keys
=
config_ptr
.
keys
()
else
:
break
if
len
(
target_keys
)
==
0
:
if
len
(
target_keys
)
==
0
:
# single node, only used for string replacement in output name.
result
[
tag
]
=
{
tag
:
config_ptr
}
result
[
tag
]
=
{
tag
:
config_ptr
}
else
:
# multiple node's, find all nodes
for
target_node
in
target_keys
:
config_ptr
=
self
.
_config
str_wildcard_loc
=
len
(
tag
.
split
(
'
%
'
)[
0
]
.
split
(
'.'
))
filter_target
=
[]
for
xmlNodeName
in
tag
.
replace
(
'
%
'
,
target_node
)
.
split
(
'.'
):
if
config_ptr
.
has_key
(
xmlNodeName
)
:
if
type
(
config_ptr
[
xmlNodeName
])
in
(
collections
.
OrderedDict
,
dict
):
filter_target
=
[]
for
xmlNodeName
in
tag
.
replace
(
'
%
'
,
target_node
)
.
split
(
'.'
):
if
xmlNodeName
in
config_ptr
:
if
type
(
config_ptr
[
xmlNodeName
])
in
(
collections
.
OrderedDict
,
dict
):
if
str_wildcard_loc
>=
len
(
filter_target
):
filter_target
.
append
(
xmlNodeName
)
if
str_wildcard_loc
==
len
(
filter_target
):
...
...
@@ -186,47 +185,44 @@ class Template(object):
return
result
def
_create_directory
(
self
,
filename
):
def
_create_directory
(
self
,
filename
):
""" create directory
:param filename: create path for filename ( if not existing )
:return: None
"""
fparts
=
[]
fparts
=
[]
for
fpart
in
filename
.
strip
()
.
split
(
'/'
)[:
-
1
]:
fparts
.
append
(
fpart
)
if
len
(
fpart
)
>
1
:
if
os
.
path
.
exists
(
'/'
.
join
(
fparts
))
==
False
:
if
len
(
fpart
)
>
1
:
if
not
os
.
path
.
exists
(
'/'
.
join
(
fparts
))
:
os
.
mkdir
(
'/'
.
join
(
fparts
))
def
generate
(
self
,
module_name
,
create_directory
=
True
):
def
generate
(
self
,
module_name
,
create_directory
=
True
):
""" generate configuration files using bound config and template data
:param module_name: module name in dot notation ( company.module )
:param create_directory: automatically create directories to place template output in ( if not existing )
:return: list of generated output files
"""
result
=
[]
result
=
[]
module_data
=
self
.
list_module
(
module_name
)
for
src_template
in
module_data
[
'+TARGETS'
]
.
keys
():
target
=
module_data
[
'+TARGETS'
][
src_template
]
target
=
module_data
[
'+TARGETS'
][
src_template
]
target_filename_tags
=
self
.
__findStringTags
(
target
)
target_filters
=
self
.
__findFilters
(
target_filename_tags
)
result_filenames
=
{
target
:{}}
result_filenames
=
{
target
:
{}}
for
target_filter
in
target_filters
.
keys
():
for
key
in
target_filters
[
target_filter
]
.
keys
():
for
filename
in
result_filenames
.
keys
():
if
filename
.
find
(
'[
%
s]'
%
target_filter
)
>
-
1
:
new_filename
=
filename
.
replace
(
'[
%
s]'
%
target_filter
,
target_filters
[
target_filter
][
key
])
if
filename
.
find
(
'[
%
s]'
%
target_filter
)
>
-
1
:
new_filename
=
filename
.
replace
(
'[
%
s]'
%
target_filter
,
target_filters
[
target_filter
][
key
])
result_filenames
[
new_filename
]
=
copy
.
deepcopy
(
result_filenames
[
filename
])
result_filenames
[
new_filename
][
key
]
=
target_filters
[
target_filter
][
key
]
j2_page
=
self
.
_j2_env
.
get_template
(
'
%
s/
%
s'
%
(
module_name
.
replace
(
'.'
,
'/'
),
src_template
))
j2_page
=
self
.
_j2_env
.
get_template
(
'
%
s/
%
s'
%
(
module_name
.
replace
(
'.'
,
'/'
),
src_template
))
for
filename
in
result_filenames
.
keys
():
if
not
(
filename
.
find
(
'['
)
!=
-
1
and
filename
.
find
(
']'
)
!=
-
1
)
:
if
not
(
filename
.
find
(
'['
)
!=
-
1
and
filename
.
find
(
']'
)
!=
-
1
)
:
# copy config data
cnf_data
=
copy
.
deepcopy
(
self
.
_config
)
cnf_data
[
'TARGET_FILTERS'
]
=
result_filenames
[
filename
]
...
...
@@ -240,16 +236,15 @@ class Template(object):
content
=
j2_page
.
render
(
cnf_data
)
# prefix filename with defined root directory
filename
=
(
'
%
s/
%
s'
%
(
self
.
_target_root_directory
,
filename
))
.
replace
(
'//'
,
'/'
)
filename
=
(
'
%
s/
%
s'
%
(
self
.
_target_root_directory
,
filename
))
.
replace
(
'//'
,
'/'
)
if
create_directory
:
# make sure the target directory exists
self
.
_create_directory
(
filename
)
f_out
=
open
(
filename
,
'wb'
)
f_out
=
open
(
filename
,
'wb'
)
f_out
.
write
(
content
)
f_out
.
close
()
result
.
append
(
filename
)
return
result
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment