diff --git a/anvil/__main__.py b/anvil/__main__.py index f76ba24a..fb1435fe 100644 --- a/anvil/__main__.py +++ b/anvil/__main__.py @@ -82,7 +82,7 @@ def run(args): # Stash the dryrun value (if any) if 'dryrun' in args: - env.set("ANVIL_DRYRUN", str(args['dryrun'])) + sh.set_dry_run(args['dryrun']) # Ensure the anvil dirs are there if others are about to use it... ensure_anvil_dirs() diff --git a/anvil/action.py b/anvil/action.py index d3853566..c1d880c6 100644 --- a/anvil/action.py +++ b/anvil/action.py @@ -33,6 +33,10 @@ from anvil.utils import OrderedDict LOG = logging.getLogger(__name__) +# Include the general yaml during all interpolation +# actions since it typically contains useful shared settings... +BASE_YAML_INTERP = ('general', ) + class PhaseFunctors(object): def __init__(self, start, run, end): @@ -74,7 +78,7 @@ class Action(object): already_gotten = set() for c in component_order: instance = instances[c] - wanted_passwords = instance.get_option('wanted_passwords') or [] + wanted_passwords = instance.get_option('wanted_passwords') if not wanted_passwords: continue for (name, prompt) in wanted_passwords.items(): @@ -160,11 +164,18 @@ class Action(object): sibling_instances[action][name] = a_sibling return there_siblings + def _get_interpolated_names(self, name): + # Return which sources that will be interpolated from + # Note(harlowja): if one of the bases here pulls in + # another yaml, it will be done automatically so this + # list is more of the starting list and not the end list... + return list(BASE_YAML_INTERP) + [name] + def _get_interpolated_options(self, name): - interpolated_opts = {} - for c in ['general', name]: - interpolated_opts.update(self.interpolator.extract(c)) - return interpolated_opts + opts = {} + for c in self._get_interpolated_names(name): + opts.update(self.interpolator.extract(c)) + return opts def _construct_instances(self, persona): """ @@ -240,6 +251,7 @@ class Action(object): utils.log_object(env.get(), logger=LOG, level=logging.DEBUG, item_max_len=64) def _get_phase_filename(self, phase_name): + # Do some canonicalization of the phase name so its in a semi-standard format... phase_name = phase_name.lower().strip() phase_name = phase_name.replace("-", '_') phase_name = phase_name.replace(" ", "_") @@ -251,12 +263,23 @@ class Action(object): """ Run a given 'functor' across all of the components, in order. """ + # All the results for each component end up in here + # in the order in which they ran... component_results = OrderedDict() + + # This phase recorder will be used to check if a given component + # and action has ran in the past, if so that components action + # will not be ran again. It will also be used to mark that a given + # component has completed a phase (if that phase runs). if not phase_name: phase_recorder = phase.NullPhaseRecorder() else: phase_recorder = phase.PhaseRecorder(self._get_phase_filename(phase_name)) + # These phase recorders will be used to undo other actions activities + # ie, when an install completes you want to uninstall phase to be + # removed from that actions phase file (and so on). This list will be + # used to accomplish that. neg_phase_recs = [] if inv_phase_names: for n in inv_phase_names: @@ -266,7 +289,14 @@ class Action(object): neg_phase_recs.append(phase.PhaseRecorder(self._get_phase_filename(n))) def change_activate(instance, on_off): - # Activate/deactivate them and there siblings (if any) + # Activate/deactivate a component instance and there siblings (if any) + # + # This is used when you say are looking at components + # that have been activated before your component has been. + # + # Typically this is useful for checking if a previous component + # has a shared dependency with your component and if so then there + # is no need to reinstall said dependency... instance.activated = on_off for (_name, sibling_instance) in instance.siblings.items(): sibling_instance.activated = on_off diff --git a/anvil/cfg.py b/anvil/cfg.py index 2b91739f..26d93187 100644 --- a/anvil/cfg.py +++ b/anvil/cfg.py @@ -139,6 +139,13 @@ class YamlInterpolator(object): self.included = {} self.interpolated = {} self.base = base + self.auto_specials = { + 'ip': utils.get_host_ip, + 'user': sh.getuser, + 'group': sh.getgroupname, + 'home': sh.gethomedir, + 'hostname': sh.hostname, + } def _interpolate_iterable(self, what): if isinstance(what, (set)): @@ -150,6 +157,8 @@ class YamlInterpolator(object): n_what = [] for v in what: n_what.append(self._interpolate(v)) + if isinstance(what, (tuple)): + n_what = tuple(n_what) return n_what def _interpolate_dictionary(self, what): @@ -174,6 +183,8 @@ class YamlInterpolator(object): n_what = [] for v in what: n_what.append(self._do_include(v)) + if isinstance(what, (tuple)): + n_what = tuple(n_what) return n_what def _interpolate(self, value): @@ -188,13 +199,16 @@ class YamlInterpolator(object): def _interpolate_string(self, what): if not re.search(INTERP_PAT, what): + # Leave it alone if the sub won't do + # anything to begin with return what def replacer(match): who = match.group(1).strip() key = match.group(2).strip() - if self._process_special(who, key): - return self._process_special(who, key) + (is_special, special_value) = self._process_special(who, key) + if is_special: + return special_value if who not in self.interpolated: self.interpolated[who] = self.included[who] self.interpolated[who] = self._interpolate(self.included[who]) @@ -203,37 +217,42 @@ class YamlInterpolator(object): return re.sub(INTERP_PAT, replacer, what) def _process_special(self, who, key): - if key == 'ip' and who == 'auto': - return utils.get_host_ip() - if key == 'user' and who == 'auto': - return sh.getuser() - if who == 'auto': - raise KeyError("Unknown auto key type %s" % (key)) - return None + if who and who.lower() in ['auto']: + if key not in self.auto_specials: + raise KeyError("Unknown auto key %r" % (key)) + functor = self.auto_specials[key] + return (True, functor()) + return (False, None) def _include_string(self, what): if not re.search(INTERP_PAT, what): + # Leave it alone if the sub won't do + # anything to begin with return what def replacer(match): who = match.group(1).strip() key = match.group(2).strip() - if self._process_special(who, key): - return self._process_special(who, key) + (is_special, special_value) = self._process_special(who, key) + if is_special: + return special_value + # Process there includes and then + # fetch the value that should have been + # populated self._process_includes(who) return str(self.included[who][key]) return re.sub(INTERP_PAT, replacer, what) - def _do_include(self, v): - n_v = v - if v and isinstance(v, (basestring, str)): - n_v = self._include_string(v) - elif isinstance(v, dict): - n_v = self._include_dictionary(v) - elif isinstance(v, (list, set, tuple)): - n_v = self._include_iterable(v) - return n_v + def _do_include(self, value): + new_value = value + if value and isinstance(value, (basestring, str)): + new_value = self._include_string(value) + elif isinstance(value, (dict)): + new_value = self._include_dictionary(value) + elif isinstance(value, (list, set, tuple)): + new_value = self._include_iterable(value) + return new_value def _process_includes(self, root): if root in self.included: diff --git a/anvil/colorizer.py b/anvil/colorizer.py index a583cb54..e1580d69 100644 --- a/anvil/colorizer.py +++ b/anvil/colorizer.py @@ -23,13 +23,15 @@ from anvil import type_utils as tu COLORS = termcolor.COLORS.keys() +LOG_COLOR = True +if 'LOG_COLOR' in env.get(): + LOG_COLOR = tu.make_bool(env.get_key('LOG_COLOR')) +if not sys.stdout.isatty(): + LOG_COLOR = False + def color_enabled(): - if 'LOG_COLOR' in env.get() and not tu.make_bool(env.get_key('LOG_COLOR')): - return False - if not sys.stdout.isatty(): - return False - return True + return LOG_COLOR def quote(data, quote_color='green', **kargs): diff --git a/anvil/components/__init__.py b/anvil/components/__init__.py index 344255d9..8f3f9cd1 100644 --- a/anvil/components/__init__.py +++ b/anvil/components/__init__.py @@ -856,6 +856,10 @@ class PythonTestingComponent(component.Component): cmd.append('--nologcapture') for e in self._get_test_exclusions(): cmd.append('--exclude=%s' % (e)) + xunit_fn = self.get_option("xunit_filename"): + if xunit_fn: + cmd.append("--with-xunit") + cmd.append("--xunit-file=%s" % (xunit_fn)) return cmd def _use_pep8(self): @@ -922,7 +926,7 @@ class PythonTestingComponent(component.Component): cmd = self._get_test_command() env = self._get_env() with open(os.devnull, 'wb') as null_fh: - if self.get_bool_option("tests_verbose", default_value=False): + if self.get_bool_option("verbose", default_value=False): null_fh = None sh.execute(*cmd, stdout_fh=None, stderr_fh=null_fh, cwd=app_dir, env_overrides=env) diff --git a/anvil/components/helpers/nova.py b/anvil/components/helpers/nova.py index fa40ebf3..800649f2 100644 --- a/anvil/components/helpers/nova.py +++ b/anvil/components/helpers/nova.py @@ -286,7 +286,7 @@ class ConfConfigurator(object): # Used more than once so we calculate it ahead of time hostip = self.installer.get_option('ip') - nova_conf.add('verbose', self.installer.get_bool_option('verbose')) + nova_conf.add('verbose', self.installer.get_bool_option('log_verbose')) # Allow destination machine to match source for resize. nova_conf.add('allow_resize_to_same_host', True) diff --git a/anvil/shell.py b/anvil/shell.py index babf060d..572dee62 100644 --- a/anvil/shell.py +++ b/anvil/shell.py @@ -42,13 +42,15 @@ SHELL_QUOTE_REPLACERS = { "$": '\$', '`': '\`', } -ROOT_PATH = os.sep # Locally stash these so that they can not be changed # by others after this is first fetched... SUDO_UID = env.get_key('SUDO_UID') SUDO_GID = env.get_key('SUDO_GID') +# Set only once +IS_DRYRUN = None + class Process(psutil.Process): def __str__(self): @@ -72,11 +74,17 @@ class Rooted(object): self.engaged = False +def set_dry_run(on_off): + global IS_DRYRUN + if not isinstance(on_off, (bool)): + raise TypeError("Dry run value must be a boolean") + if IS_DRYRUN is not None: + raise RuntimeError("Dry run value has already been previously set to '%s'" % (IS_DRYRUN)) + IS_DRYRUN = on_off + + def is_dry_run(): - # Not stashed locally since the main entrypoint - # actually adjusts this value depending on a command - # line option... - return tu.make_bool(env.get_key('ANVIL_DRYRUN')) + return bool(IS_DRYRUN) # Originally borrowed from nova computes execute... @@ -85,13 +93,12 @@ def execute(*cmd, **kwargs): check_exit_code = kwargs.pop('check_exit_code', [0]) cwd = kwargs.pop('cwd', None) env_overrides = kwargs.pop('env_overrides', None) - close_stdin = kwargs.pop('close_stdin', False) ignore_exit_code = kwargs.pop('ignore_exit_code', False) - if isinstance(check_exit_code, bool): + if isinstance(check_exit_code, (bool)): ignore_exit_code = not check_exit_code check_exit_code = [0] - elif isinstance(check_exit_code, int): + elif isinstance(check_exit_code, (int)): check_exit_code = [check_exit_code] run_as_root = kwargs.pop('run_as_root', False) @@ -109,22 +116,28 @@ def execute(*cmd, **kwargs): stdin_fh = subprocess.PIPE stdout_fh = subprocess.PIPE stderr_fh = subprocess.PIPE - close_file_descriptors = True - if 'stdout_fh' in kwargs.keys(): - stdout_fh = kwargs.get('stdout_fh') + stdout_fn = kwargs.get('stdout_fn') + stderr_fn = kwargs.get('stderr_fn') + trace_writer = kwargs.get('tracewriter') - if 'stdin_fh' in kwargs.keys(): - stdin_fh = kwargs.get('stdin_fh') - process_input = None + if 'stdout_fh' in kwargs: + stdout_fh = kwargs['stdout_fh'] + if stdout_fn: + LOG.warn("Stdout file handles and stdout file names can not be used simultaneously!") + stdout_fn = None - if 'stderr_fh' in kwargs.keys(): - stderr_fh = kwargs.get('stderr_fh') + if 'stderr_fh' in kwargs: + stderr_fh = kwargs['stderr_fh'] + if stderr_fn: + LOG.warn("Stderr file handles and stderr file names can not be used simultaneously!") + stderr_fn = None if not shell: LOG.debug('Running cmd: %r' % (execute_cmd)) else: LOG.debug('Running shell cmd: %r' % (execute_cmd)) + if process_input is not None: LOG.debug('With stdin: %s' % (process_input)) if cwd: @@ -145,8 +158,12 @@ def execute(*cmd, **kwargs): return doit if not run_as_root: + # Ensure we drop down to the suid user before the command + # is executed (ensuring we don't run in root mode when we + # should not be) (user_uid, user_gid) = get_suids() - demoter = demoter_functor(user_uid=user_uid, user_gid=user_gid) + if user_uid is not None and user_gid is not None: + demoter = demoter_functor(user_uid=user_uid, user_gid=user_gid) rc = None result = None @@ -157,7 +174,7 @@ def execute(*cmd, **kwargs): else: try: obj = subprocess.Popen(execute_cmd, stdin=stdin_fh, stdout=stdout_fh, stderr=stderr_fh, - close_fds=close_file_descriptors, cwd=cwd, shell=shell, + close_fds=True, cwd=cwd, shell=shell, preexec_fn=demoter, env=process_env) if process_input is not None: result = obj.communicate(str(process_input)) @@ -166,8 +183,6 @@ def execute(*cmd, **kwargs): except OSError as e: raise excp.ProcessExecutionError(description="%s: [%s, %s]" % (e, e.errno, e.strerror), cmd=str_cmd) - if (stdin_fh != subprocess.PIPE and obj.stdin and close_stdin): - obj.stdin.close() rc = obj.returncode if not result: @@ -188,13 +203,10 @@ def execute(*cmd, **kwargs): LOG.debug("A failure may of just happened when running command %r [%s] (%s, %s)", str_cmd, rc, stdout, stderr) # See if a requested storage place was given for stderr/stdout - trace_writer = kwargs.get('tracewriter') - stdout_fn = kwargs.get('stdout_fn') if stdout_fn: write_file(stdout_fn, stdout) if trace_writer: trace_writer.file_touched(stdout_fn) - stderr_fn = kwargs.get('stderr_fn') if stderr_fn: write_file(stderr_fn, stderr) if trace_writer: @@ -204,7 +216,7 @@ def execute(*cmd, **kwargs): def abspth(path): if not path: - path = ROOT_PATH + path = "/" if path == "~": path = gethomedir() return os.path.abspath(path) diff --git a/conf/components/nova.yaml b/conf/components/nova.yaml index c1373947..a7df4f8f 100644 --- a/conf/components/nova.yaml +++ b/conf/components/nova.yaml @@ -102,7 +102,7 @@ nova_version: "1.1" scheduler: nova.scheduler.filter_scheduler.FilterScheduler # Should nova be in verbose mode? -verbose: True +log_verbose: True # Virtualization settings # Drivers known (libvirt, xensever, vmware, baremetal) diff --git a/conf/messages/fails.1.txt b/conf/messages/fails.1.txt new file mode 100644 index 00000000..509cfde1 --- /dev/null +++ b/conf/messages/fails.1.txt @@ -0,0 +1,4 @@ + + __________ +< Failure! > + ---------- diff --git a/conf/messages/fails.10.txt b/conf/messages/fails.10.txt new file mode 100644 index 00000000..b8047f24 --- /dev/null +++ b/conf/messages/fails.10.txt @@ -0,0 +1,6 @@ + + _____________________ +/ We were in the nick \ +| of time. You were | +\ in great peril. / + --------------------- diff --git a/conf/messages/fails.11.txt b/conf/messages/fails.11.txt new file mode 100644 index 00000000..80016e75 --- /dev/null +++ b/conf/messages/fails.11.txt @@ -0,0 +1,8 @@ + + ___________________ +/ I know a dead \ +| parrot when I see | +| one, and I'm | +| looking at one | +\ right now. / + ------------------- diff --git a/conf/messages/fails.12.txt b/conf/messages/fails.12.txt new file mode 100644 index 00000000..b69cdf77 --- /dev/null +++ b/conf/messages/fails.12.txt @@ -0,0 +1,6 @@ + + _________________ +/ Welcome to the \ +| National Cheese | +\ Emporium / + ----------------- diff --git a/conf/messages/fails.13.txt b/conf/messages/fails.13.txt new file mode 100644 index 00000000..339cd208 --- /dev/null +++ b/conf/messages/fails.13.txt @@ -0,0 +1,6 @@ + + ______________________ +/ What is the airspeed \ +| velocity of an | +\ unladen swallow? / + ---------------------- diff --git a/conf/messages/fails.14.txt b/conf/messages/fails.14.txt new file mode 100644 index 00000000..9b151126 --- /dev/null +++ b/conf/messages/fails.14.txt @@ -0,0 +1,5 @@ + + ______________________ +/ Now stand aside, \ +\ worthy adversary. / + ---------------------- diff --git a/conf/messages/fails.15.txt b/conf/messages/fails.15.txt new file mode 100644 index 00000000..35f65931 --- /dev/null +++ b/conf/messages/fails.15.txt @@ -0,0 +1,5 @@ + + ___________________ +/ Okay, we'll call \ +\ it a draw. / + ------------------- diff --git a/conf/messages/fails.16.txt b/conf/messages/fails.16.txt new file mode 100644 index 00000000..32ff05fd --- /dev/null +++ b/conf/messages/fails.16.txt @@ -0,0 +1,5 @@ + + _______________ +/ She turned me \ +\ into a newt! / + --------------- diff --git a/conf/messages/fails.17.txt b/conf/messages/fails.17.txt new file mode 100644 index 00000000..ef55c829 --- /dev/null +++ b/conf/messages/fails.17.txt @@ -0,0 +1,4 @@ + + ___________________ +< Fetchez la vache! > + ------------------- diff --git a/conf/messages/fails.18.txt b/conf/messages/fails.18.txt new file mode 100644 index 00000000..323ecfe7 --- /dev/null +++ b/conf/messages/fails.18.txt @@ -0,0 +1,6 @@ + + __________________________ +/ We'd better not risk \ +| another frontal assault, | +\ that rabbit's dynamite. / + -------------------------- diff --git a/conf/messages/fails.19.txt b/conf/messages/fails.19.txt new file mode 100644 index 00000000..122e0094 --- /dev/null +++ b/conf/messages/fails.19.txt @@ -0,0 +1,8 @@ + + ______________________ +/ This is supposed to \ +| be a happy occasion. | +| Let's not bicker and | +| argue about who | +\ killed who. / + ---------------------- diff --git a/conf/messages/fails.2.txt b/conf/messages/fails.2.txt new file mode 100644 index 00000000..e85ac3a1 --- /dev/null +++ b/conf/messages/fails.2.txt @@ -0,0 +1,4 @@ + + ___________ +< Run away! > + ----------- diff --git a/conf/messages/fails.20.txt b/conf/messages/fails.20.txt new file mode 100644 index 00000000..de24fa34 --- /dev/null +++ b/conf/messages/fails.20.txt @@ -0,0 +1,4 @@ + + _______________________ +< You have been borked. > + ----------------------- diff --git a/conf/messages/fails.21.txt b/conf/messages/fails.21.txt new file mode 100644 index 00000000..2090a414 --- /dev/null +++ b/conf/messages/fails.21.txt @@ -0,0 +1,6 @@ + + __________________ +/ We used to dream \ +| of living in a | +\ corridor! / + ------------------- diff --git a/conf/messages/fails.3.txt b/conf/messages/fails.3.txt new file mode 100644 index 00000000..0852d572 --- /dev/null +++ b/conf/messages/fails.3.txt @@ -0,0 +1,5 @@ + + ______________________ +/ NOBODY expects the \ +\ Spanish Inquisition! / + ---------------------- diff --git a/conf/messages/fails.4.txt b/conf/messages/fails.4.txt new file mode 100644 index 00000000..3c152600 --- /dev/null +++ b/conf/messages/fails.4.txt @@ -0,0 +1,5 @@ + + ______________________ +/ Spam spam spam spam \ +\ baked beans and spam / + ---------------------- diff --git a/conf/messages/fails.5.txt b/conf/messages/fails.5.txt new file mode 100644 index 00000000..e2b4f0d9 --- /dev/null +++ b/conf/messages/fails.5.txt @@ -0,0 +1,5 @@ + + ____________________ +/ Brave Sir Robin \ +\ ran away. / + -------------------- diff --git a/conf/messages/fails.6.txt b/conf/messages/fails.6.txt new file mode 100644 index 00000000..353f3078 --- /dev/null +++ b/conf/messages/fails.6.txt @@ -0,0 +1,4 @@ + + _______________________ +< Message for you, sir. > + ----------------------- diff --git a/conf/messages/fails.7.txt b/conf/messages/fails.7.txt new file mode 100644 index 00000000..f9dabbde --- /dev/null +++ b/conf/messages/fails.7.txt @@ -0,0 +1,5 @@ + + ____________________ +/ We are the knights \ +\ who say.... NI! / + -------------------- diff --git a/conf/messages/fails.8.txt b/conf/messages/fails.8.txt new file mode 100644 index 00000000..937e617f --- /dev/null +++ b/conf/messages/fails.8.txt @@ -0,0 +1,6 @@ + + ____________________ +/ Now go away or I \ +| shall taunt you a | +\ second time. / + -------------------- diff --git a/conf/messages/fails.9.txt b/conf/messages/fails.9.txt new file mode 100644 index 00000000..c054dffa --- /dev/null +++ b/conf/messages/fails.9.txt @@ -0,0 +1,7 @@ + + ____________________ +/ It's time for the \ +| penguin on top of | +| your television to | +\ explode. / + -------------------- diff --git a/conf/messages/stacks.1.txt b/conf/messages/stacks.1.txt new file mode 100644 index 00000000..ea00c325 --- /dev/null +++ b/conf/messages/stacks.1.txt @@ -0,0 +1,7 @@ + + ___ ____ _____ _ _ ____ _____ _ ____ _ __ + / _ \| _ \| ____| \ | / ___|_ _|/ \ / ___| |/ / +| | | | |_) | _| | \| \___ \ | | / _ \| | | ' / +| |_| | __/| |___| |\ |___) || |/ ___ \ |___| . \ + \___/|_| |_____|_| \_|____/ |_/_/ \_\____|_|\_\ + diff --git a/conf/messages/stacks.2.txt b/conf/messages/stacks.2.txt new file mode 100644 index 00000000..6d38093e --- /dev/null +++ b/conf/messages/stacks.2.txt @@ -0,0 +1,6 @@ + + ___ ___ ___ _ _ ___ _____ _ ___ _ __ + / _ \| _ \ __| \| / __|_ _/_\ / __| |/ / +| (_) | _/ _|| .` \__ \ | |/ _ \ (__| ' < + \___/|_| |___|_|\_|___/ |_/_/ \_\___|_|\_\ + diff --git a/conf/messages/stacks.3.txt b/conf/messages/stacks.3.txt new file mode 100644 index 00000000..478240b3 --- /dev/null +++ b/conf/messages/stacks.3.txt @@ -0,0 +1,5 @@ + +____ ___ ____ _ _ ____ ___ ____ ____ _ _ +| | |__] |___ |\ | [__ | |__| | |_/ +|__| | |___ | \| ___] | | | |___ | \_ + diff --git a/conf/messages/stacks.4.txt b/conf/messages/stacks.4.txt new file mode 100644 index 00000000..0f2ddfb9 --- /dev/null +++ b/conf/messages/stacks.4.txt @@ -0,0 +1,6 @@ + + _ ___ ___ _ _ __ ___ _ __ _ _ + / \| o \ __|| \| |/ _||_ _|/ \ / _|| |// +( o ) _/ _| | \\ |\_ \ | || o ( (_ | ( + \_/|_| |___||_|\_||__/ |_||_n_|\__||_|\\ + diff --git a/conf/messages/stacks.5.txt b/conf/messages/stacks.5.txt new file mode 100644 index 00000000..bca585d2 --- /dev/null +++ b/conf/messages/stacks.5.txt @@ -0,0 +1,6 @@ + + _ ___ ___ _ __ ___ _____ _ __ _ + ,' \ / o |/ _/ / |/ /,' _//_ _/.' \ ,'_/ / //7 +/ o |/ _,'/ _/ / || /_\ `. / / / o // /_ / ,' +|_,'/_/ /___//_/|_//___,' /_/ /_n_/ |__//_/\\ + diff --git a/conf/messages/stacks.6.txt b/conf/messages/stacks.6.txt new file mode 100644 index 00000000..9e0f4b0a --- /dev/null +++ b/conf/messages/stacks.6.txt @@ -0,0 +1,8 @@ + + _____ ___ ___ _ _ ___ _____ _____ ___ _ _ +( _ )( _`\ ( _`\ ( ) ( )( _`\(_ _)( _ )( _`\ ( ) ( ) +| ( ) || |_) )| (_(_)| `\| || (_(_) | | | (_) || ( (_)| |/'/' +| | | || ,__/'| _)_ | , ` |`\__ \ | | | _ || | _ | , < +| (_) || | | (_( )| |`\ |( )_) | | | | | | || (_( )| |\`\ +(_____)(_) (____/'(_) (_)`\____) (_) (_) (_)(____/'(_) (_) + diff --git a/conf/messages/success.1.txt b/conf/messages/success.1.txt new file mode 100644 index 00000000..f73d4c97 --- /dev/null +++ b/conf/messages/success.1.txt @@ -0,0 +1,10 @@ + + ___________ +/ You shine \ +| out like | +| a shaft | +| of gold | +| when all | +| around is | +\ dark. / + ----------- diff --git a/conf/messages/success.2.txt b/conf/messages/success.2.txt new file mode 100644 index 00000000..8c59131a --- /dev/null +++ b/conf/messages/success.2.txt @@ -0,0 +1,4 @@ + + ______________________________ +< I'm a lumberjack and I'm OK. > + ------------------------------ diff --git a/conf/messages/success.3.txt b/conf/messages/success.3.txt new file mode 100644 index 00000000..3b724f78 --- /dev/null +++ b/conf/messages/success.3.txt @@ -0,0 +1,7 @@ + + ____________________ +/ Australia! \ +| Australia! | +| Australia! | +\ We love you, amen. / + -------------------- diff --git a/conf/messages/success.4.txt b/conf/messages/success.4.txt new file mode 100644 index 00000000..b34d774f --- /dev/null +++ b/conf/messages/success.4.txt @@ -0,0 +1,6 @@ + + ______________ +/ Say no more, \ +| Nudge nudge | +\ wink wink. / + -------------- diff --git a/conf/messages/success.5.txt b/conf/messages/success.5.txt new file mode 100644 index 00000000..740ccc0a --- /dev/null +++ b/conf/messages/success.5.txt @@ -0,0 +1,5 @@ + + ________________ +/ And there was \ +\ much rejoicing / + ---------------- diff --git a/conf/messages/success.6.txt b/conf/messages/success.6.txt new file mode 100644 index 00000000..db282288 --- /dev/null +++ b/conf/messages/success.6.txt @@ -0,0 +1,4 @@ + + __________ +< Success! > + ---------- \ No newline at end of file diff --git a/conf/messages/welcome.1.txt b/conf/messages/welcome.1.txt new file mode 100644 index 00000000..31252eb3 --- /dev/null +++ b/conf/messages/welcome.1.txt @@ -0,0 +1 @@ +And now for something completely different! \ No newline at end of file diff --git a/conf/messages/welcome.2.txt b/conf/messages/welcome.2.txt new file mode 100644 index 00000000..09d761c8 --- /dev/null +++ b/conf/messages/welcome.2.txt @@ -0,0 +1 @@ +Let us get on with the show! \ No newline at end of file diff --git a/smithy b/smithy index ffcec598..6dcb0356 100755 --- a/smithy +++ b/smithy @@ -28,7 +28,6 @@ if [ -n "$SUDO_USER" ]; then fi ARGS="$@" -VER=$(python -c "from anvil import version; print version.version_string()") PWD=`pwd` if [ -z "$BOOT_FILES" ]; then BOOT_FN=".anvil_bootstrapped" @@ -85,10 +84,11 @@ bootstrap_epel() has_bootstrapped() { + checksums=$(get_checksums) for i in $BOOT_FILES; do if [ -f $i ]; then contents=`cat $i` - if [ "$contents" == "$VER" ]; then + if [ "$contents" == "$checksums" ]; then return 0 fi fi @@ -96,6 +96,14 @@ has_bootstrapped() return 1 } +get_checksums() +{ + pkg_checksum=$(md5sum tools/pkg-requires) + pip_checksum=$(md5sum tools/pip-requires) + echo "$pkg_checksum" + echo "$pip_checksum" +} + bootstrap_rhel() { echo "Bootstrapping RHEL: $1" @@ -122,7 +130,7 @@ run_smithy() puke() { # TODO(harlowja) better way to do this?? - cleaned_force=$(python -c "f='$FORCE';print(f.lower().strip())") + cleaned_force=$(python -c "f='$FORCE'; print(f.lower().strip())") if [[ "$cleaned_force" == "yes" ]]; then run_smithy else @@ -146,8 +154,12 @@ if [[ "$TYPE" =~ "Red Hat Enterprise Linux Server" ]]; then fi bootstrap_rhel $RH_VER if [ $? -eq 0 ]; then + # Write the checksums of the requirement files + # which if new requirements are added will cause new checksums + # and a new dependency install... + checksums=$(get_checksums) for i in $BOOT_FILES; do - echo "$VER" > $i + echo -e "$checksums" > $i done run_smithy else diff --git a/tools/pkg-requires b/tools/pkg-requires index 710fa447..77a1e74a 100644 --- a/tools/pkg-requires +++ b/tools/pkg-requires @@ -1,3 +1,4 @@ +PyYAML gcc git pylint @@ -6,6 +7,6 @@ python-cheetah python-iso8601 python-netifaces python-ordereddict +python-pip python-progressbar python-psutil -PyYAML