aws-codedeploy-agent 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/aws-codedeploy-agent.gemspec +5 -5
  2. data/certs/host-agent-deployment-signer-ca-chain.pem +30 -0
  3. data/conf/codedeployagent.yml +0 -1
  4. data/lib/instance_agent.rb +1 -13
  5. data/lib/instance_agent/agent/base.rb +38 -12
  6. data/lib/instance_agent/agent/plugin.rb +21 -0
  7. data/lib/instance_agent/config.rb +2 -1
  8. data/lib/instance_agent/platform/linux_util.rb +4 -0
  9. data/lib/instance_agent/plugins/codedeploy/application_specification/ace_info.rb +133 -0
  10. data/lib/instance_agent/plugins/codedeploy/application_specification/acl_info.rb +163 -0
  11. data/lib/instance_agent/plugins/codedeploy/application_specification/application_specification.rb +143 -0
  12. data/lib/instance_agent/plugins/codedeploy/application_specification/context_info.rb +23 -0
  13. data/lib/instance_agent/plugins/codedeploy/application_specification/file_info.rb +23 -0
  14. data/lib/instance_agent/plugins/codedeploy/application_specification/linux_permission_info.rb +121 -0
  15. data/lib/instance_agent/plugins/codedeploy/application_specification/mode_info.rb +66 -0
  16. data/lib/instance_agent/plugins/codedeploy/application_specification/range_info.rb +134 -0
  17. data/lib/instance_agent/plugins/codedeploy/application_specification/script_info.rb +27 -0
  18. data/lib/instance_agent/plugins/codedeploy/codedeploy_control.rb +100 -0
  19. data/lib/instance_agent/plugins/codedeploy/command_executor.rb +359 -0
  20. data/lib/instance_agent/plugins/codedeploy/command_poller.rb +178 -0
  21. data/lib/instance_agent/plugins/codedeploy/deployment_specification.rb +161 -0
  22. data/lib/instance_agent/plugins/codedeploy/hook_executor.rb +226 -0
  23. data/lib/instance_agent/plugins/codedeploy/install_instruction.rb +389 -0
  24. data/lib/instance_agent/plugins/codedeploy/installer.rb +147 -0
  25. data/lib/instance_agent/plugins/codedeploy/onpremise_config.rb +42 -0
  26. data/lib/instance_agent/plugins/codedeploy/register_plugin.rb +17 -0
  27. data/lib/instance_agent/runner/child.rb +20 -5
  28. data/lib/instance_agent/runner/master.rb +2 -15
  29. data/lib/instance_metadata.rb +2 -2
  30. data/test/certificate_helper.rb +1 -1
  31. data/test/helpers/instance_agent_helper.rb +1 -0
  32. data/test/instance_agent/agent/base_test.rb +16 -3
  33. data/test/instance_agent/config_test.rb +2 -1
  34. data/test/instance_agent/plugins/codedeploy/application_specification_test.rb +1713 -0
  35. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/codedeploy_control_test.rb +1 -1
  36. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/command_executor_test.rb +32 -9
  37. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/command_poller_test.rb +13 -14
  38. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/deployment_specification_test.rb +98 -25
  39. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/hook_executor_test.rb +83 -15
  40. data/test/instance_agent/plugins/codedeploy/install_instruction_test.rb +568 -0
  41. data/test/instance_agent/{codedeploy_plugin → plugins/codedeploy}/installer_test.rb +12 -9
  42. data/test/instance_agent/plugins/codedeploy/onpremise_config_test.rb +72 -0
  43. data/test/instance_agent/runner/child_test.rb +1 -1
  44. data/vendor/gems/.codedeploy-commands-1.0.0.created.rid +1 -1
  45. data/vendor/gems/codedeploy-commands/lib/aws/plugins/deploy_control_endpoint.rb +4 -0
  46. data/vendor/gems/jmespath-1.0.1/lib/jmespath.rb +41 -0
  47. data/vendor/gems/jmespath-1.0.1/lib/jmespath/caching_parser.rb +30 -0
  48. data/vendor/gems/jmespath-1.0.1/lib/jmespath/errors.rb +17 -0
  49. data/vendor/gems/jmespath-1.0.1/lib/jmespath/expr_node.rb +15 -0
  50. data/vendor/gems/jmespath-1.0.1/lib/jmespath/lexer.rb +116 -0
  51. data/vendor/gems/jmespath-1.0.1/lib/jmespath/parser.rb +347 -0
  52. data/vendor/gems/jmespath-1.0.1/lib/jmespath/runtime.rb +71 -0
  53. data/vendor/gems/jmespath-1.0.1/lib/jmespath/token.rb +41 -0
  54. data/vendor/gems/jmespath-1.0.1/lib/jmespath/token_stream.rb +60 -0
  55. data/vendor/gems/jmespath-1.0.1/lib/jmespath/tree_interpreter.rb +523 -0
  56. data/vendor/gems/jmespath-1.0.1/lib/jmespath/version.rb +3 -0
  57. data/vendor/gems/process_manager/lib/process_manager/master.rb +16 -5
  58. data/vendor/specifications/{aws-sdk-core-2.0.5.gemspec → aws-sdk-core-2.0.42.gemspec} +9 -11
  59. data/vendor/specifications/builder-3.2.2.gemspec +1 -1
  60. data/vendor/specifications/codedeploy-commands-1.0.0.gemspec +7 -6
  61. data/vendor/specifications/gli-2.5.6.gemspec +1 -1
  62. data/vendor/specifications/jmespath-1.0.1.gemspec +29 -0
  63. data/vendor/specifications/little-plugger-1.1.3.gemspec +1 -1
  64. data/vendor/specifications/logging-1.8.1.gemspec +1 -1
  65. data/vendor/specifications/multi_json-1.7.7.gemspec +1 -1
  66. data/vendor/specifications/multi_json-1.8.4.gemspec +1 -1
  67. data/vendor/specifications/multi_xml-0.5.5.gemspec +1 -1
  68. data/vendor/specifications/process_manager-0.0.13.gemspec +1 -1
  69. data/vendor/specifications/simple_pid-0.2.1.gemspec +1 -1
  70. metadata +76 -63
  71. data/lib/instance_agent/codedeploy_plugin/application_specification/ace_info.rb +0 -133
  72. data/lib/instance_agent/codedeploy_plugin/application_specification/acl_info.rb +0 -163
  73. data/lib/instance_agent/codedeploy_plugin/application_specification/application_specification.rb +0 -142
  74. data/lib/instance_agent/codedeploy_plugin/application_specification/context_info.rb +0 -23
  75. data/lib/instance_agent/codedeploy_plugin/application_specification/file_info.rb +0 -23
  76. data/lib/instance_agent/codedeploy_plugin/application_specification/linux_permission_info.rb +0 -121
  77. data/lib/instance_agent/codedeploy_plugin/application_specification/mode_info.rb +0 -66
  78. data/lib/instance_agent/codedeploy_plugin/application_specification/range_info.rb +0 -134
  79. data/lib/instance_agent/codedeploy_plugin/application_specification/script_info.rb +0 -27
  80. data/lib/instance_agent/codedeploy_plugin/codedeploy_control.rb +0 -72
  81. data/lib/instance_agent/codedeploy_plugin/command_executor.rb +0 -357
  82. data/lib/instance_agent/codedeploy_plugin/command_poller.rb +0 -170
  83. data/lib/instance_agent/codedeploy_plugin/deployment_specification.rb +0 -150
  84. data/lib/instance_agent/codedeploy_plugin/hook_executor.rb +0 -206
  85. data/lib/instance_agent/codedeploy_plugin/install_instruction.rb +0 -374
  86. data/lib/instance_agent/codedeploy_plugin/installer.rb +0 -143
  87. data/lib/instance_agent/codedeploy_plugin/request_helper.rb +0 -28
  88. data/test/instance_agent/codedeploy_plugin/application_specification_test.rb +0 -1710
  89. data/test/instance_agent/codedeploy_plugin/install_instruction_test.rb +0 -566
  90. data/test/instance_agent/codedeploy_plugin/request_helper_test.rb +0 -37
  91. data/vendor/specifications/jamespath-0.5.1.gemspec +0 -35
@@ -0,0 +1,143 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ class AppSpecValidationException < Exception; end
6
+
7
+ class ApplicationSpecification
8
+
9
+ attr_reader :version, :os, :hooks, :files, :permissions
10
+ def initialize(yaml_hash, opts = {})
11
+ @version = parse_version(yaml_hash['version'])
12
+ @os = parse_os(yaml_hash['os'])
13
+ @hooks = parse_hooks(yaml_hash['hooks'] || {})
14
+ @files = parse_files(yaml_hash['files'] || [])
15
+ @permissions = parse_permissions(yaml_hash['permissions'] || [])
16
+ end
17
+
18
+ def self.parse(app_spec_string)
19
+ new(YAML.load(app_spec_string))
20
+ end
21
+
22
+ private
23
+ def supported_versions()
24
+ [0.0]
25
+ end
26
+
27
+ def parse_version(version)
28
+ if !supported_versions.include?(version)
29
+ raise AppSpecValidationException, "unsupported version: #{version}"
30
+ end
31
+ version
32
+ end
33
+
34
+ def supported_oses()
35
+ InstanceAgent::Platform.util.supported_oses()
36
+ end
37
+
38
+ def parse_os(os)
39
+ if !supported_oses.include?(os)
40
+ raise AppSpecValidationException, "unsupported os: #{os}"
41
+ end
42
+ os
43
+ end
44
+
45
+ def parse_files(file_map_hash)
46
+ files = []
47
+ #loop through hash and create fileInfo representations
48
+ file_map_hash.each do |mapping|
49
+ files << FileInfo.new(mapping['source'], mapping['destination'])
50
+ end
51
+ files
52
+ end
53
+
54
+ def parse_hooks(hooks_hash)
55
+ temp_hooks_hash = Hash.new
56
+ hooks_hash.each_pair do |hook, scripts|
57
+ current_hook_scripts = []
58
+ scripts.each do |script|
59
+ if (script.has_key?('location') && !script['location'].nil?)
60
+ current_hook_scripts << InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::ScriptInfo.new(script['location'].to_s.strip,
61
+ {
62
+ :runas => script.has_key?('runas') && !script['runas'].nil? ? script['runas'].to_s.strip : nil,
63
+ :timeout => script['timeout']
64
+ })
65
+ else
66
+ raise AppSpecValidationException, 'script provided without a location value'
67
+ end
68
+ end
69
+ temp_hooks_hash[hook] = current_hook_scripts
70
+ end
71
+ temp_hooks_hash
72
+ end
73
+
74
+ def parse_permissions(permissions_list)
75
+ permissions = []
76
+ #loop through list and create permissionsInfo representations
77
+ permissions_list.each do |permission|
78
+ if !permission.has_key?('object') || permission['object'].nil?
79
+ raise AppSpecValidationException, 'permission provided without a object value'
80
+ end
81
+ if @os.eql?('linux')
82
+ permissions << InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::LinuxPermissionInfo.new(permission['object'].to_s.strip,
83
+ {
84
+ :pattern => ('**'.eql?(permission['pattern']) || permission['pattern'].nil?) ? '**' : parse_simple_glob(permission['pattern']),
85
+ :except => parse_simple_glob_list(permission['except']),
86
+ :type => parse_type_list(permission['type']),
87
+ :owner => permission['owner'],
88
+ :group => permission['group'],
89
+ :mode => parse_mode(permission['mode']),
90
+ :acls => parse_acl(permission['acls']),
91
+ :context => parse_context(permission['context'])
92
+ })
93
+ else
94
+ raise AppSpecValidationException, 'permissions only supported with linux os currently'
95
+ end
96
+ end
97
+ permissions
98
+ end
99
+
100
+ #placeholder for parsing globs: we should verify that the glob is only including what we expect. For now just returning it as it is.
101
+ def parse_simple_glob(glob)
102
+ glob
103
+ end
104
+
105
+ def parse_simple_glob_list(glob_list)
106
+ temp_glob_list = []
107
+ (glob_list || []).each do |glob|
108
+ temp_glob_list << parse_simple_glob(glob)
109
+ end
110
+ temp_glob_list
111
+ end
112
+
113
+ def supported_types
114
+ ['file', 'directory']
115
+ end
116
+
117
+ def parse_type_list(type_list)
118
+ type_list ||= supported_types
119
+ type_list.each do |type|
120
+ if !supported_types.include?(type)
121
+ raise AppSpecValidationException, "assigning permissions to objects of type #{type} not supported"
122
+ end
123
+ end
124
+ type_list
125
+ end
126
+
127
+ def parse_mode(mode)
128
+ mode.nil? ? nil : InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::ModeInfo.new(mode)
129
+ end
130
+
131
+ def parse_acl(acl)
132
+ acl.nil? ? nil : InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::AclInfo.new(acl)
133
+ end
134
+
135
+ def parse_context(context)
136
+ context.nil? ? nil : InstanceAgent::Plugins::CodeDeployPlugin::ApplicationSpecification::ContextInfo.new(context)
137
+ end
138
+ end
139
+
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,23 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ #Helper Class for storing a context
6
+ class ContextInfo
7
+
8
+ attr_reader :user, :role, :type, :range
9
+ def initialize(context)
10
+ if context['type'].nil?
11
+ raise AppSpecValidationException, "invalid context type required #{context.inspect}"
12
+ end
13
+ @user = context['name']
14
+ @role = nil
15
+ @type = context['type']
16
+ @range = context['range'].nil? ? nil : RangeInfo.new(context['range'])
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ #Helper class for storing data parsed from file maps
6
+ class FileInfo
7
+
8
+ attr_reader :source, :destination
9
+ def initialize(source, destination, opts = {})
10
+ if(source.nil?)
11
+ raise AppSpecValidationException, 'File needs to have a source'
12
+ elsif (destination.nil?)
13
+ raise AppSpecValidationException, 'File needs to have a destination'
14
+ end
15
+ @source = source
16
+ @destination = destination
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,121 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ #Helper Class for storing data parsed from permissions list
6
+ class LinuxPermissionInfo
7
+
8
+ attr_reader :object, :pattern, :except, :type, :owner, :group, :mode, :acls, :context
9
+ def initialize(object, opts = {})
10
+ object = object.to_s
11
+ if (object.empty?)
12
+ raise AppSpecValidationException, 'Permission needs a object value'
13
+ end
14
+ @object = object
15
+ @pattern = opts[:pattern] || "**"
16
+ @except = opts[:except] || []
17
+ @type = opts[:type] || ["file", "directory"]
18
+ @owner = opts[:owner]
19
+ @group = opts[:group]
20
+ @mode = opts[:mode]
21
+ @acls = opts[:acls]
22
+ @context = opts[:context]
23
+ end
24
+
25
+ def validate_file_permission()
26
+ if @type.include?("file")
27
+ if !"**".eql?(@pattern)
28
+ raise AppSpecValidationException, "Attempt to use pattern #{@pattern} when assigning permissions to file #{@object}"
29
+ end
30
+ if !@except.empty?
31
+ raise AppSpecValidationException, "Attempt to use except #{@except} when assigning permissions to file #{@object}"
32
+ end
33
+ end
34
+ end
35
+
36
+ def validate_file_acl(object)
37
+ if !@acls.nil?
38
+ default_acl = @acls.get_default_ace
39
+ if !default_acl.nil?
40
+ raise "Attempt to set default acl #{default_acl} on file #{object}"
41
+ end
42
+ end
43
+ end
44
+
45
+ def matches_pattern?(name)
46
+ name = name.chomp(File::SEPARATOR)
47
+ base_object = sanitize_dir_path(@object)
48
+ if !base_object.end_with?(File::SEPARATOR)
49
+ base_object = base_object + File::SEPARATOR
50
+ end
51
+ if name.start_with?(base_object)
52
+ if ("**".eql?(@pattern))
53
+ return true
54
+ end
55
+ rel_name = name[base_object.length..name.length]
56
+ return matches_simple_glob(rel_name, @pattern)
57
+ end
58
+ false
59
+ end
60
+
61
+ def matches_except?(name)
62
+ name = name.chomp(File::SEPARATOR)
63
+ base_object = sanitize_dir_path(@object)
64
+ if !base_object.end_with?(File::SEPARATOR)
65
+ base_object = base_object + File::SEPARATOR
66
+ end
67
+ if name.start_with?(base_object)
68
+ rel_name = name[base_object.length..name.length]
69
+ @except.each do |item|
70
+ if matches_simple_glob(rel_name, item)
71
+ return true
72
+ end
73
+ end
74
+ end
75
+ false
76
+ end
77
+
78
+ private
79
+ def matches_simple_glob(name, pattern)
80
+ if name.include?(File::SEPARATOR)
81
+ return false
82
+ end
83
+ options = expand(pattern.chars.entries)
84
+ name.chars.each do |char|
85
+ new_options = []
86
+ options.each do |option|
87
+ if option[0].eql?("*")
88
+ new_options.concat(expand(option))
89
+ elsif option[0].eql?(char)
90
+ option.shift
91
+ new_options.concat(expand(option))
92
+ end
93
+ end
94
+ options = new_options
95
+ if (options.include?(["*"]))
96
+ return true
97
+ end
98
+ end
99
+ options.include?([])
100
+ end
101
+
102
+ private
103
+ def expand(option)
104
+ previous_option = nil
105
+ while "*".eql?(option[0]) do
106
+ previous_option = Array.new(option)
107
+ option.shift
108
+ end
109
+ previous_option.nil? ? [option] : [previous_option, option]
110
+ end
111
+
112
+ private
113
+ def sanitize_dir_path(path)
114
+ File.expand_path(path)
115
+ end
116
+ end
117
+
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,66 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ #Helper Class for storing mode of a file
6
+ class ModeInfo
7
+
8
+ attr_reader :mode
9
+ attr_reader :world, :world_readable, :world_writable, :world_executable
10
+ attr_reader :group, :group_readable, :group_writable, :group_executable
11
+ attr_reader :owner, :owner_readable, :owner_writable, :owner_executable
12
+ attr_reader :setuid, :setgid, :sticky
13
+ def initialize(mode)
14
+ mode = mode.to_s
15
+ while mode.length < 3 do
16
+ mode = "0" + mode;
17
+ end
18
+ if mode.length > 4
19
+ raise AppSpecValidationException, "permission mode length incorrect: #{mode}"
20
+ end
21
+ mode.each_char do |char|
22
+ if (char.ord < '0'.ord) || (char.ord > '7'.ord)
23
+ raise AppSpecValidationException, "invalid character #{char} in permission mode #{mode}"
24
+ end
25
+ end
26
+ @mode = mode
27
+ mode_array = mode.reverse.chars.entries
28
+
29
+ @world = mode_array[0]
30
+ world_bits = to_bits(@world.to_i, 3)
31
+ @world_readable = (world_bits[0] == 1)
32
+ @world_writable = (world_bits[1] == 1)
33
+ @world_executable = (world_bits[2] == 1)
34
+
35
+ @group = mode_array[1]
36
+ group_bits = to_bits(@group.to_i, 3)
37
+ @group_readable = (group_bits[0] == 1)
38
+ @group_writable = (group_bits[1] == 1)
39
+ @group_executable = (group_bits[2] == 1)
40
+
41
+ @owner = mode_array[2]
42
+ owner_bits = to_bits(@owner.to_i, 3)
43
+ @owner_readable = (owner_bits[0] == 1)
44
+ @owner_writable = (owner_bits[1] == 1)
45
+ @owner_executable = (owner_bits[2] == 1)
46
+
47
+ special = (mode_array.length > 3) ? mode_array[3]: '0'
48
+ special_bits = to_bits(special.to_i, 3)
49
+ @setuid = (special_bits[0] == 1)
50
+ @setgid = (special_bits[1] == 1)
51
+ @sticky = (special_bits[2] == 1)
52
+ end
53
+
54
+ def to_bits(num, min_size)
55
+ bits = Array.new(min_size, 0)
56
+ num_bits = num.to_s(2).split("")
57
+ diff = [0, min_size - num_bits.length].max
58
+ num_bits.map.with_index {|n,i| bits[i+diff] = n.to_i}
59
+ bits
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,134 @@
1
+ module InstanceAgent
2
+ module Plugins
3
+ module CodeDeployPlugin
4
+ module ApplicationSpecification
5
+ #Helper Class for storing the range of a context
6
+ class RangeInfo
7
+
8
+ attr_reader :low_sensitivity, :high_sensitivity, :categories
9
+ def initialize(range)
10
+ parts = ensure_parts(range, ":")
11
+ sensitivity_parts = ensure_parts(parts[0], "-")
12
+ @low_sensitivity = getSensitivityNumber(sensitivity_parts[0])
13
+ if sensitivity_parts.length == 2
14
+ @high_sensitivity = getSensitivityNumber(sensitivity_parts[1])
15
+ if @high_sensitivity < @low_sensitivity
16
+ raise AppSpecValidationException, "invalid sensitivity range in #{range}"
17
+ end
18
+ else
19
+ @high_sensitivity = @low_sensitivity
20
+ end
21
+ if parts.length == 2
22
+ @categories = get_category_numbers(parts[1].split(","))
23
+ end
24
+ end
25
+
26
+ def ensure_parts(input, split_on)
27
+ num_parts = 1
28
+ if input.include?(split_on)
29
+ num_parts = 2
30
+ end
31
+ parts = input.split(split_on, 2)
32
+ if parts.length != num_parts
33
+ raise AppSpecValidationException, "invalid range part #{input}"
34
+ end
35
+ parts.each do |part|
36
+ if part.nil? || part.eql?('')
37
+ raise AppSpecValidationException, "invalid range part #{input}"
38
+ end
39
+ end
40
+ parts
41
+ end
42
+
43
+ def getSensitivityNumber(sensitivity)
44
+ if sensitivity.nil? || sensitivity.length < 2 || !sensitivity.start_with?('s')
45
+ raise AppSpecValidationException, "invalid sensitivity #{sensitivity}"
46
+ end
47
+ s_level = sensitivity.sub('s', '')
48
+ s_level.chars.each do |digit|
49
+ if (digit.ord < '0'.ord) || (digit.ord > '9'.ord)
50
+ raise AppSpecValidationException, "invalid sensitivity #{sensitivity}"
51
+ end
52
+ end
53
+ s_level.to_i
54
+ end
55
+
56
+ def get_category_number(category)
57
+ if category.nil? || category.length < 2 || !category.start_with?('c')
58
+ raise AppSpecValidationException, "invalid category #{category}"
59
+ end
60
+ c_level = category.sub('c', '')
61
+ c_level.chars.each do |digit|
62
+ if (digit.ord < '0'.ord) || (digit.ord > '9'.ord)
63
+ raise AppSpecValidationException, "invalid category #{category}"
64
+ end
65
+ end
66
+ level = c_level.to_i
67
+ if level > 1023
68
+ raise AppSpecValidationException, "invalid category #{category}"
69
+ end
70
+ level
71
+ end
72
+
73
+ def get_category_range(range)
74
+ low = get_category_number(range[0])
75
+ high = get_category_number(range[1])
76
+ if (high < low)
77
+ raise AppSpecValidationException, "invalid category range #{range[0]}.#{range[1]}"
78
+ end
79
+ (low..high).to_a
80
+ end
81
+
82
+ def get_category_numbers(parts)
83
+ temp_categories = [];
84
+ parts.each do |part|
85
+ if part.include? "."
86
+ temp_categories.concat get_category_range(ensure_parts(part, "."))
87
+ else
88
+ temp_categories << get_category_number(part)
89
+ end
90
+ end
91
+ if !temp_categories.sort!.uniq!.nil?
92
+ raise AppSpecValidationException, "duplicate categories"
93
+ end
94
+ temp_categories
95
+ end
96
+
97
+ # format s#[-s#][:c#[.c#](,c#[.c#])*] (# means a number)
98
+ def get_range
99
+ range = "s" + @low_sensitivity.to_s
100
+ if (@low_sensitivity != @high_sensitivity)
101
+ range = range + "-s" + @high_sensitivity.to_s
102
+ end
103
+ if @categories
104
+ range = range + ":"
105
+ index = 0
106
+ while index < @categories.length
107
+ if (index != 0)
108
+ range = range + ","
109
+ end
110
+
111
+ low = @categories[index]
112
+ low_index = index
113
+ high = @categories[index]
114
+ index += 1
115
+ while (@categories[index] == low + (index - low_index))
116
+ high += 1
117
+ index += 1
118
+ end
119
+
120
+ if (low == high)
121
+ range = range + "c" + low.to_s
122
+ else
123
+ range = range + "c" + low.to_s + ".c" + high.to_s
124
+ end
125
+ end
126
+ end
127
+ range
128
+ end
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end