diff --git a/bin/cdist b/bin/cdist
new file mode 100755
index 00000000..4267b3fa
--- /dev/null
+++ b/bin/cdist
@@ -0,0 +1,607 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# 2010-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 .
+#
+#
+
+import argparse
+import logging
+import os
+import subprocess
+import shutil
+import stat
+import sys
+import tempfile
+
+BANNER = """
+ .. . .x+=:. s
+ dF @88> z` ^% :8
+ '88bu. %8P . is an object
+ if content == DOT_CDIST:
+ object_paths.append(starting_point)
+
+ return object_paths
+
+ def get_type_from_object(self, cdist_object):
+ """Returns the first part (i.e. type) of an object"""
+ return cdist_object.split(os.sep)[0]
+
+ def get_object_id_from_object(self, cdist_object):
+ """Returns everything but the first part (i.e. object_id) of an object"""
+ return os.sep.join(cdist_object.split(os.sep)[1:])
+
+ def object_dir(self, cdist_object):
+ """Returns the full path to the object (including .cdist)"""
+ return os.path.join(self.object_base_dir, cdist_object, DOT_CDIST)
+
+ def remote_object_dir(self, cdist_object):
+ """Returns the remote full path to the object (including .cdist)"""
+ return os.path.join(REMOTE_OBJECT_DIR, cdist_object, DOT_CDIST)
+
+ def object_parameter_dir(self, cdist_object):
+ """Returns the dir to the object parameter"""
+ return os.path.join(self.object_dir(cdist_object), "parameter")
+
+ def remote_object_parameter_dir(self, cdist_object):
+ """Returns the remote dir to the object parameter"""
+ return os.path.join(self.remote_object_dir(cdist_object), "parameter")
+
+ def object_code_paths(self, cdist_object):
+ """Return paths to code scripts of object"""
+ return [os.path.join(self.object_dir(cdist_object), "code-local"),
+ os.path.join(self.object_dir(cdist_object), "code-remote")]
+
+ def list_objects(self, starting_point = False):
+ """Return list of existing objects"""
+
+ if not starting_point:
+ starting_point = self.object_base_dir
+
+ object_paths = self.list_object_paths(starting_point)
+ objects = []
+
+ for path in object_paths:
+ objects.append(os.path.relpath(path, starting_point))
+
+ return objects
+
+ def type_explorer_dir(self, type):
+ """Return directory that holds the explorers of a type"""
+ return os.path.join(TYPE_DIR, type, "explorer")
+
+ def type_gencode_paths(self, type):
+ """Return paths to gencode scripts of type"""
+ return [os.path.join(TYPE_DIR, type, "gencode-local"),
+ os.path.join(TYPE_DIR, type, "gencode-remote")]
+
+ def type_manifest_path(self, type):
+ """Return path to manifest of type"""
+ return os.path.join(TYPE_DIR, type, "manifest")
+
+ def remote_type_explorer_dir(self, type):
+ """Return remote directory that holds the explorers of a type"""
+ return os.path.join(REMOTE_TYPE_DIR, type, "explorer")
+
+ def transfer_object_parameter(self, cdist_object):
+ """Transfer the object parameter to the remote destination"""
+ # Create base path before using mkdir -p
+ self.remote_mkdir(self.remote_object_parameter_dir(cdist_object))
+
+ # Synchronise parameter dir afterwards
+ self.transfer_dir(self.object_parameter_dir(cdist_object),
+ self.remote_object_parameter_dir(cdist_object))
+
+ def transfer_object_code(self, cdist_object):
+ FIXME
+ """Transfer the object code to the remote destination"""
+ # Create base path before using mkdir -p
+ self.remote_mkdir(self.remote_object_parameter_dir(cdist_object))
+
+ # Synchronise parameter dir afterwards
+ self.transfer_file(self.object_code_path(cdist_object),
+ self.remote_object_parameter_dir(cdist_object))
+
+ def transfer_global_explorers(self):
+ """Transfer the global explorers"""
+ self.transfer_dir(GLOBAL_EXPLORER_DIR, REMOTE_GLOBAL_EXPLORER_DIR)
+
+ def transfer_type_explorers(self, type):
+ """Transfer explorers of a type, but only once"""
+ if type in self.type_explorers_transferred:
+ log.debug("Skipping retransfer for explorers of %s", type)
+ return
+ else:
+ # Do not retransfer
+ self.type_explorers_transferred[type] = 1
+
+ src = self.type_explorer_dir(type)
+ remote_base = os.path.join(REMOTE_TYPE_DIR, type)
+ dst = self.remote_type_explorer_dir(type)
+
+ # Only continue, if there is at least the directory
+ if os.path.isdir(src):
+ # Ensure that the path exists
+ self.remote_mkdir(remote_base)
+ self.transfer_dir(src, dst)
+
+
+ def link_type_to_emulator(self):
+ """Link type names to cdist-type-emulator"""
+ for type in list_types():
+ source = os.path.join(LIB_DIR, "cdist-type-emulator")
+ destination = os.path.join(self.bin_dir, type)
+ log.debug("Linking %s to %s", source, destination)
+ os.symlink(source, destination)
+
+ def run_global_explores(self):
+ """Run global explorers"""
+ explorers = self.list_global_explorers()
+ if(len(explorers) == 0):
+ self.exit_error("No explorers found in", GLOBAL_EXPLORER_DIR)
+
+ self.transfer_global_explorers()
+ for explorer in explorers:
+ output = self.global_explorer_output_path(explorer)
+ output_fd = open(output, mode='w')
+ cmd = []
+ cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR)
+ cmd.append(self.remote_global_explorer_path(explorer))
+
+ self.run_or_fail(cmd, stdout=output_fd, remote=True)
+ output_fd.close()
+
+ def run_type_explorer(self, cdist_object):
+ """Run type specific explorers for objects"""
+ # Based on bin/cdist-object-explorer-run
+
+ # Transfering explorers for this type
+ type = self.get_type_from_object(cdist_object)
+ self.transfer_type_explorers(type)
+
+ cmd = []
+ cmd.append("__explorer=" + REMOTE_GLOBAL_EXPLORER_DIR)
+ cmd.append("__type_explorer=" + self.remote_type_explorer_dir(type))
+ cmd.append("__object=" + self.remote_object_dir(cdist_object))
+ cmd.append("__object_id=" + self.get_object_id_from_object(cdist_object))
+ cmd.append("__object_fq=" + cdist_object)
+
+ # Need to transfer at least the parameters for objects to be useful
+ self.transfer_object_parameter(cdist_object)
+
+ explorers = self.list_type_explorers(type)
+ for explorer in explorers:
+ remote_cmd = cmd + [os.path.join(self.remote_type_explorer_dir(type), explorer)]
+ output = os.path.join(self.type_explorer_output_dir(cdist_object), explorer)
+ output_fd = open(output, mode='w')
+ log.debug("%s exploring %s using %s storing to %s",
+ cdist_object, explorer, remote_cmd, output)
+
+ self.run_or_fail(remote_cmd, stdout=output_fd, remote=True)
+ output_fd.close()
+
+ def init_deploy(self):
+ log.debug("Creating clean directory structure")
+
+ # Ensure there is no old stuff, neither local nor remote
+ # remote_run_or_fail(hostname, ["rm -rf", "${__cdist_remote_base_dir}"])
+ #
+ # # Create base directories
+ # remote_run_or_fail(hostname,["mkdir -p", "${__cdist_remote_base_dir}"])
+ #
+ # # Link configuraion source directory - consistent with remote
+ # run_or_fail(["ln -sf", "$__cdist_conf_dir", "$__cdist_local_base_dir/$__cdist_name_conf_dir"])
+
+ def run_initial_manifest(self):
+ """Run the initial manifest"""
+ env = { "__manifest" : MANIFEST_DIR }
+ self.run_manifest(self.initial_manifest, extra_env=env)
+
+ def run_type_manifest(self, cdist_object):
+ """Run manifest for a specific object"""
+ type = self.get_type_from_object(cdist_object)
+ manifest = self.type_manifest_path(type)
+
+ log.debug("%s: Running %s", cdist_object, manifest)
+ # FIXME: add more sensible checks for manifest
+ if os.path.exists(manifest):
+ env = { "__object" : self.object_dir(cdist_object),
+ "__object_id": self.get_object_id_from_object(cdist_object),
+ "__object_fq": cdist_object,
+ "__type": type
+ }
+ self.run_manifest(manifest, extra_env=env)
+
+ def run_manifest(self, manifest, extra_env=None):
+ """Run a manifest"""
+ log.debug("Running manifest %s, env=%s", manifest, extra_env)
+ env = os.environ.copy()
+ env['PATH'] = self.bin_dir + ":" + env['PATH']
+
+ env['__target_host'] = self.target_host
+ env['__global'] = self.out_dir
+
+ # Legacy stuff to make cdist-type-emulator work
+ env['__cdist_conf_dir'] = CONF_DIR
+ env['__cdist_core_dir'] = os.path.join(BASE_DIR, "core")
+ env['__cdist_local_base_dir'] = self.temp_dir
+ env['__cdist_manifest'] = self.initial_manifest
+
+ # Other environment stuff
+ if extra_env:
+ env.update(extra_env)
+
+ self.shell_run_or_debug_fail(manifest, [manifest], env=env)
+
+ def list_object_requirements(self, cdist_object):
+ """Return list of requirements for specific object"""
+ file=os.path.join(self.object_dir(cdist_object), "require")
+
+ if os.path.isfile(file):
+ file_fd = open(file, "r")
+ requirements = file_fd.readlines()
+ file_fd.close()
+
+ # Remove \n from all lines
+ requirements = map(lambda s: s.strip(), requirements)
+
+ log.debug("Requirements for %s: %s", cdist_object, requirements)
+ else:
+ requirements = []
+
+ return requirements
+
+ def object_run(self, cdist_object, mode):
+ """Run gencode or code for an object"""
+ log.debug("Running %s from %s", mode, cdist_object)
+ requirements = self.list_object_requirements(cdist_object)
+
+ for requirement in requirements:
+ log.debug("Object %s requires %s", cdist_object, requirement)
+ self.object_run(requirement, mode=mode)
+
+ #
+ # Setup env Variable:
+ #
+ env = os.environ.copy()
+ env['__target_host'] = self.target_host
+ env['__global'] = self.out_dir
+ env["__object"] = self.object_dir(cdist_object)
+ env["__object_id"] = self.get_object_id_from_object(cdist_object)
+ env["__object_fq"] = cdist_object
+
+ if mode == "gencode":
+ paths = self.type_gencode_paths(self.get_type_from_object(cdist_object))
+ for bin in paths:
+ if os.path.isfile(bin):
+ # omit "gen" from gencode and
+ outfile=os.path.join(self.object_dir(cdist_object),
+ os.path.basename(bin)[3:])
+
+ outfile_fd = open(outfile, "w")
+ self.shell_run_or_debug_fail(bin, [bin], env=env, stdout=outfile_fd)
+ outfile_fd.close()
+
+ status = os.stat(outfile)
+
+ # Remove output if empty, else make it executable
+ if status.st_size == 0:
+ os.unlink(outfile)
+ else:
+ os.chmod(outfile, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
+
+ if mode == "code":
+# paths = self.object_code_paths(cdist_object)
+ local_dir = self.object_dir(cdist_object)
+ remote_dir = self.remote_object_dir(cdist_object)
+
+ bin = os.path.join(local_dir, "code-local")
+ if os.path.isfile(bin):
+ self.run_or_fail([bin], remote=False)
+
+
+ local_remote_code = os.path.join(local_dir, "code-remote")
+ remote_remote_code = os.path.join(remote_dir, "code-remote")
+ if os.path.isfile(local_remote_code):
+ self.transfer_file(local_remote_code, remote_remote_code)
+ self.run_or_fail([remote_remote_code], remote=True)
+
+ def deploy_to(self):
+ """Mimic the old deploy to: Deploy to one host"""
+ log.info("Deploying to " + self.target_host)
+ self.init_deploy()
+ self.run_global_explores()
+ self.run_initial_manifest()
+
+ old_objects = []
+ objects = self.list_objects()
+
+ # Continue process until no new objects are created anymore
+ while old_objects != objects:
+ log.debug("Prepare stage")
+ old_objects = list(objects)
+ # FIXME: do not rerun existing objects!
+ for cdist_object in objects:
+ self.run_type_explorer(cdist_object)
+ self.run_type_manifest(cdist_object)
+
+ objects = self.list_objects()
+
+ log.debug("Actual run objects")
+ # Now do the final steps over the existing objects
+ for cdist_object in objects:
+ log.debug("Run object: %s", cdist_object)
+ self.object_run(cdist_object, mode="gencode")
+ self.object_run(cdist_object, mode="code")
+
+ log.info("Finished run of %s", self.target_host)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='cdist ' + VERSION)
+ parser.add_argument('host', nargs='*', help='one or more hosts to operate on')
+ parser.add_argument('-b', '--banner',
+ help='Show cdist banner',
+ action='store_true', dest='banner')
+ parser.add_argument('-d', '--debug', help='Set log level to debug',
+ action='store_true')
+ parser.add_argument('-i', '--initial-manifest',
+ help='Path to a cdist manifest or - to read from stdin',
+ dest='manifest', required=False)
+ parser.add_argument('-p', '--parallel',
+ help='Operate on multiple hosts in parallel',
+ action='store_true', dest='parallel')
+ parser.add_argument('-s', '--sequential',
+ help='Operate on multiple hosts sequentially',
+ action='store_false', dest='parallel')
+
+ args = parser.parse_args(sys.argv[1:])
+ if args.debug:
+ logging.root.setLevel(logging.DEBUG)
+
+ if args.banner:
+ banner()
+ sys.exit(0)
+
+ try:
+ log.debug(args)
+
+ for host in args.host:
+ c = Cdist(host, initial_manifest=args.manifest)
+ c.deploy_to()
+ c.cleanup()
+ except KeyboardInterrupt:
+ sys.exit(0)
diff --git a/bin/cdist-deploy-to b/bin/cdist-deploy-to
index bf5614bc..86e15800 100755
--- a/bin/cdist-deploy-to
+++ b/bin/cdist-deploy-to
@@ -43,16 +43,6 @@ __cdist_echo info "cdist $__cdist_version: Configuring $__cdist_target_host "
# See cdist-stages(7)
#
-# Prepare local and remote directories
-__cdist_init_deploy "$__cdist_target_host"
-
-# Transfer cdist executables
-__cdist_echo info "Transferring cdist binaries to the target host "
-cdist-dir push "$__cdist_target_host" \
- "${__cdist_abs_mydir}" "${__cdist_remote_bin_dir}"
-cdist-explorer-run-global "$__cdist_target_host"
-cdist-manifest-run-init "$__cdist_target_host"
-cdist-object-all "$__cdist_target_host" cdist-object-prepare
cdist-object-all "$__cdist_target_host" cdist-object-run
cdist-cache "$__cdist_target_host"
diff --git a/core/__cdist_cache b/core/__cdist_cache
new file mode 100755
index 00000000..95764d3d
--- /dev/null
+++ b/core/__cdist_cache
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# 2010 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 .
+#
+#
+# Save the configuration tree into the local cache
+#
+
+__cdist_cache()
+{
+ # Create base to move into
+ mkdir -p "${__cdist_local_base_cache_dir}"
+
+ __cdist_echo info \
+ "Caching to $(__cdist_host_cache_dir "$__cdist_target_host")"
+ rm -rf "$(__cdist_host_cache_dir "$__cdist_target_host")"
+ mv "$__cdist_local_base_dir" \
+ "$(__cdist_host_cache_dir "$__cdist_target_host")"
+}
diff --git a/bin/cdist-dir b/core/__cdist_dir
similarity index 50%
rename from bin/cdist-dir
rename to core/__cdist_dir
index 0d30e14a..32ee0075 100755
--- a/bin/cdist-dir
+++ b/core/__cdist_dir
@@ -23,29 +23,24 @@
# Pull a directory from a target, both sides have the same name (i.e. explorers)
#
+__cdist_dir()
+{
+ [ $# -eq 3 ] || __cdist_usage ""
-. cdist-config
-[ $# -eq 4 ] || __cdist_usage ""
-set -ue
+ # ${3%/*} will be the destination directory, so no subdirectories
+ # of the same name are created, if the directory is already existing
-__cdist_action="$1"; shift
-__cdist_target_host="$1"; shift
-__cdist_src_dir="$1"; shift
-__cdist_dst_dir="$1"; shift
-
-# This will be the destination directory, so no subdirectories
-# of the same name are created, if the directory is already existing
-__cdist_top_dir="${__cdist_dst_dir%/*}"
-
-if [ "$__cdist_action" = "push" ]; then
- ssh "${__cdist_remote_user}@${__cdist_target_host}" \
- "mkdir -p \"${__cdist_dst_dir}\""
- scp -qr "$__cdist_src_dir" \
- "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_top_dir}"
-elif [ "$__cdist_action" = "pull" ]; then
- mkdir -p "${__cdist_dst_dir}"
- scp -qr "${__cdist_remote_user}@${__cdist_target_host}:${__cdist_src_dir}" \
- "${__cdist_top_dir}"
-else
- __cdist_exit_err "Unknown action $__cdist_action"
-fi
+ if [ "$1" = "push" ]; then
+ # FIXME: add error handling with __cdist_run_remote_... or so
+ ssh "${__cdist_remote_user}@${__cdist_target_host}" \
+ "mkdir -p \"$3\""
+ scp -qr "$2" \
+ "${__cdist_remote_user}@${__cdist_target_host}:${3%/*}"
+ elif [ "$1" = "pull" ]; then
+ mkdir -p "$3"
+ scp -qr "${__cdist_remote_user}@${__cdist_target_host}:$2" \
+ "${3%/*}"
+ else
+ __cdist_exit_err "Unknown action $1"
+ fi
+}
diff --git a/core/__cdist_dir_listing b/core/__cdist_dir_listing
new file mode 100755
index 00000000..f4aa2320
--- /dev/null
+++ b/core/__cdist_dir_listing
@@ -0,0 +1,30 @@
+#!/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 .
+#
+#
+# List files in a directory, if it exists
+#
+# We only create output, if there's at least one entry
+# and can thus be used as a boolean ;-)
+#
+
+__cdist_dir_listing()
+{
+ [ -d "$1" ] && ls -1 "$1"
+}
diff --git a/core/__cdist_echo b/core/__cdist_echo
new file mode 100755
index 00000000..a89d1821
--- /dev/null
+++ b/core/__cdist_echo
@@ -0,0 +1,56 @@
+#!/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 .
+#
+#
+# echo / syslog alike function
+#
+
+__cdist_echo()
+{
+ __cdist_echo_type="$1"; shift
+
+ set +u
+ if [ "$__cdist_object_self" ]; then
+ __cdist_echo_prefix="${__cdist_object_self}:"
+ else
+ __cdist_echo_prefix="core: "
+ fi
+ set -u
+
+ case "$__cdist_echo_type" in
+ debug)
+ if [ "$__cdist_debug" = 1 ]; then
+ echo $__cdist_echo_prefix "DEBUG: $@"
+ fi
+ ;;
+ info)
+ echo $__cdist_echo_prefix "$@"
+ ;;
+ warn)
+ echo $__cdist_echo_prefix "Warning: $@"
+ ;;
+ error)
+ echo $__cdist_echo_prefix "Error: $@" >&2
+ ;;
+ *)
+ echo "CORE BUG, who created the broken commit in $0?" >&2
+ exit 23
+ ;;
+ esac
+}
diff --git a/core/__cdist_exit_err b/core/__cdist_exit_err
new file mode 100755
index 00000000..303dbf20
--- /dev/null
+++ b/core/__cdist_exit_err
@@ -0,0 +1,28 @@
+#!/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 .
+#
+#
+# Print error and exit (perror() alike)
+#
+
+__cdist_exit_err()
+{
+ __cdist_echo error "$@"
+ exit 1
+}
diff --git a/core/__cdist_explorer_run b/core/__cdist_explorer_run
new file mode 100755
index 00000000..9e58fa09
--- /dev/null
+++ b/core/__cdist_explorer_run
@@ -0,0 +1,79 @@
+#!/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 .
+#
+#
+# Run explorers - FIXME: this function is ugly
+#
+
+__cdist_explorer_run()
+{
+ [ $# -eq 5 ] || __cdist_usage ""
+
+ # Ensure there is at least one explorer
+ num="$(ls -1 "$__cdist_explorer_dir" | wc -l)"
+ if [ "$num" -lt 1 ]; then
+ __cdist_exit_err "${__cdist_explorer_dir}: Contains no explorers"
+ fi
+
+ # Check whether to setup variable for type explorer
+ case "$1" in
+ global)
+ ;;
+ type)
+ # FIXME: think about how and where this gets setup!
+ "$__cdist_name_var_object=\"$(__cdist_remote_object_dir "$__cdist_object_self")\""
+ ;;
+ esac
+
+ # Transfer explorers
+ __cdist_dir push "$2" "$3"
+
+ # Create output directory
+ __cdist_run_remote mkdir -p "$4"
+
+ # Execute all explorers - FIXME: isolate cd call?
+ cd "$2";
+ # FIXME: cleanup double variable, no need when in directory
+ for __cdist_explorer_run_explorer in *; do
+ __cdist_explorer_explorer_name="${__cdist_explorer_run_explorer##*/}"
+
+ if [ -f "$__cdist_explorer_run_explorer" ]; then
+ if [ ! -x "$__cdist_explorer_run_explorer" ]; then
+ __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not executable."
+ fi
+
+ else
+ if [ -e "$__cdist_explorer_run_explorer" ]; then
+ __cdist_exit_err "Explorer \"$__cdist_explorer_run_explorer\" exists, but is not a file."
+ fi
+ fi
+
+ # FIXME: no need for remote out dir probably?
+ # or should we leave it and continue using __cdist_dir pull?
+ __cdist_run_remote \
+ "export $__cdist_name_var_explorer=\"$__cdist_remote_explorer_dir\";" \
+ "export $__cdist_name_var_global=\"$__cdist_remote_out_dir\";" \
+ "$3/$__cdist_explorer_run_explorer" ">" \
+ "$4/$__cdist_explorer_run_explorer" || \
+ __cdist_exit_err "Explorer $__cdist_explorer_run_explorer failed."
+ done
+
+ # Transfer results back
+ __cdist_dir pull "$4" "$5"
+}
diff --git a/bin/cdist-type-build-emulation b/core/__cdist_explorer_run_global
similarity index 56%
rename from bin/cdist-type-build-emulation
rename to core/__cdist_explorer_run_global
index 51c2f5b4..27359713 100755
--- a/bin/cdist-type-build-emulation
+++ b/core/__cdist_explorer_run_global
@@ -17,27 +17,16 @@
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see .
#
-# Build pseudo binaries for type emulation
+#
+# Copy & run the global explorers, i.e. not bound to types
#
-. cdist-config
-[ $# -eq 1 ] || __cdist_usage ""
-set -eu
+__cdist_explorer_run_global()
+{
+ __cdist_echo info "Running global explorers "
-__cdist_output_dir="$1"; shift
-
-__cdist_type_emulator="$__cdist_abs_mydir/cdist-type-emulator"
-
-if [ ! -d "${__cdist_type_dir}" ]; then
- __cdist_exit_err "$__cdist_type_dir must exist and contain available types"
-fi
-
-# Get Types
-cd "${__cdist_type_dir}"
-ls -1 > "${__cdist_tmp_file}"
-
-# Create binaries
-mkdir -p "${__cdist_output_dir}"
-while read type; do
- ln -sf "${__cdist_type_emulator}" "${__cdist_output_dir}/${type}"
-done < "${__cdist_tmp_file}"
+ # run the global explorers remotely
+ __cdist_explorer_run global \
+ "$__cdist_explorer_dir" "$__cdist_remote_explorer_dir" \
+ "$__cdist_remote_out_explorer_dir" "$__cdist_out_explorer_dir"
+}
diff --git a/core/__cdist_is_executable b/core/__cdist_is_executable
new file mode 100755
index 00000000..a7a6d174
--- /dev/null
+++ b/core/__cdist_is_executable
@@ -0,0 +1,44 @@
+#!/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 .
+#
+#
+# Test whether something is executable (that should be executable) or
+# is missing
+#
+
+__cdist_is_executable()
+{
+ [ $# -eq 1 ] || __cdist_exit_err ""
+
+ if [ -e "$1" ]; then
+ if [ -f "$1" ]; then
+ if [ -x "$1" ]; then
+ # Exists and is a correct executable
+ true
+ else
+ __cdist_exit_err "$1 exists, but is not executable."
+ fi
+ else
+ __cdist_exit_err "$1 exists, but is not a file."
+ fi
+ else
+ # Does not exist
+ false
+ fi
+}
diff --git a/core/__cdist_kill_on_interrupt b/core/__cdist_kill_on_interrupt
new file mode 100644
index 00000000..7cb711fa
--- /dev/null
+++ b/core/__cdist_kill_on_interrupt
@@ -0,0 +1,31 @@
+#!/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 .
+#
+#
+# Run the given command for each created object.
+#
+
+# Does not work in children, will be called again in every script!
+# Use only in interactive "front end" scripts
+__cdist_kill_on_interrupt()
+{
+ __cdist_tmp_removal
+ kill 0
+ exit 1
+}
diff --git a/core/__cdist_manifest_run b/core/__cdist_manifest_run
new file mode 100755
index 00000000..cf85d646
--- /dev/null
+++ b/core/__cdist_manifest_run
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# 2010-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 .
+#
+#
+# Let's build a cconfig tree from a configuration
+# And save it into the cache tree
+#
+
+__cdist_manifest_run()
+{
+ [ $# -eq 1 ] || __cdist_usage ""
+
+ __cdist_manifest="$1"; shift
+
+ ################################################################################
+ # Export information for cdist-type-emulator or manifest
+ #
+
+ # Config dir should not get reset - FIXME: why did I do this?
+ export __cdist_conf_dir
+
+ # Used to record the source in the object
+ export __cdist_manifest
+
+ # Export information for manifests - __cdist_out_dir comes from cdist-config
+ export $__cdist_name_var_global="$__cdist_out_dir"
+
+ ################################################################################
+ # The actual run
+ #
+
+ # Ensure binaries are existing - FIXME: move error handling into __cdist_type_build_emulation
+ __cdist_type_build_emulation \
+ || __cdist_exit_err "Failed to build type emulation binaries"
+
+ __cdist_run_shell "${__cdist_manifest}"
+}
diff --git a/bin/cdist-cache b/core/__cdist_manifest_run_init
similarity index 62%
rename from bin/cdist-cache
rename to core/__cdist_manifest_run_init
index ee27ffb4..e8fa63de 100755
--- a/bin/cdist-cache
+++ b/core/__cdist_manifest_run_init
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# 2010 Nico Schottelius (nico-cdist at schottelius.org)
+# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org)
#
# This file is part of cdist.
#
@@ -22,18 +22,11 @@
# And save it into the cache tree
#
-. cdist-config
-[ $# -eq 1 ] || __cdist_usage ""
-set -u
+__cdist_manifest_run_init()
+{
+ # FIXME: probably do not export but always set explicitly?
+ export $__cdist_name_var_manifest="$__cdist_manifest_dir"
-__cdist_target_host="$1"; shift
-
-# Create base to move into
-mkdir -p "${__cdist_local_base_cache_dir}"
-
-# Now determine absolute path
-__cdist_ddir="$(__cdist_host_cache_dir "$__cdist_target_host")"
-
-__cdist_echo info "Saving cache to $__cdist_ddir "
-rm -rf "$__cdist_ddir"
-mv "$__cdist_local_base_dir" "$__cdist_ddir"
+ __cdist_echo info "Running initial manifest for $__cdist_target_host "
+ __cdist_manifest_run "$__cdist_manifest_init"
+}
diff --git a/core/__cdist_object_all b/core/__cdist_object_all
new file mode 100755
index 00000000..965d08f6
--- /dev/null
+++ b/core/__cdist_object_all
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# 2011 Nico Schottelius (nico-cdist at schottelius.org)
+# 2011 Steven Armstrong (steven-cdist at 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 .
+#
+#
+# Run the given command for each created object.
+#
+
+__cdist_object_all()
+{
+ [ $# -eq 1 ] || __cdist_usage ""
+
+ __cdist_object_all_object_all_command="$1"; shift
+
+ __cdist_object_all_object_all_objects="$__cdist_tmp_dir/objects"
+
+ # Ensure object dir exists, so marker can be created
+ mkdir -p "${__cdist_out_object_dir}"
+
+ # FIXME: : - why do we use a file?
+ # core/__cdist_object_manifest_run: touch "$__cdist_objects_created"
+
+ # Loop until we do not create new objects anymore
+ # which is equal to all objects have been run
+ touch "$__cdist_objects_created"
+ while [ -f "$__cdist_objects_created" ]; do
+ # Assume we're done after this run
+ rm "$__cdist_objects_created"
+
+ # Get listing of objects
+ __cdist_object_list "$__cdist_out_object_dir" > \
+ "$__cdist_object_all_object_all_objects"
+
+ # NEED TO CREATE ARRAY, SSH DESTROYS WHILE READ LOOP
+ while read __cdist_object_all_object; do
+ set -- "$@" "$__cdist_object_all_object"
+ done < "$__cdist_object_all_object_all_objects"
+
+ while [ $# -gt 0 ]; do
+ __cdist_object_all_object="$1"; shift
+ $__cdist_object_all_object_all_command "$__cdist_object_all_object"
+ done
+ done
+}
diff --git a/core/__cdist_object_code_run b/core/__cdist_object_code_run
new file mode 100755
index 00000000..8af67ab8
--- /dev/null
+++ b/core/__cdist_object_code_run
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# 2010-2011 Nico Schottelius (nico-cdist at schottelius.org)
+# 2011 Steven Armstrong (steven-cdist at 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 .
+#
+#
+# Exec the code for the given object locally and remote
+#
+
+__cdist_object_code_run()
+{
+ [ $# -eq 1 ] || __cdist_exit_err "