From 00dfd02b3b1e1e1b8832996f76c784a68a41d1bd Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Mar 2019 14:44:16 +0000 Subject: [PATCH 01/24] Extract methods to utils Both methods relating to finding all assets within a group have been moved to Utils. --- lib/inventoryware/commands/list.rb | 3 +- .../commands/multi_node_command.rb | 38 +------------------ lib/inventoryware/utils.rb | 36 ++++++++++++++++++ 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/lib/inventoryware/commands/list.rb b/lib/inventoryware/commands/list.rb index bc52017..6f34428 100644 --- a/lib/inventoryware/commands/list.rb +++ b/lib/inventoryware/commands/list.rb @@ -26,13 +26,14 @@ # ============================================================================== require 'inventoryware/command' require 'inventoryware/config' +require 'inventoryware/utils' module Inventoryware module Commands class List < MultiNodeCommand def run files = if @options.group - find_nodes_in_groups(@options.group.split(',')) + Utils.find_nodes_in_groups(@options.group.split(',')) else Dir.glob(File.join(Config.yaml_dir, '*.yaml')) end diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index e7ba062..7af87b8 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -73,48 +73,12 @@ def locate_nodes(nodes, options) node_locations.push(*find_single_nodes(nodes, !!options.create)) end if options.group - node_locations.push(*find_nodes_in_groups(options.group.split(','))) + node_locations.push(*Utils.find_nodes_in_groups(options.group.split(','))) end end return node_locations end - # retrieves all .yaml files in the storage dir - def find_all_nodes() - node_locations = Dir.glob(File.join(Config.yaml_dir, '*.yaml')) - if node_locations.empty? - $stderr.puts "No asset data found "\ - "in #{File.expand_path(Config.yaml_dir)}" - end - return node_locations - end - - # retreives all nodes in the given groups - # this quite an intensive method of way to go about searching the yaml - # each file is converted to a sting and then searched - # seems fine as it stands but if speed becomes an issue could stand to - # be changed - def find_nodes_in_groups(groups) - nodes = [] - find_all_nodes().each do |location| - found = [] - File.open(location) do |file| - contents = file.read - m = contents.match(/primary_group: (.*?)$/) - found.append(m[1]) if m - m = contents.match(/secondary_groups: (.*?)$/) - found = found + (m[1].split(',')) if m - end - unless (found & groups).empty? - nodes.append(location) - end - end - if nodes.empty? - $stderr.puts "No assets found in #{groups.join(' or ')}." - end - return nodes - end - # retreives the .yaml file for each of the given nodes # expands node ranges if they exist # if return missing is passed, returns paths to the .yamls of non-existent diff --git a/lib/inventoryware/utils.rb b/lib/inventoryware/utils.rb index d8961c8..cd846a8 100644 --- a/lib/inventoryware/utils.rb +++ b/lib/inventoryware/utils.rb @@ -105,5 +105,41 @@ def self.load_yaml(path) end return data end + + # retrieves all .yaml files in the storage dir + def self.find_all_nodes() + node_locations = Dir.glob(File.join(Config.yaml_dir, '*.yaml')) + if node_locations.empty? + $stderr.puts "No asset data found "\ + "in #{File.expand_path(Config.yaml_dir)}" + end + return node_locations + end + + # retreives all nodes in the given groups + # this quite an intensive method of way to go about searching the yaml + # each file is converted to a sting and then searched + # seems fine as it stands but if speed becomes an issue could stand to + # be changed + def self.find_nodes_in_groups(groups) + nodes = [] + find_all_nodes().each do |location| + found = [] + File.open(location) do |file| + contents = file.read + m = contents.match(/primary_group: (.*?)$/) + found.append(m[1]) if m + m = contents.match(/secondary_groups: (.*?)$/) + found = found + (m[1].split(',')) if m + end + unless (found & groups).empty? + nodes.append(location) + end + end + if nodes.empty? + $stderr.puts "No assets found in #{groups.join(' or ')}." + end + return nodes + end end end From 9dc1dd73ea7acccd83cd672626ad75ee81a9243d Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Mar 2019 14:53:36 +0000 Subject: [PATCH 02/24] Revert inheritance Now that the methods this class needed within MultiNodeCommand have been moved to Utils it made no sense to keep this inheritance. Especially as it wasn't the cleanest way of handling things in the first place --- lib/inventoryware/commands/list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inventoryware/commands/list.rb b/lib/inventoryware/commands/list.rb index 6f34428..cc7e10f 100644 --- a/lib/inventoryware/commands/list.rb +++ b/lib/inventoryware/commands/list.rb @@ -30,7 +30,7 @@ module Inventoryware module Commands - class List < MultiNodeCommand + class List < Command def run files = if @options.group Utils.find_nodes_in_groups(@options.group.split(',')) From 1f523fd0eb9255997c79a33c5aa2838dfc0c0963 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Mar 2019 15:08:00 +0000 Subject: [PATCH 03/24] Extract group option into its own method --- lib/inventoryware/cli.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index e58224c..fbf00fe 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -82,14 +82,18 @@ def cli_syntax(command, args_str = nil) def add_multi_node_options(command) command.option '--all', "Select all assets" - command.option '-g', '--group GROUP', - "Select assets in GROUP, specify commma-separated list for multiple groups" + add_group_option(command) end def add_create_option(command) command.option '-c', '--create', "Create specified asset(s) if they don't exist" end + + def add_group_option(command) + command.option '-g', '--group GROUP', + "Select assets in GROUP, specify comma-separated list for multiple groups" + end end command :parse do |c| From a486a071af0ee71798dead4712916dbe623a6f1e Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Mar 2019 15:21:46 +0000 Subject: [PATCH 04/24] Add multi node options to modify notes command --- lib/inventoryware/cli.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index fbf00fe..9b6f732 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -140,6 +140,7 @@ def add_group_option(command) cli_syntax(c, 'ASSET') c.description = "Modify miscellaneous notes for an asset" c.hidden = true + add_multi_node_options(c) add_create_option(c) action(c, Commands::Modifys::Notes) end From e85d4971e9c59b0d1899756f9fc04377cb76e881 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 22 Mar 2019 15:22:12 +0000 Subject: [PATCH 05/24] Use only group option for list command --- lib/inventoryware/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index 9b6f732..895ceb7 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -148,7 +148,7 @@ def add_group_option(command) command :list do |c| cli_syntax(c) c.description = "List all assets that have stored data" - add_multi_node_options(c) + add_group_option(c) action(c, Commands::List) end From 0e22317a094bb41ea5a851ac18d72f484c26b3a5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 11:29:16 +0000 Subject: [PATCH 06/24] Allow argument to be optional This prevents the command from complaining when the user attempts to modify notes for an entire group. In this case they would not want to specify a singular asset so this adjusment gives the intended behaviour. --- lib/inventoryware/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index 895ceb7..88e5713 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -137,7 +137,7 @@ def add_group_option(command) end command :'modify notes' do |c| - cli_syntax(c, 'ASSET') + cli_syntax(c, '[ASSET_SPEC]') c.description = "Modify miscellaneous notes for an asset" c.hidden = true add_multi_node_options(c) From f9dd8af47afb908b79a66d7060329930c9dacd76 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 11:35:19 +0000 Subject: [PATCH 07/24] Get every node within the specified group This commit also changes the name of the `node` variable to `nodes`. This is mostly so that only one thing needs to be passed with `action`. --- lib/inventoryware/commands/single_node_command.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/inventoryware/commands/single_node_command.rb b/lib/inventoryware/commands/single_node_command.rb index 23502c4..450f83d 100644 --- a/lib/inventoryware/commands/single_node_command.rb +++ b/lib/inventoryware/commands/single_node_command.rb @@ -47,8 +47,14 @@ def run if @options.create location = File.join(Config.yaml_dir, "#{name}.yaml") - node = Node.new(location) - node.create_if_non_existent(Utils.get_new_asset_type) + nodes = Node.new(location) + nodes.create_if_non_existent(Utils.get_new_asset_type) + elsif @options.group + node_locations = [*Utils.find_nodes_in_groups(@options.group.split(','))] + nodes = [] + node_locations.each do |location| + nodes.push(Node.new(location)) + end else found = Utils.find_file(name, Config.yaml_dir) unless found.length == 1 @@ -56,10 +62,10 @@ def run Please refine your search ERROR end - node = Node.new(found[0]) + nodes = Node.new(found[0]) end - action(node) + action(nodes) end def action From 1004a714e19162b32c859c7a11d9f8508878e449 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 11:48:14 +0000 Subject: [PATCH 08/24] Refactor to work with groups --- lib/inventoryware/commands/modifys/notes.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/inventoryware/commands/modifys/notes.rb b/lib/inventoryware/commands/modifys/notes.rb index bbb6f05..2887b48 100644 --- a/lib/inventoryware/commands/modifys/notes.rb +++ b/lib/inventoryware/commands/modifys/notes.rb @@ -30,9 +30,19 @@ module Inventoryware module Commands module Modifys class Notes < SingleNodeCommand - def action(node) + def action(nodes) + nodes = *nodes unless nodes.is_a?(Array) + node = nodes.first + notes = node.data['mutable'].fetch('notes', '') notes = edit_with_tmp_file(notes, :rvim).strip + + nodes.each do |node| + save_notes(node, notes) + end + end + + def save_notes(node, notes) node.data['mutable']['notes'] = notes node.save end From cfce05d90e47c5ea9748d495a6f4029ec0dbb617 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 11:48:34 +0000 Subject: [PATCH 09/24] Add error message if no arguments given Only applies to commands that have no mandatory arguments --- lib/inventoryware/commands/single_node_command.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/inventoryware/commands/single_node_command.rb b/lib/inventoryware/commands/single_node_command.rb index 450f83d..615bcd9 100644 --- a/lib/inventoryware/commands/single_node_command.rb +++ b/lib/inventoryware/commands/single_node_command.rb @@ -38,7 +38,16 @@ module Commands class SingleNodeCommand < Command def run name = @argv[0] - # error to prevent confusion if attempting to provide >1 asset + + # Error to prevent further execution when no argument is specified + # for commands with no mandatory arguments e.g. modify notes + if name.nil? && !@options + raise ArgumentError, <<-ERROR.chomp +Please provide at least one asset + ERROR + end + + # error to prevent confusion if attempting to provide >1 node if NodeattrUtils::NodeParser.expand(name).length > 1 raise ArgumentError, <<-ERROR.chomp Issue with argument name, please only provide a single asset From 64399e8c4e66c95d2bbc288fe21f88c01b2ec731 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 11:59:41 +0000 Subject: [PATCH 10/24] Add multi node options to modify map --- lib/inventoryware/cli.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index 88e5713..df28f59 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -129,9 +129,10 @@ def add_group_option(command) end command :'modify map' do |c| - cli_syntax(c, 'ASSET') + cli_syntax(c, '[ASSET_SPEC]') c.description = "Modify mapping data for an asset" c.hidden = true + add_multi_node_options(c) add_create_option(c) action(c, Commands::Modifys::Map) end From aa1607dcaedb928b829960cf2bf100d90e286bb5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 12:00:29 +0000 Subject: [PATCH 11/24] Refactor to work with groups --- lib/inventoryware/commands/modifys/map.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/inventoryware/commands/modifys/map.rb b/lib/inventoryware/commands/modifys/map.rb index 024fec7..2d18dc5 100644 --- a/lib/inventoryware/commands/modifys/map.rb +++ b/lib/inventoryware/commands/modifys/map.rb @@ -31,16 +31,22 @@ module Inventoryware module Commands module Modifys class Map < SingleNodeCommand - def action(node) + def action(nodes) + nodes = *nodes unless nodes.is_a?(Array) + node = nodes.first + prompt = TTY::Prompt.new unless prompt.no?('Would you like to add map metadata? (Default: No)') - get_map_metadata_from_user(node, prompt) + get_map_metadata_from_user(nodes, prompt) end map = map_to_string(node.data['mutable']['map']) map = string_to_map(edit_with_tmp_file(map, :"rvim +'set number'")) - node.data['mutable']['map'] = map - node.save + + nodes.each do |node| + node.data['mutable']['map'] = map + node.save + end end # takes a hash with numerical keys @@ -74,7 +80,7 @@ def string_to_map(str) return map end - def get_map_metadata_from_user(node, prompt) + def get_map_metadata_from_user(nodes, prompt) prompt.say('Enter integer values for the dimensions of the map:') x = prompt.ask('X:') do |q| @@ -90,8 +96,10 @@ def get_map_metadata_from_user(node, prompt) %w(DownRight RightDown RightUp UpRight) ) - node.data['mutable']['map_dimensions'] = "#{x}x#{y}" - node.data['mutable']['map_pattern'] = pattern + nodes.each do |node| + node.data['mutable']['map_dimensions'] = "#{x}x#{y}" + node.data['mutable']['map_pattern'] = pattern + end end end end From 77ef310753629cef258720b0390237ac905210aa Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 12:02:46 +0000 Subject: [PATCH 12/24] Adjust descriptions of altered commands --- lib/inventoryware/cli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index df28f59..56e89b9 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -130,7 +130,7 @@ def add_group_option(command) command :'modify map' do |c| cli_syntax(c, '[ASSET_SPEC]') - c.description = "Modify mapping data for an asset" + c.description = "Modify mapping data for one or more assets" c.hidden = true add_multi_node_options(c) add_create_option(c) @@ -139,7 +139,7 @@ def add_group_option(command) command :'modify notes' do |c| cli_syntax(c, '[ASSET_SPEC]') - c.description = "Modify miscellaneous notes for an asset" + c.description = "Modify miscellaneous notes for one or more assets" c.hidden = true add_multi_node_options(c) add_create_option(c) From 006d8f7cda5139f01e66748246911ba3bd700aa8 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 12:11:53 +0000 Subject: [PATCH 13/24] Remove unnecessary method Initially extracted the logic for saving the note to each node to make things cleaner but looking at it now I feel it doesn't add much by having this separation. Therefore I have made the decision to remove the method and handle it within the `action` method like it did previously --- lib/inventoryware/commands/modifys/notes.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/inventoryware/commands/modifys/notes.rb b/lib/inventoryware/commands/modifys/notes.rb index 2887b48..8d256df 100644 --- a/lib/inventoryware/commands/modifys/notes.rb +++ b/lib/inventoryware/commands/modifys/notes.rb @@ -38,14 +38,10 @@ def action(nodes) notes = edit_with_tmp_file(notes, :rvim).strip nodes.each do |node| - save_notes(node, notes) + node.data['mutable']['notes'] = notes + node.save end end - - def save_notes(node, notes) - node.data['mutable']['notes'] = notes - node.save - end end end end From c978b6285af1d0cf44e9a9e2e18c364b208be04d Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 25 Mar 2019 12:43:20 +0000 Subject: [PATCH 14/24] Point to the method now that it has moved --- lib/inventoryware/commands/multi_node_command.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index 7af87b8..4c1ec5d 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -67,7 +67,7 @@ def resolve_node_options(argv, options, other_args) def locate_nodes(nodes, options) node_locations = [] if options.all - node_locations = find_all_nodes + node_locations = Utils.find_all_nodes else if nodes node_locations.push(*find_single_nodes(nodes, !!options.create)) From 7be3dd2f4e88f38a29d2b34066079ca7c4e0c060 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 13:41:46 +0000 Subject: [PATCH 15/24] Move methods to ndoe class Make find_all_nodes, find_nodes_in_groups, find_single_nodes & expand_asterisks class methods of the node class & change refrences to them accordingly --- lib/inventoryware/commands/list.rb | 4 +- .../commands/multi_node_command.rb | 49 +----------- .../commands/single_node_command.rb | 2 +- lib/inventoryware/node.rb | 79 +++++++++++++++++++ lib/inventoryware/utils.rb | 36 --------- 5 files changed, 86 insertions(+), 84 deletions(-) diff --git a/lib/inventoryware/commands/list.rb b/lib/inventoryware/commands/list.rb index cc7e10f..ad6d73a 100644 --- a/lib/inventoryware/commands/list.rb +++ b/lib/inventoryware/commands/list.rb @@ -26,14 +26,14 @@ # ============================================================================== require 'inventoryware/command' require 'inventoryware/config' -require 'inventoryware/utils' +require 'inventoryware/node' module Inventoryware module Commands class List < Command def run files = if @options.group - Utils.find_nodes_in_groups(@options.group.split(',')) + Node.find_nodes_in_groups(@options.group.split(',')) else Dir.glob(File.join(Config.yaml_dir, '*.yaml')) end diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index 4c1ec5d..156fcea 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -26,7 +26,7 @@ # ============================================================================== require 'inventoryware/command' require 'inventoryware/exceptions' -require 'inventoryware/utils' +require 'inventoryware/node' require 'nodeattr_utils' @@ -67,58 +67,17 @@ def resolve_node_options(argv, options, other_args) def locate_nodes(nodes, options) node_locations = [] if options.all - node_locations = Utils.find_all_nodes + node_locations = Node.find_all_nodes else if nodes - node_locations.push(*find_single_nodes(nodes, !!options.create)) + node_locations.push(*Node.find_single_nodes(nodes, !!options.create)) end if options.group - node_locations.push(*Utils.find_nodes_in_groups(options.group.split(','))) + node_locations.push(*Node.find_nodes_in_groups(options.group.split(','))) end end return node_locations end - - # retreives the .yaml file for each of the given nodes - # expands node ranges if they exist - # if return missing is passed, returns paths to the .yamls of non-existent - # nodes - def find_single_nodes(node_str, return_missing = false) - nodes = expand_asterisks(NodeattrUtils::NodeParser.expand(node_str)) - $stderr.puts "No assets found for '#{node_str}'" if nodes.empty? - node_locations = [] - nodes.each do |node| - node_yaml = "#{node}.yaml" - node_yaml_location = File.join(Config.yaml_dir, node_yaml) - unless Utils.check_file_readable?(node_yaml_location) - $stderr.puts "File #{node_yaml} not found within "\ - "#{File.expand_path(Config.yaml_dir)}" - if return_missing - $stderr.puts "Creating..." - else - $stderr.puts "Skipping." - next - end - end - node_locations.append(node_yaml_location) - end - return node_locations - end - - def expand_asterisks(nodes) - new_nodes = [] - nodes.each do |node| - if node.match(/\*/) - node_names = Dir.glob(File.join(Config.yaml_dir, node)).map { |file| - File.basename(file, '.yaml') - } - new_nodes.push(*node_names) - end - end - nodes.delete_if { |node| node.match(/\*/) } - nodes.push(*new_nodes) - return nodes - end end end end diff --git a/lib/inventoryware/commands/single_node_command.rb b/lib/inventoryware/commands/single_node_command.rb index 615bcd9..cb6261a 100644 --- a/lib/inventoryware/commands/single_node_command.rb +++ b/lib/inventoryware/commands/single_node_command.rb @@ -59,7 +59,7 @@ def run nodes = Node.new(location) nodes.create_if_non_existent(Utils.get_new_asset_type) elsif @options.group - node_locations = [*Utils.find_nodes_in_groups(@options.group.split(','))] + node_locations = [*Node.find_nodes_in_groups(@options.group.split(','))] nodes = [] node_locations.each do |location| nodes.push(Node.new(location)) diff --git a/lib/inventoryware/node.rb b/lib/inventoryware/node.rb index 823b08a..9c421fe 100644 --- a/lib/inventoryware/node.rb +++ b/lib/inventoryware/node.rb @@ -29,6 +29,85 @@ module Inventoryware class Node + class << self + # retrieves all .yaml files in the storage dir + def find_all_nodes() + node_locations = Dir.glob(File.join(Config.yaml_dir, '*.yaml')) + if node_locations.empty? + $stderr.puts "No asset data found "\ + "in #{File.expand_path(Config.yaml_dir)}" + end + return node_locations + end + + # retreives all nodes in the given groups + # this quite an intensive method of way to go about searching the yaml + # each file is converted to a sting and then searched + # seems fine as it stands but if speed becomes an issue could stand to + # be changed + def find_nodes_in_groups(groups) + nodes = [] + find_all_nodes().each do |location| + found = [] + File.open(location) do |file| + contents = file.read + m = contents.match(/primary_group: (.*?)$/) + found.append(m[1]) if m + m = contents.match(/secondary_groups: (.*?)$/) + found = found + (m[1].split(',')) if m + end + unless (found & groups).empty? + nodes.append(location) + end + end + if nodes.empty? + $stderr.puts "No assets found in #{groups.join(' or ')}." + end + return nodes + end + + # retreives the .yaml file for each of the given nodes + # expands node ranges if they exist + # if return missing is passed, returns paths to the .yamls of non-existent + # nodes + def find_single_nodes(node_str, return_missing = false) + nodes = expand_asterisks(NodeattrUtils::NodeParser.expand(node_str)) + $stderr.puts "No assets found for '#{node_str}'" if nodes.empty? + node_locations = [] + nodes.each do |node| + node_yaml = "#{node}.yaml" + node_yaml_location = File.join(Config.yaml_dir, node_yaml) + unless Utils.check_file_readable?(node_yaml_location) + $stderr.puts "File #{node_yaml} not found within "\ + "#{File.expand_path(Config.yaml_dir)}" + if return_missing + $stderr.puts "Creating..." + else + $stderr.puts "Skipping." + next + end + end + node_locations.append(node_yaml_location) + end + return node_locations + end + + def expand_asterisks(nodes) + new_nodes = [] + nodes.each do |node| + if node.match(/\*/) + node_names = Dir.glob(File.join(Config.yaml_dir, node)).map { |file| + File.basename(file, '.yaml') + } + new_nodes.push(*node_names) + end + end + nodes.delete_if { |node| node.match(/\*/) } + nodes.push(*new_nodes) + return nodes + end + end + def initialize(location) @location = location @name = File.basename(location, File.extname(location)) diff --git a/lib/inventoryware/utils.rb b/lib/inventoryware/utils.rb index cd846a8..d8961c8 100644 --- a/lib/inventoryware/utils.rb +++ b/lib/inventoryware/utils.rb @@ -105,41 +105,5 @@ def self.load_yaml(path) end return data end - - # retrieves all .yaml files in the storage dir - def self.find_all_nodes() - node_locations = Dir.glob(File.join(Config.yaml_dir, '*.yaml')) - if node_locations.empty? - $stderr.puts "No asset data found "\ - "in #{File.expand_path(Config.yaml_dir)}" - end - return node_locations - end - - # retreives all nodes in the given groups - # this quite an intensive method of way to go about searching the yaml - # each file is converted to a sting and then searched - # seems fine as it stands but if speed becomes an issue could stand to - # be changed - def self.find_nodes_in_groups(groups) - nodes = [] - find_all_nodes().each do |location| - found = [] - File.open(location) do |file| - contents = file.read - m = contents.match(/primary_group: (.*?)$/) - found.append(m[1]) if m - m = contents.match(/secondary_groups: (.*?)$/) - found = found + (m[1].split(',')) if m - end - unless (found & groups).empty? - nodes.append(location) - end - end - if nodes.empty? - $stderr.puts "No assets found in #{groups.join(' or ')}." - end - return nodes - end end end From 11810d9891153f98ae30292d453b07d4286adc78 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 13:46:50 +0000 Subject: [PATCH 16/24] Add conditional to find_nodes_in_groups Allow it to be called with a string --- lib/inventoryware/node.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/inventoryware/node.rb b/lib/inventoryware/node.rb index 9c421fe..251ee65 100644 --- a/lib/inventoryware/node.rb +++ b/lib/inventoryware/node.rb @@ -46,6 +46,7 @@ def find_all_nodes() # seems fine as it stands but if speed becomes an issue could stand to # be changed def find_nodes_in_groups(groups) + groups = *groups unless groups.is_a?(Array) nodes = [] find_all_nodes().each do |location| found = [] From ccae1f5cce6f40fbfadb1a0050fd7046775eb22d Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 14:23:34 +0000 Subject: [PATCH 17/24] Move edit_with_tmp_file to utils --- lib/inventoryware/commands/modifys/map.rb | 3 ++- lib/inventoryware/commands/modifys/notes.rb | 2 +- lib/inventoryware/commands/single_node_command.rb | 14 -------------- lib/inventoryware/utils.rb | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/inventoryware/commands/modifys/map.rb b/lib/inventoryware/commands/modifys/map.rb index 2d18dc5..3b1fa07 100644 --- a/lib/inventoryware/commands/modifys/map.rb +++ b/lib/inventoryware/commands/modifys/map.rb @@ -41,7 +41,8 @@ def action(nodes) end map = map_to_string(node.data['mutable']['map']) - map = string_to_map(edit_with_tmp_file(map, :"rvim +'set number'")) + map = string_to_map(Utils.edit_with_tmp_file(map, + :"rvim +'set number'")) nodes.each do |node| node.data['mutable']['map'] = map diff --git a/lib/inventoryware/commands/modifys/notes.rb b/lib/inventoryware/commands/modifys/notes.rb index 8d256df..41d11e1 100644 --- a/lib/inventoryware/commands/modifys/notes.rb +++ b/lib/inventoryware/commands/modifys/notes.rb @@ -35,7 +35,7 @@ def action(nodes) node = nodes.first notes = node.data['mutable'].fetch('notes', '') - notes = edit_with_tmp_file(notes, :rvim).strip + notes = Utils.edit_with_tmp_file(notes, :rvim).strip nodes.each do |node| node.data['mutable']['notes'] = notes diff --git a/lib/inventoryware/commands/single_node_command.rb b/lib/inventoryware/commands/single_node_command.rb index cb6261a..4ea9698 100644 --- a/lib/inventoryware/commands/single_node_command.rb +++ b/lib/inventoryware/commands/single_node_command.rb @@ -80,20 +80,6 @@ def run def action raise NotImplementedError end - - def edit_with_tmp_file(text, command) - tmp_file = Tempfile.new('inv_ware_file_') - begin - TTY::Editor.open(tmp_file.path, - content: text, - command: command) - edited = tmp_file.read - ensure - tmp_file.close - tmp_file.unlink - end - return edited - end end end end diff --git a/lib/inventoryware/utils.rb b/lib/inventoryware/utils.rb index d8961c8..a76cc44 100644 --- a/lib/inventoryware/utils.rb +++ b/lib/inventoryware/utils.rb @@ -105,5 +105,19 @@ def self.load_yaml(path) end return data end + + def self.edit_with_tmp_file(text, command) + tmp_file = Tempfile.new('inv_ware_file_') + begin + TTY::Editor.open(tmp_file.path, + content: text, + command: command) + edited = tmp_file.read + ensure + tmp_file.close + tmp_file.unlink + end + return edited + end end end From f3fb2063f0cf1097072a69b1e2ff0a0ac03fe706 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 14:25:15 +0000 Subject: [PATCH 18/24] Change inheritance Have modify notes and modify map inherit from MultiNodeCommand to use the `find_nodes` method --- lib/inventoryware/commands/modifys/map.rb | 10 ++++++---- lib/inventoryware/commands/modifys/notes.rb | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/inventoryware/commands/modifys/map.rb b/lib/inventoryware/commands/modifys/map.rb index 3b1fa07..b3046d5 100644 --- a/lib/inventoryware/commands/modifys/map.rb +++ b/lib/inventoryware/commands/modifys/map.rb @@ -24,15 +24,17 @@ # For more information on Flight Inventory, please visit: # https://github.com/openflighthpc/flight-inventory # ============================================================================== -require 'inventoryware/commands/single_node_command' +require 'inventoryware/commands/multi_node_command' require 'inventoryware/exceptions' +require 'inventoryware/node' module Inventoryware module Commands module Modifys - class Map < SingleNodeCommand - def action(nodes) - nodes = *nodes unless nodes.is_a?(Array) + class Map < MultiNodeCommand + def run + nodes = find_nodes() + nodes.map! { |n| Node.new(n) } node = nodes.first prompt = TTY::Prompt.new diff --git a/lib/inventoryware/commands/modifys/notes.rb b/lib/inventoryware/commands/modifys/notes.rb index 41d11e1..307e3c9 100644 --- a/lib/inventoryware/commands/modifys/notes.rb +++ b/lib/inventoryware/commands/modifys/notes.rb @@ -24,14 +24,16 @@ # For more information on Flight Inventory, please visit: # https://github.com/openflighthpc/flight-inventory # ============================================================================== -require 'inventoryware/commands/single_node_command' +require 'inventoryware/commands/multi_node_command' +require 'inventoryware/node' module Inventoryware module Commands module Modifys - class Notes < SingleNodeCommand - def action(nodes) - nodes = *nodes unless nodes.is_a?(Array) + class Notes < MultiNodeCommand + def run + nodes = find_nodes() + nodes.map! { |n| Node.new(n) } node = nodes.first notes = node.data['mutable'].fetch('notes', '') From 8a0275def045580ffdae7225e8f465fa5f154460 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 14:30:38 +0000 Subject: [PATCH 19/24] Revert some single_node_command changes --- .../commands/single_node_command.rb | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/inventoryware/commands/single_node_command.rb b/lib/inventoryware/commands/single_node_command.rb index 4ea9698..78d1b6b 100644 --- a/lib/inventoryware/commands/single_node_command.rb +++ b/lib/inventoryware/commands/single_node_command.rb @@ -39,14 +39,6 @@ class SingleNodeCommand < Command def run name = @argv[0] - # Error to prevent further execution when no argument is specified - # for commands with no mandatory arguments e.g. modify notes - if name.nil? && !@options - raise ArgumentError, <<-ERROR.chomp -Please provide at least one asset - ERROR - end - # error to prevent confusion if attempting to provide >1 node if NodeattrUtils::NodeParser.expand(name).length > 1 raise ArgumentError, <<-ERROR.chomp @@ -56,14 +48,8 @@ def run if @options.create location = File.join(Config.yaml_dir, "#{name}.yaml") - nodes = Node.new(location) - nodes.create_if_non_existent(Utils.get_new_asset_type) - elsif @options.group - node_locations = [*Node.find_nodes_in_groups(@options.group.split(','))] - nodes = [] - node_locations.each do |location| - nodes.push(Node.new(location)) - end + node = Node.new(location) + node.create_if_non_existent(Utils.get_new_asset_type) else found = Utils.find_file(name, Config.yaml_dir) unless found.length == 1 @@ -71,10 +57,10 @@ def run Please refine your search ERROR end - nodes = Node.new(found[0]) + node = Node.new(found[0]) end - action(nodes) + action(node) end def action From 1457c62e2d01f9335dcd560466cf7b0f9fd87b38 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 14:46:01 +0000 Subject: [PATCH 20/24] Add condition if no assets returned --- lib/inventoryware/commands/multi_node_command.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index 156fcea..8e8ff35 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -76,6 +76,11 @@ def locate_nodes(nodes, options) node_locations.push(*Node.find_nodes_in_groups(options.group.split(','))) end end + if node_locations.empty? + raise ArgumentError, <<-ERROR.chomp +No assets found + ERROR + end return node_locations end end From 4f1e0fed45a5f0e6898b52fb2eb46d89a1caf79c Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 16:02:22 +0000 Subject: [PATCH 21/24] location -> path --- lib/inventoryware/commands/edit.rb | 2 +- lib/inventoryware/commands/shows/data.rb | 2 +- lib/inventoryware/node.rb | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/inventoryware/commands/edit.rb b/lib/inventoryware/commands/edit.rb index 6850722..e9ba1c8 100644 --- a/lib/inventoryware/commands/edit.rb +++ b/lib/inventoryware/commands/edit.rb @@ -35,7 +35,7 @@ def action(node) node.save # maybe don't create unless saved? i.e. don't create the file above # instead save as closing - TTY::Editor.open(node.location, command: :rvim) + TTY::Editor.open(node.path, command: :rvim) end end end diff --git a/lib/inventoryware/commands/shows/data.rb b/lib/inventoryware/commands/shows/data.rb index 2c39e99..1a66b77 100644 --- a/lib/inventoryware/commands/shows/data.rb +++ b/lib/inventoryware/commands/shows/data.rb @@ -31,7 +31,7 @@ module Commands module Shows class Data < SingleNodeCommand def action(node) - File.open(node.location) do |file| + File.open(node.path) do |file| puts file.read end end diff --git a/lib/inventoryware/node.rb b/lib/inventoryware/node.rb index 251ee65..fe7bfae 100644 --- a/lib/inventoryware/node.rb +++ b/lib/inventoryware/node.rb @@ -109,9 +109,9 @@ def expand_asterisks(nodes) end end - def initialize(location) - @location = location - @name = File.basename(location, File.extname(location)) + def initialize(path) + @path = path + @name = File.basename(path, File.extname(path)) end def data @@ -123,11 +123,11 @@ def data=(value) end def open - node_data = Utils.load_yaml(@location) + node_data = Utils.load_yaml(@path) # condition for if the .yaml is empty unless node_data raise ParseError, <<-ERROR.chomp -Yaml in #{@location} is empty - aborting +Yaml in #{@path} is empty - aborting ERROR end @data = node_data.values[0] @@ -135,17 +135,17 @@ def open end def save - unless Utils.check_file_writable?(@location) + unless Utils.check_file_writable?(@path) raise FileSysError, <<-ERROR.chomp -Output file #{@location} not accessible - aborting +Output file #{@path} not accessible - aborting ERROR end yaml_hash = {data['name'] => data} - File.open(@location, 'w') { |file| file.write(yaml_hash.to_yaml) } + File.open(@path, 'w') { |file| file.write(yaml_hash.to_yaml) } end def create_if_non_existent(type = '') - unless Utils.check_file_readable?(@location) + unless Utils.check_file_readable?(@path) @data = { 'name' => @name, 'mutable' => {}, @@ -155,6 +155,6 @@ def create_if_non_existent(type = '') end end - attr_reader :location, :name + attr_reader :path, :name end end From cce616d685d14fa25cc0a2019ac6d76d2c6b04b9 Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 16:07:58 +0000 Subject: [PATCH 22/24] Return node objects Replace find_nodes with fetch_nodes (locate_nodes is now called find_nodes) and have fetch_nodes return node obejcts This is to soon allow central modification/interaction with the node list --- lib/inventoryware/commands/delete.rb | 22 ++++++++----------- lib/inventoryware/commands/modifys/groups.rb | 3 +-- lib/inventoryware/commands/modifys/map.rb | 3 +-- lib/inventoryware/commands/modifys/notes.rb | 3 +-- lib/inventoryware/commands/modifys/other.rb | 3 +-- .../commands/multi_node_command.rb | 9 +++++--- lib/inventoryware/commands/shows/document.rb | 18 ++++++--------- 7 files changed, 26 insertions(+), 35 deletions(-) diff --git a/lib/inventoryware/commands/delete.rb b/lib/inventoryware/commands/delete.rb index 93c9668..0799d89 100644 --- a/lib/inventoryware/commands/delete.rb +++ b/lib/inventoryware/commands/delete.rb @@ -31,21 +31,17 @@ module Inventoryware module Commands class Delete < MultiNodeCommand def run - node_locations = find_nodes() + nodes = fetch_nodes() - unless node_locations.empty? - prefix = "You are about to delete" - node_locations.map! { |loc| File.expand_path(loc) } - if node_locations.length > 1 - node_msg = "#{prefix}:\n#{node_locations.join("\n")}\nProceed? (y/n)" - else - node_msg = "#{prefix} #{node_locations[0]} - proceed? (y/n)" - end - if $terminal.agree(node_msg) - node_locations.each { |node| FileUtils.rm node } - end + prefix = "You are about to delete" + node_paths = nodes.map { |n| File.expand_path(n.path) } + if node_paths.length > 1 + node_msg = "#{prefix}:\n#{node_paths.join("\n")}\nProceed? (y/n)" else - puts "No assets found" + node_msg = "#{prefix} #{node_paths[0]} - proceed? (y/n)" + end + if $terminal.agree(node_msg) + node_paths.each { |path| FileUtils.rm path } end end end diff --git a/lib/inventoryware/commands/modifys/groups.rb b/lib/inventoryware/commands/modifys/groups.rb index 5f5b188..18ead18 100644 --- a/lib/inventoryware/commands/modifys/groups.rb +++ b/lib/inventoryware/commands/modifys/groups.rb @@ -41,8 +41,7 @@ def run group = @argv[0] - find_nodes("group").each do |location| - node = Node.new(location) + fetch_nodes("group").each do |node| type = Utils.get_new_asset_type if @options.create node.create_if_non_existent(type) if @options.primary diff --git a/lib/inventoryware/commands/modifys/map.rb b/lib/inventoryware/commands/modifys/map.rb index b3046d5..d865a0d 100644 --- a/lib/inventoryware/commands/modifys/map.rb +++ b/lib/inventoryware/commands/modifys/map.rb @@ -33,8 +33,7 @@ module Commands module Modifys class Map < MultiNodeCommand def run - nodes = find_nodes() - nodes.map! { |n| Node.new(n) } + nodes = fetch_nodes() node = nodes.first prompt = TTY::Prompt.new diff --git a/lib/inventoryware/commands/modifys/notes.rb b/lib/inventoryware/commands/modifys/notes.rb index 307e3c9..f3145e8 100644 --- a/lib/inventoryware/commands/modifys/notes.rb +++ b/lib/inventoryware/commands/modifys/notes.rb @@ -32,8 +32,7 @@ module Commands module Modifys class Notes < MultiNodeCommand def run - nodes = find_nodes() - nodes.map! { |n| Node.new(n) } + nodes = fetch_nodes() node = nodes.first notes = node.data['mutable'].fetch('notes', '') diff --git a/lib/inventoryware/commands/modifys/other.rb b/lib/inventoryware/commands/modifys/other.rb index 28be708..ad3937f 100644 --- a/lib/inventoryware/commands/modifys/other.rb +++ b/lib/inventoryware/commands/modifys/other.rb @@ -49,8 +49,7 @@ def run ERROR end - find_nodes("modification").each do |location| - node = Node.new(location) + fetch_nodes("modification").each do |node| type = Utils.get_new_asset_type if @options.create node.create_if_non_existent(type) if value diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index 8e8ff35..f3e6eda 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -33,12 +33,15 @@ module Inventoryware module Commands class MultiNodeCommand < Command - def find_nodes(*args) + def fetch_nodes(*args) resolve_node_options(@argv, @options, args) nodes = @argv[args.length] - node_locations = locate_nodes(nodes, @options) + node_paths = find_nodes(nodes, @options) + node_paths = node_paths.uniq + nodes = node_paths.map { |p| Node.new(p) } + #create if non-existant here end private @@ -64,7 +67,7 @@ def resolve_node_options(argv, options, other_args) # given a set of nodes and relevant options returns an expanded list # of all the necessary nodes - def locate_nodes(nodes, options) + def find_nodes(nodes, options) node_locations = [] if options.all node_locations = Node.find_all_nodes diff --git a/lib/inventoryware/commands/shows/document.rb b/lib/inventoryware/commands/shows/document.rb index 348a267..c34aad1 100644 --- a/lib/inventoryware/commands/shows/document.rb +++ b/lib/inventoryware/commands/shows/document.rb @@ -39,24 +39,20 @@ module Commands module Shows class Document < MultiNodeCommand def run - node_locations = find_nodes() - node_locations = node_locations.uniq - node_locations = node_locations.sort_by do |location| - File.basename(location) - end + nodes = fetch_nodes() + nodes = nodes.sort_by { |node| node.name } - output(node_locations, @options.location) + output(nodes, @options.location) end private - def output(node_locations, out_dest) + def output(nodes, out_dest) out = "" # check, will loading all output cause issues with memory size? # probably fine - 723 nodes was 350Kb - node_locations.each do |location| - node = Node.new(location) + nodes.each do |node| out += fill_template(node, find_template(node), render_env) - $stderr.puts "Rendered #{File.basename(location, '.yaml')}" + $stderr.puts "Rendered #{File.basename(node.path, '.yaml')}" end if out_dest @@ -143,7 +139,7 @@ def fill_template(node, template, render_env) rescue StandardError => e unless @options.debug raise ParseError, <<-ERROR.chomp -Error filling template using #{File.basename(node_location)}. +Error filling template using #{File.basename(node.path)}. Use '--debug' for more information ERROR else From 934952cb9a5ca527c7d7ec04e63f71c6f6a6411f Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 16:26:41 +0000 Subject: [PATCH 23/24] move 'create_if_non_existent' call to fetch_nodes --- lib/inventoryware/commands/modifys/groups.rb | 2 -- lib/inventoryware/commands/modifys/other.rb | 2 -- lib/inventoryware/commands/multi_node_command.rb | 9 ++++++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/inventoryware/commands/modifys/groups.rb b/lib/inventoryware/commands/modifys/groups.rb index 18ead18..304431b 100644 --- a/lib/inventoryware/commands/modifys/groups.rb +++ b/lib/inventoryware/commands/modifys/groups.rb @@ -42,8 +42,6 @@ def run group = @argv[0] fetch_nodes("group").each do |node| - type = Utils.get_new_asset_type if @options.create - node.create_if_non_existent(type) if @options.primary node.data['mutable']['primary_group'] = group else diff --git a/lib/inventoryware/commands/modifys/other.rb b/lib/inventoryware/commands/modifys/other.rb index ad3937f..21567e0 100644 --- a/lib/inventoryware/commands/modifys/other.rb +++ b/lib/inventoryware/commands/modifys/other.rb @@ -50,8 +50,6 @@ def run end fetch_nodes("modification").each do |node| - type = Utils.get_new_asset_type if @options.create - node.create_if_non_existent(type) if value node.data['mutable'][field] = value else diff --git a/lib/inventoryware/commands/multi_node_command.rb b/lib/inventoryware/commands/multi_node_command.rb index f3e6eda..7bd42a2 100644 --- a/lib/inventoryware/commands/multi_node_command.rb +++ b/lib/inventoryware/commands/multi_node_command.rb @@ -41,7 +41,14 @@ def fetch_nodes(*args) node_paths = find_nodes(nodes, @options) node_paths = node_paths.uniq nodes = node_paths.map { |p| Node.new(p) } - #create if non-existant here + if @options.create + new_nodes = nodes.select { |n| not File.file?(n.path) } + unless new_nodes.empty? + type = Utils.get_new_asset_type + new_nodes.each { |n| n.create_if_non_existent(type) } + end + end + return nodes end private From ecb5fa67e766d20ee82a6e989bd11ad7c4f33f2c Mon Sep 17 00:00:00 2001 From: DavidMarchant Date: Mon, 25 Mar 2019 16:27:09 +0000 Subject: [PATCH 24/24] Alter cli indentation I know later parameters should line up with the first one but that looks awful --- lib/inventoryware/cli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/inventoryware/cli.rb b/lib/inventoryware/cli.rb index 56e89b9..0dbd0d7 100644 --- a/lib/inventoryware/cli.rb +++ b/lib/inventoryware/cli.rb @@ -87,12 +87,12 @@ def add_multi_node_options(command) def add_create_option(command) command.option '-c', '--create', - "Create specified asset(s) if they don't exist" + "Create specified asset(s) if they don't exist" end def add_group_option(command) command.option '-g', '--group GROUP', - "Select assets in GROUP, specify comma-separated list for multiple groups" + "Select assets in GROUP, specify comma-separated list for multiple groups" end end