aws-codedeploy-agent 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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