Merge branch 'master' into notifications

Took the __file parts from master.

Signed-off-by: Nico Schottelius <nico@bento.schottelius.org>

Conflicts:
	cdist/conf/type/__file/gencode-local
	cdist/conf/type/__file/gencode-remote
This commit is contained in:
Nico Schottelius 2013-12-03 14:38:11 +01:00
commit 684ad56a80
21 changed files with 401 additions and 190 deletions

1
.gitignore vendored
View File

@ -29,3 +29,4 @@ cdist/version.py
build
.lock-*
.git-current-branch
.lock*

View File

@ -1,39 +0,0 @@
#!/bin/sh
#
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Check whether file exists or not
#
destination="/$__object_id"
os=$("$__explorer/os")
case "$os" in
"freebsd")
cmd="stat -f %Su"
;;
*)
cmd="stat -c %U"
;;
esac
if [ -e "$destination" ]; then
$cmd "$destination"
fi

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,23 +17,27 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Check whether file exists or not
#
destination="/$__object_id"
os=$("$__explorer/os")
# nothing to work with, nothing we could do
[ -e "$destination" ] || exit 0
os=$("$__explorer/os")
case "$os" in
"freebsd")
cmd="stat -f %Sg"
;;
# FIXME: should be something like this based on man page, but can not test
stat -f "type: %ST
owner: %Du %Su
group: %Dg %Sg
mode: %Op %Sp
" "$destination"
;;
*)
cmd="stat -c %G"
;;
stat --printf="type: %F
owner: %u %U
group: %g %G
mode: %a %A
" "$destination"
;;
esac
if [ -e "$destination" ]; then
$cmd "$destination"
fi

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,14 +17,17 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Check whether file exists or not
#
destination="/$__object_id"
if [ -e "$destination" ]; then
echo yes
if [ ! -e "$destination" ]; then
echo none
elif [ -h "$destination" ]; then
echo symlink
elif [ -f "$destination" ]; then
echo file
elif [ -d "$destination" ]; then
echo directory
else
echo no
echo unknown
fi

View File

@ -1,6 +1,7 @@
#!/bin/sh
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2011-2013 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -19,53 +20,84 @@
#
destination="/$__object_id"
state_should="$(cat "$__object/parameter/state")"
type="$(cat "$__object/explorer/type")"
stat_file="$__object/explorer/stat"
state_is="$(cat "$__object/explorer/state")"
owner_is="$(cat "$__object/explorer/owner")"
group_is="$(cat "$__object/explorer/group")"
mode_is="$(cat "$__object/explorer/mode")"
# variable to keep track if we have to set directory attributes
set_attributes=
state_should="present"
[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
mode=""
[ -f "$__object/parameter/mode" ] && mode="$(cat "$__object/parameter/mode")"
owner=""
[ -f "$__object/parameter/owner" ] && owner="$(cat "$__object/parameter/owner")"
group=""
[ -f "$__object/parameter/group" ] && group="$(cat "$__object/parameter/group")"
mkdiropt=""
[ -f "$__object/parameter/parents" ] && mkdiropt="-p"
[ -f "$__object/parameter/parents" ] && mkdiropt="-p"
recursive=""
[ -f "$__object/parameter/recursive" ] && recursive="-R"
if [ -f "$__object/parameter/recursive" ]; then
recursive="-R"
# need to allways set attributes when recursive is given
# as we don't want to check all subfolders/files
set_attributes=1
fi
get_current_value() {
if [ -s "$stat_file" ]; then
_name="$1"
_value="$2"
case "$_value" in
[0-9]*)
_index=2
;;
*)
_index=3
;;
esac
awk '/'"$_name"':/ { print $'$_index' }' "$stat_file"
unset _name _value _index
fi
}
set_group() {
echo chgrp $recursive \"$1\" \"$destination\"
}
set_owner() {
echo chown $recursive \"$1\" \"$destination\"
}
set_mode() {
echo chmod $recursive \"$1\" \"$destination\"
}
case "$state_should" in
present)
if [ "$state_is" != "present" ]; then
echo mkdir $mkdiropt \"$destination\"
fi
present)
if [ "$type" != "directory" ]; then
# our destination is not a directory, remove whatever is there
# and then create our directory and set all attributes
set_attributes=1
cat << DONE
rm -f "$destination"
mkdir $mkdiropt "$destination"
DONE
fi
# Mode settings
if [ "$mode" ] && [ "$mode_is" != "$mode" -o -n "$recursive" ]; then
echo chmod $recursive \"$mode\" \"$destination\"
fi
# Group
if [ "$group" ] && [ "$group_is" != "$group" -o -n "$recursive" ]; then
echo chgrp $recursive \"$group\" \"$destination\"
fi
# Owner
if [ "$owner" ] && [ "$owner_is" != "$owner" -o -n "$recursive" ]; then
echo chown $recursive \"$owner\" \"$destination\"
fi
;;
absent)
if [ "$state_is" != "absent" ]; then
echo rm -rf \"$destination\"
fi
;;
*)
echo "Unknown state: $state_should" >&2
exit 1
;;
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
# clearing S_ISUID and S_ISGID bits (see chown(2))
for attribute in group owner mode; do
if [ -f "$__object/parameter/$attribute" ]; then
value_should="$(cat "$__object/parameter/$attribute")"
value_is="$(get_current_value "$attribute" "$value_should")"
if [ "$set_attributes" -o "$value_should" != "$value_is" ]; then
"set_$attribute" "$value_should"
fi
fi
done
;;
absent)
if [ "$type" = "directory" ]; then
echo rm -rf \"$destination\"
fi
;;
*)
echo "Unknown state: $state_should" >&2
exit 1
;;
esac

View File

@ -0,0 +1 @@
present

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,23 +17,31 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Check whether file exists or not
#
destination="/$__object_id"
os=$("$__explorer/os")
# nothing to work with, nothing we could do
[ -e "$destination" ] || exit 0
os=$("$__explorer/os")
case "$os" in
"freebsd")
cmd="stat -f %Op"
;;
# FIXME: should be something like this based on man page, but can not test
stat -f "type: %ST
owner: %Du %Su
group: %Dg %Sg
mode: %Op %Sp
size: %Dz
links: %Dl
" "$destination"
;;
*)
cmd="stat -c %a"
;;
stat --printf="type: %F
owner: %u %U
group: %g %G
mode: %a %A
size: %s
links: %h
" "$destination"
;;
esac
if [ -e "$destination" ]; then
$cmd "$destination"
fi

View File

@ -1,6 +1,6 @@
#!/bin/sh
#
# 2011 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,14 +17,17 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Check whether file exists or not
#
destination="/$__object_id"
if [ -e "$destination" ]; then
echo present
if [ ! -e "$destination" ]; then
echo none
elif [ -h "$destination" ]; then
echo symlink
elif [ -f "$destination" ]; then
echo file
elif [ -d "$destination" ]; then
echo directory
else
echo absent
echo unknown
fi

View File

@ -1,6 +1,7 @@
#!/bin/sh
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,35 +18,59 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# __file is a very basic type, which will probably be reused quite often
#
destination="/$__object_id"
state_should=present
[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
exists="$(cat "$__object/explorer/exists")"
state_should="$(cat "$__object/parameter/state")"
type="$(cat "$__object/explorer/type")"
[ "$state_should" = "exists" -a "$exists" = "yes" ] && exit 0 # nothing to do
[ "$state_should" = "exists" -a "$type" = "file" ] && exit 0 # nothing to do
upload_file=
create_file=
if [ "$state_should" = "present" -o "$state_should" = "exists" ]; then
if [ -f "$__object/parameter/source" ]; then
if [ ! -f "$__object/parameter/source" ]; then
create_file=1
else
source="$(cat "$__object/parameter/source")"
if [ "$source" = "-" ]; then
source="$__object/stdin"
fi
if [ -f "$source" ]; then
local_cksum="$(cksum < "$source")"
remote_cksum="$(cat "$__object/explorer/cksum")"
if [ "$local_cksum" != "$remote_cksum" ]; then
echo "$__remote_copy" "$source" "${__target_host}:${destination}"
echo "copy" >> "$__messages_out"
fi
else
if [ ! -f "$source" ]; then
echo "Source \"$source\" does not exist." >&2
exit 1
else
if [ "$type" != "file" ]; then
# destination is not a regular file, upload source to replace it
upload_file=1
else
local_cksum="$(cksum < "$source")"
remote_cksum="$(cat "$__object/explorer/cksum")"
if [ "$local_cksum" != "$remote_cksum" ]; then
# destination is a regular file, but not the right one
upload_file=1
fi
fi
fi
fi
if [ "$create_file" -o "$upload_file" ]; then
# tell gencode-remote that we created or uploaded a file and that it must
# set all attributes no matter what the explorer retreived
mkdir "$__object/files"
touch "$__object/files/set-attributes"
# upload file to temp location
tempfile_template="${destination}.cdist.XXXXXXXXXX"
cat << DONE
destination_upload="\$($__remote_exec $__target_host "mktemp $tempfile_template")"
DONE
if [ "$upload_file" ]; then
cat << DONE
$__remote_copy $source ${__target_host}:\$destination_upload
DONE
fi
# move uploaded file into place
cat << DONE
$__remote_exec $__target_host "rm -rf \"$destination\"; mv \"\$destination_upload\" \"$destination\""
DONE
fi
fi

View File

@ -1,6 +1,7 @@
#!/bin/sh
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
@ -17,59 +18,66 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# __file is a very basic type, which will probably be reused quite often
#
destination="/$__object_id"
state_should=present
[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
exists="$(cat "$__object/explorer/exists")"
state_should="$(cat "$__object/parameter/state")"
type="$(cat "$__object/explorer/type")"
stat_file="$__object/explorer/stat"
get_current_value() {
if [ -s "$stat_file" ]; then
_name="$1"
_value="$2"
case "$_value" in
[0-9]*)
_index=2
;;
*)
_index=3
;;
esac
awk '/'"$_name"':/ { print $'$_index' }' "$stat_file"
unset _name _value _index
fi
}
set_group() {
echo chgrp \"$1\" \"$destination\"
}
set_owner() {
echo chown \"$1\" \"$destination\"
}
set_mode() {
echo chmod \"$1\" \"$destination\"
}
set_attributes=
case "$state_should" in
present|exists)
# No source? Create empty file
if [ ! -f "$__object/parameter/source" ]; then
if [ "$exists" = "no" ]; then
echo touch \"$destination\"
# Note: Mode - needs to happen last as a chown/chgrp can alter mode by
# clearing S_ISUID and S_ISGID bits (see chown(2))
for attribute in group owner mode; do
if [ -f "$__object/parameter/$attribute" ]; then
value_should="$(cat "$__object/parameter/$attribute")"
value_is="$(get_current_value "$attribute" "$value_should")"
if [ -f "$__object/files/set-attributes" -o "$value_should" != "$value_is" ]; then
"set_$attribute" "$value_should"
fi
fi
fi
# Group
if [ -f "$__object/parameter/group" ]; then
echo chgrp \"$(cat "$__object/parameter/group")\" \"$destination\"
# FIXME: only if necessary, not if parameter is present
# echo "chgrp" >> "$__object/notifications"
fi
# Owner
if [ -f "$__object/parameter/owner" ]; then
echo chown \"$(cat "$__object/parameter/owner")\" \"$destination\"
# FIXME: only if necessary, not if parameter is present
# echo "chown" >> "$__object/notifications"
fi
# Mode - needs to happen last as a chown/chgrp can alter mode by
# clearing S_ISUID and S_ISGID bits (see chown(2))
if [ -f "$__object/parameter/mode" ]; then
echo chmod \"$(cat "$__object/parameter/mode")\" \"$destination\"
# FIXME: only if necessary, not if parameter is present
# echo "chmod" >> "$__object/notifications"
fi
done
;;
absent)
if [ "$exists" = "yes" ]; then
if [ "$type" = "file" ]; then
echo rm -f \"$destination\"
echo "remove" >> "$__messages_out"
fi
;;
*)
echo "Unknown state: $state_should" >&2
exit 1
;;
esac

View File

@ -13,6 +13,15 @@ DESCRIPTION
This cdist type allows you to create files, remove files and set file
attributes on the target.
If the file already exists on the target, then if it is a:
- regular file, and state is:
present: replace it with the source file if they are not equal
exists: do nothing
- symlink: replace it with the source file
- directory: replace it with the source file
In any case, make sure that the file attributes are as specified.
REQUIRED PARAMETERS
-------------------

View File

@ -0,0 +1 @@
present

View File

@ -0,0 +1,46 @@
#!/bin/sh
#
# 2013 Steven Armstrong (steven-cdist armstrong.cc)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
# Mostly a wrapper for ln
#
destination="/$__object_id"
if [ ! -e "$destination" ]; then
echo none
elif [ -h "$destination" ]; then
echo symlink
elif [ -f "$destination" ]; then
type="$(cat "$__object/parameter/type")"
case "$type" in
hard)
link_count=$(ls -l "$destination" | awk '{ print $2 }')
if [ $link_count -gt 1 ]; then
echo hardlink
exit 0
fi
;;
esac
echo file
elif [ -d "$destination" ]; then
echo directory
else
echo unknown
fi

View File

@ -1,6 +1,7 @@
#!/bin/sh
#
# 2011-2012 Nico Schottelius (nico-cdist at schottelius.org)
# 2013 Steven Armstrong (steven-cdist at armstrong.cc)
#
# This file is part of cdist.
#
@ -40,17 +41,30 @@ case "$type" in
esac
state_is="$(cat "$__object/explorer/state")"
state_should=present
[ -f "$__object/parameter/state" ] && state_should="$(cat "$__object/parameter/state")"
state_should="$(cat "$__object/parameter/state")"
[ "$state_should" = "$state_is" ] && exit 0
file_type="$(cat "$__object/explorer/type")"
case "$state_should" in
present)
echo ln ${lnopt} -f \"$source\" \"$destination\"
if [ "$file_type" = "directory" ]; then
# our destination is currently a directory, delete it
cat << DONE
rm -rf "$destination"
DONE
fi
# create our link
cat << DONE
ln ${lnopt} -f "$source" "$destination"
DONE
;;
absent)
echo rm -f \"$destination\"
# only delete if it is a sym/hard link
if [ "$file_type" = "symlink" -o "$file_type" = "hardlink" ]; then
echo rm -f \"$destination\"
fi
;;
*)
echo "Unknown state: $state_should" >&2

View File

@ -0,0 +1 @@
present

2
cdist/conf/type/__package_zypper/explorer/pkg_version Executable file → Normal file
View File

@ -27,4 +27,4 @@ else
name="$__object_id"
fi
rpm -q --whatprovides "$name" 2>/dev/null || true
rpm -q --whatprovides "$name" | grep -v 'no package provides' || true

11
cdist/conf/type/__package_zypper/gencode-remote Executable file → Normal file
View File

@ -39,15 +39,22 @@ else
state_should="present"
fi
pkg_version="$(cat "$__object/explorer/pkg_version")"
if [ -z "$pkg_version" ]; then
state_is="absent"
else
state_is="present"
fi
# Exit if nothing is needed to be done
[ "$state_is" = "$state_should" ] && exit 0
case "$state_should" in
present)
echo zypper "$globalopts" install --auto-agree-with-licenses \"$name\"
echo zypper $globalopts install --auto-agree-with-licenses \"$name\" ">/dev/null"
;;
absent)
echo pacman "$globalopts" remove \"$name\"
echo zypper $globalopts remove \"$name\" ">/dev/null"
;;
*)
echo "Unknown state: $state_should" >&2

View File

@ -249,7 +249,7 @@ class Config(object):
cdist_type = cdist_object.cdist_type
# Generate
self.log.info("Generating and executing code for %s" % (cdist_object.name))
self.log.info("Generating code for %s" % (cdist_object.name))
cdist_object.code_local = self.code.run_gencode_local(cdist_object)
cdist_object.code_remote = self.code.run_gencode_remote(cdist_object)
if cdist_object.code_local or cdist_object.code_remote:
@ -257,6 +257,8 @@ class Config(object):
# Execute
if not self.dry_run:
if cdist_object.code_local or cdist_object.code_remote:
self.log.info("Executing code for %s" % (cdist_object.name))
if cdist_object.code_local:
self.code.run_code_local(cdist_object)
if cdist_object.code_remote:

View File

@ -196,8 +196,13 @@ class Local(object):
def save_cache(self):
destination = os.path.join(self.cache_path, self.target_host)
self.log.debug("Saving " + self.base_path + " to " + destination)
if os.path.exists(destination):
shutil.rmtree(destination)
try:
if os.path.exists(destination):
shutil.rmtree(destination)
except PermissionError as e:
raise cdist.Error("Cannot delete old cache %s: %s" % (destination, e))
shutil.move(self.base_path, destination)
def _create_messages(self):

View File

@ -0,0 +1,72 @@
Todo for preos:
get debian installer (?)
x86, amd64
configure sshd
add authorized_keys
output files
tftp: cuni: curl -s "http://http.us.debian.org/debian/dists/$version/main/installer-$arch/current/images/netboot/netboot.tar.gz" | tar xz
iso
http://wiki.debian.org/DebianInstaller/
--------------------------------------------------------------------------------
debootstrap:
[19:33] brief:hack% sudo debootstrap squeeze ./debian-squeeze
[19:30] brief:hack# du -sh .
213M .
install kernel
[19:35] brief:hack# chroot debian-squeeze/ apt-get -y install linux-image-amd64
[19:37] brief:debian-squeeze# ls boot/initrd*
boot/initrd.img-2.6.32-5-amd64
[19:37] brief:debian-squeeze# ls boot/vmlinuz*
boot/vmlinuz-2.6.32-5-amd64
install sshd
[19:37] brief:hack# chroot debian-squeeze/ apt-get -y --force-yes install openssh-server
- connect back?
- generate sshd keys?
--------------------------------------------------------------------------------
initramfs:
find . -print0 | bsdcpio $( (( QUIET )) && echo '--quiet' ) -R 0:0 -0oH newc | $COMPRESSION $COMPRESSION_OPTIONS > "$IMGPATH"
/init for booting
find . -print0 | cpio --null -ov --format=newc | gzip -9 > /boot/my-initramfs.cpio.gz
cpio -H newc -o
find . | cpio -H newc -o > ../initramfs.cpio # <-- this is the actual initramfs
[19:39] brief:debian-squeeze# find . | bsdcpio -H newc -o > ../initramfs.cpio
[19:43] brief:debian-squeeze# xz ../initramfs.cpio
--------------------------------------------------------------------------------
cdrom:
http://tldp.org/HOWTO/Bootdisk-HOWTO/cd-roms.html
--------------------------------------------------------------------------------
[19:34] brief:hack# chroot debian-squeeze/ apt-cache search kernel | grep linux-image
linux-image-2.6.32-5-amd64-dbg - Debugging infos for Linux 2.6.32-5-amd64
linux-image-2.6.32-5-amd64 - Linux 2.6.32 for 64-bit PCs
linux-image-2.6.32-5-openvz-amd64-dbg - Debugging infos for Linux 2.6.32-5-openvz-amd64
linux-image-2.6.32-5-openvz-amd64 - Linux 2.6.32 for 64-bit PCs, OpenVZ support
linux-image-2.6.32-5-vserver-amd64-dbg - Debugging infos for Linux 2.6.32-5-vserver-amd64
linux-image-2.6.32-5-vserver-amd64 - Linux 2.6.32 for 64-bit PCs, Linux-VServer support
linux-image-2.6.32-5-xen-amd64-dbg - Debugging infos for Linux 2.6.32-5-xen-amd64
linux-image-2.6.32-5-xen-amd64 - Linux 2.6.32 for 64-bit PCs, Xen dom0 support
linux-image-2.6-amd64 - Linux 2.6 for 64-bit PCs (meta-package)
linux-image-2.6-openvz-amd64 - Linux 2.6 for 64-bit PCs (meta-package), OpenVZ support
linux-image-2.6-vserver-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Linux-VServer support
linux-image-2.6-xen-amd64 - Linux 2.6 for 64-bit PCs (meta-package), Xen dom0 support
linux-image-amd64 - Linux for 64-bit PCs (meta-package)
linux-image-openvz-amd64 - Linux for 64-bit PCs (meta-package), OpenVZ support
linux-image-vserver-amd64 - Linux for 64-bit PCs (meta-package), Linux-VServer support
linux-image-xen-amd64 - Linux for 64-bit PCs (meta-package), Xen dom0 support
[19:34] brief:hack#
--------------------------------------------------------------------------------

View File

@ -4,6 +4,14 @@ Changelog
* Changes are always commented with their author in (braces)
* Exception: No braces means author == Nico Schottelius
2.3.7: 2013-12-02
* Type __file: Secure the file transfer by using mktemp (Steven Armstrong)
* Type __file: Only remove file when state is absent (Steven Armstrong)
* Type __link: Only remove link when state is absent (Steven Armstrong)
* Type __directory: Only remove directory when state is absent (Steven Armstrong)
* Type __package_zypper: Fix explorer and parameter issue (Daniel Heule)
* Core: Fix backtrace when cache cannot be deleted
2.3.6: 2013-11-25
* New Type: __locale
* Type __line: Ensure special characters are not interpreted