schema-evolution-manager 0.9.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +334 -0
- data/bin/sem-add +46 -0
- data/bin/sem-apply +41 -0
- data/bin/sem-baseline +34 -0
- data/bin/sem-config +1 -0
- data/bin/sem-dist +92 -0
- data/bin/sem-info +43 -0
- data/bin/sem-init +95 -0
- data/lib/schema-evolution-manager.rb +26 -0
- data/lib/schema-evolution-manager/apply_util.rb +60 -0
- data/lib/schema-evolution-manager/args.rb +159 -0
- data/lib/schema-evolution-manager/ask.rb +44 -0
- data/lib/schema-evolution-manager/baseline_util.rb +50 -0
- data/lib/schema-evolution-manager/db.rb +104 -0
- data/lib/schema-evolution-manager/install_template.rb +118 -0
- data/lib/schema-evolution-manager/library.rb +176 -0
- data/lib/schema-evolution-manager/migration_file.rb +93 -0
- data/lib/schema-evolution-manager/preconditions.rb +61 -0
- data/lib/schema-evolution-manager/rdoc_usage.rb +37 -0
- data/lib/schema-evolution-manager/script_error.rb +19 -0
- data/lib/schema-evolution-manager/scripts.rb +95 -0
- data/lib/schema-evolution-manager/sem_info.rb +72 -0
- data/lib/schema-evolution-manager/sem_version.rb +9 -0
- data/lib/schema-evolution-manager/template.rb +39 -0
- data/lib/schema-evolution-manager/version.rb +71 -0
- data/scripts/20130318-105434.sql +64 -0
- data/scripts/20130318-105456.sql +135 -0
- data/template/README.md +28 -0
- data/template/dev.rb +12 -0
- metadata +80 -0
data/bin/sem-config
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
load File.join(File.dirname(__FILE__), '../lib/schema-evolution-manager.rb')
|
data/bin/sem-dist
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# == Creates a tarball containing SQL scripts that might need to be
|
3
|
+
# applied to a specific postgresql database. This tarball can then
|
4
|
+
# be uploaded, unpacked, and schema changes applied using
|
5
|
+
# schema-evolution-manager scripts
|
6
|
+
#
|
7
|
+
# == Usage
|
8
|
+
# sem-dist [--artifact_name <tag> --tag <tag>]
|
9
|
+
#
|
10
|
+
# name
|
11
|
+
# Optional artifact_name - defaults to the current directory name. Used in the
|
12
|
+
# actual artifact name which has the format <artifact_name>-<tag>.tar.gz
|
13
|
+
#
|
14
|
+
# tag
|
15
|
+
# Optional tag - if specified, we create a distribution file for this tag.
|
16
|
+
# If not specified, we create a new tag.
|
17
|
+
#
|
18
|
+
# == Example
|
19
|
+
# sem-dist
|
20
|
+
# Creates a new tag and generates the distribution file
|
21
|
+
#
|
22
|
+
# sem-dist --tag 0.0.1
|
23
|
+
# Creates a distribution file for the specified tag
|
24
|
+
#
|
25
|
+
|
26
|
+
load File.join(File.dirname(__FILE__), 'sem-config')
|
27
|
+
SchemaEvolutionManager::Library.set_verbose(true)
|
28
|
+
|
29
|
+
args = SchemaEvolutionManager::Args.from_stdin(:optional => ['artifact_name', 'tag'])
|
30
|
+
|
31
|
+
# On MAC OS X, use gnutar to avoid warnings like
|
32
|
+
# Ignoring unknown extended header keyword `SCHILY.ino'
|
33
|
+
tar_cmd = `which gnutar 2> /dev/null`.strip
|
34
|
+
if tar_cmd == ""
|
35
|
+
tar_cmd = "tar"
|
36
|
+
end
|
37
|
+
|
38
|
+
if args.tag
|
39
|
+
tag = args.tag
|
40
|
+
else
|
41
|
+
if latest = SchemaEvolutionManager::Library.latest_tag
|
42
|
+
suggested_tag = latest.next_micro.to_version_string
|
43
|
+
else
|
44
|
+
suggested_tag = "0.0.1"
|
45
|
+
end
|
46
|
+
|
47
|
+
tag = SchemaEvolutionManager::Ask.for_string("Version:", :default => suggested_tag)
|
48
|
+
if !SchemaEvolutionManager::Library.tag_exists?(tag)
|
49
|
+
SchemaEvolutionManager::Library.git_create_tag(tag)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
SchemaEvolutionManager::Library.git_assert_tag_exists(tag)
|
53
|
+
|
54
|
+
changes = SchemaEvolutionManager::Library.git_changes(:tag => tag)
|
55
|
+
repo_path = SchemaEvolutionManager::Library.normalize_path(`pwd`.strip)
|
56
|
+
|
57
|
+
if args.artifact_name
|
58
|
+
artifact_name = args.artifact_name
|
59
|
+
else
|
60
|
+
artifact_name = File.basename(repo_path)
|
61
|
+
end
|
62
|
+
|
63
|
+
filename = "%s-%s" % [artifact_name, tag]
|
64
|
+
|
65
|
+
dist_dir = File.join(repo_path, "dist")
|
66
|
+
SchemaEvolutionManager::Library.ensure_dir!(dist_dir)
|
67
|
+
tarball = File.join(dist_dir, "#{filename}.tar")
|
68
|
+
|
69
|
+
SchemaEvolutionManager::Library.with_temp_file do |tmp|
|
70
|
+
tmpdir = File.join(tmp, filename)
|
71
|
+
SchemaEvolutionManager::Library.ensure_dir!(tmpdir)
|
72
|
+
|
73
|
+
SchemaEvolutionManager::Library.system_or_error("cp -R %s %s" % [File.join(repo_path, "scripts"), File.join(tmpdir, "scripts")])
|
74
|
+
File.open(File.join(tmpdir, "CHANGES"), "w") { |out| out << changes }
|
75
|
+
|
76
|
+
Dir.chdir(tmp) do
|
77
|
+
SchemaEvolutionManager::Library.system_or_error("#{tar_cmd} cf #{filename}.tar #{filename}")
|
78
|
+
FileUtils.cp("#{filename}.tar", tarball)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
gzip_file = "#{tarball}.gz"
|
83
|
+
if File.exists?(gzip_file)
|
84
|
+
puts "Removing old gzip file at #{gzip_file}"
|
85
|
+
FileUtils.rm(gzip_file)
|
86
|
+
end
|
87
|
+
|
88
|
+
command = "gzip #{tarball}"
|
89
|
+
SchemaEvolutionManager::Library.system_or_error(command)
|
90
|
+
|
91
|
+
puts ""
|
92
|
+
puts "Created distribution file at #{gzip_file}"
|
data/bin/sem-info
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Usage
|
3
|
+
#
|
4
|
+
# sem-info command [arg1...]
|
5
|
+
#
|
6
|
+
# sem-info tag exists 1.2.3
|
7
|
+
# Returns true if the specified tag exists,
|
8
|
+
# false otherwise
|
9
|
+
#
|
10
|
+
# sem-info tag latest
|
11
|
+
# Display the latest tag
|
12
|
+
#
|
13
|
+
# sem-info version
|
14
|
+
# Display the version of schema-evolution-manager
|
15
|
+
#
|
16
|
+
# sem-info tag next [major|minor|micro]
|
17
|
+
# Output information on the next tag. Defaults to micro
|
18
|
+
# version increment from latest tag
|
19
|
+
#
|
20
|
+
# Description
|
21
|
+
#
|
22
|
+
# Utility script to pull information from the schema-evolution-manager
|
23
|
+
# libraries. Initially designed to help with wrapper scripts that
|
24
|
+
# needed information (like the next minor tag)
|
25
|
+
#
|
26
|
+
|
27
|
+
load File.join(File.dirname(__FILE__), 'sem-config')
|
28
|
+
|
29
|
+
command = ARGV.shift.to_s.strip
|
30
|
+
|
31
|
+
if command == "tag"
|
32
|
+
puts SchemaEvolutionManager::SemInfo.tag(ARGV)
|
33
|
+
|
34
|
+
elsif command == "version"
|
35
|
+
puts SchemaEvolutionManager::SemInfo.version(ARGV)
|
36
|
+
|
37
|
+
else
|
38
|
+
if command != ""
|
39
|
+
puts "ERROR: Unrecognized command[%s]" % command
|
40
|
+
puts ""
|
41
|
+
end
|
42
|
+
SchemaEvolutionManager::RdocUsage.printAndExit(1)
|
43
|
+
end
|
data/bin/sem-init
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# == Initializes an existing git repository to support schema evolutions managed
|
3
|
+
# by schema-evolution-manager
|
4
|
+
#
|
5
|
+
# == Usage
|
6
|
+
# sem-init --dir <dir> --url <url>
|
7
|
+
# or
|
8
|
+
# sem-init --dir <dir> --host <database host> --user <db user> --name <db name>
|
9
|
+
#
|
10
|
+
# dir: The directory containing a git repository that will contain the schema evolution files
|
11
|
+
# url: The connection string for the psql database
|
12
|
+
#
|
13
|
+
# == Example
|
14
|
+
# git init /tmp/example_repo
|
15
|
+
# bin/sem-init --dir /tmp/example_repo --url postgresql://username@localhost/sample
|
16
|
+
#
|
17
|
+
|
18
|
+
load File.join(File.dirname(__FILE__), 'sem-config')
|
19
|
+
SchemaEvolutionManager::Library.set_verbose(true)
|
20
|
+
|
21
|
+
args = SchemaEvolutionManager::Args.from_stdin(:required => %w(dir), :optional => %w(url host port name user))
|
22
|
+
SchemaEvolutionManager::Preconditions.check_state(File.directory?(args.dir), "Dir[%s] does not exist" % args.dir)
|
23
|
+
|
24
|
+
if args.url.nil? && args.name.nil?
|
25
|
+
puts "Must specify either url or name"
|
26
|
+
exit(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
db = SchemaEvolutionManager::Db.from_args(args)
|
30
|
+
|
31
|
+
def copy_file(source, target, substitutions)
|
32
|
+
template = SchemaEvolutionManager::Template.new
|
33
|
+
substitutions.each do |name, value|
|
34
|
+
template.add(name, value)
|
35
|
+
end
|
36
|
+
final = template.parse(IO.read(source))
|
37
|
+
File.open(target, "w") do |os|
|
38
|
+
os << final
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
template_dir = File.join(SchemaEvolutionManager::Library.base_dir, "template")
|
43
|
+
SchemaEvolutionManager::Preconditions.check_state(File.directory?(template_dir),
|
44
|
+
"Could not find schema-evolution-manager/template subdir. Expected it at[%s]" % [template_dir])
|
45
|
+
|
46
|
+
subs = {
|
47
|
+
"url" => db.url,
|
48
|
+
"add_script_path" => File.join(SchemaEvolutionManager::Library.base_dir, "bin/sem-add")
|
49
|
+
}
|
50
|
+
|
51
|
+
puts "chdir %s" % args.dir
|
52
|
+
Dir.chdir(args.dir) do
|
53
|
+
|
54
|
+
wrappers = []
|
55
|
+
Dir.glob("#{template_dir}/*").each do |path|
|
56
|
+
wrapper = File.basename(path)
|
57
|
+
if !File.exists?(wrapper)
|
58
|
+
puts "Creating wrapper script #{wrapper}"
|
59
|
+
copy_file(path, wrapper, subs)
|
60
|
+
SchemaEvolutionManager::Library.system_or_error("chmod +x #{wrapper}")
|
61
|
+
SchemaEvolutionManager::Library.system_or_error("git add #{wrapper}")
|
62
|
+
wrappers << wrapper
|
63
|
+
end
|
64
|
+
end
|
65
|
+
if !wrappers.empty?
|
66
|
+
SchemaEvolutionManager::Library.system_or_error("git commit -m 'Add schema-evolution-manager wrapper scripts' #{wrappers.join(" ")}")
|
67
|
+
end
|
68
|
+
|
69
|
+
readme = "README.md"
|
70
|
+
if !File.exists?(readme)
|
71
|
+
puts "Creating #{readme}"
|
72
|
+
copy_file("schema-evolution-manager/template/README.md", "README.md", subs)
|
73
|
+
SchemaEvolutionManager::Library.system_or_error("git add #{readme}")
|
74
|
+
SchemaEvolutionManager::Library.system_or_error("git commit -m 'Adding README.md' README.md")
|
75
|
+
end
|
76
|
+
|
77
|
+
if !File.exists?("scripts")
|
78
|
+
SchemaEvolutionManager::Library.system_or_error("mkdir scripts")
|
79
|
+
SchemaEvolutionManager::Library.system_or_error("touch scripts/.exists")
|
80
|
+
SchemaEvolutionManager::Library.system_or_error("git add scripts/.exists")
|
81
|
+
SchemaEvolutionManager::Library.system_or_error("git commit -m 'Adding scripts directory' scripts/.exists")
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create the first git tag if necessary
|
85
|
+
tags = SchemaEvolutionManager::Library.system_or_error("git tag -l")
|
86
|
+
if tags.nil? || tags == ""
|
87
|
+
puts "Creating initial git tag (0.0.1)"
|
88
|
+
SchemaEvolutionManager::Library.git_create_tag("0.0.1")
|
89
|
+
end
|
90
|
+
|
91
|
+
if SchemaEvolutionManager::Library.git_has_remote?
|
92
|
+
SchemaEvolutionManager::Library.system_or_error("git push origin master")
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
dir = File.dirname(__FILE__)
|
5
|
+
lib_dir = File.join(dir, "schema-evolution-manager")
|
6
|
+
|
7
|
+
load File.join(lib_dir, 'preconditions.rb')
|
8
|
+
load File.join(lib_dir, 'rdoc_usage.rb')
|
9
|
+
load File.join(lib_dir, 'library.rb')
|
10
|
+
|
11
|
+
# Need to set base_dir early - version.rb depends on dir being set
|
12
|
+
SchemaEvolutionManager::Library.set_base_dir(File.join(dir, '..'))
|
13
|
+
|
14
|
+
load File.join(lib_dir, 'sem_version.rb')
|
15
|
+
load File.join(lib_dir, 'ask.rb')
|
16
|
+
load File.join(lib_dir, 'version.rb')
|
17
|
+
load File.join(lib_dir, 'args.rb')
|
18
|
+
load File.join(lib_dir, 'scripts.rb')
|
19
|
+
load File.join(lib_dir, 'db.rb')
|
20
|
+
load File.join(lib_dir, 'apply_util.rb')
|
21
|
+
load File.join(lib_dir, 'baseline_util.rb')
|
22
|
+
load File.join(lib_dir, 'template.rb')
|
23
|
+
load File.join(lib_dir, 'install_template.rb')
|
24
|
+
load File.join(lib_dir, 'script_error.rb')
|
25
|
+
load File.join(lib_dir, 'sem_info.rb')
|
26
|
+
load File.join(lib_dir, 'migration_file.rb')
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module SchemaEvolutionManager
|
2
|
+
|
3
|
+
class ApplyUtil
|
4
|
+
|
5
|
+
def initialize(db, opts={})
|
6
|
+
@dry_run = opts.delete(:dry_run)
|
7
|
+
if @dry_run.nil?
|
8
|
+
@dry_run = true
|
9
|
+
end
|
10
|
+
|
11
|
+
@db = Preconditions.assert_class(db, Db)
|
12
|
+
@scripts = Scripts.new(@db, Scripts::SCRIPTS)
|
13
|
+
end
|
14
|
+
|
15
|
+
def dry_run?
|
16
|
+
@dry_run
|
17
|
+
end
|
18
|
+
|
19
|
+
# Applies scripts in order, returning number of scripts applied
|
20
|
+
def apply!(dir)
|
21
|
+
Preconditions.check_state(File.directory?(dir),
|
22
|
+
"Dir[%s] does not exist" % dir)
|
23
|
+
|
24
|
+
count = 0
|
25
|
+
@scripts.each_pending(dir) do |filename, path|
|
26
|
+
count += 1
|
27
|
+
if @dry_run
|
28
|
+
puts "[DRY RUN] Applying #{filename}"
|
29
|
+
apply_dry_run(filename, path)
|
30
|
+
else
|
31
|
+
puts "Applying #{filename}"
|
32
|
+
apply_real(filename, path)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
count
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def apply_dry_run(filename, path)
|
40
|
+
puts path
|
41
|
+
puts ""
|
42
|
+
end
|
43
|
+
|
44
|
+
def apply_real(filename, path)
|
45
|
+
have_error = true
|
46
|
+
begin
|
47
|
+
@db.psql_file(path)
|
48
|
+
have_error = false
|
49
|
+
ensure
|
50
|
+
if have_error
|
51
|
+
raise ScriptError.new(@db, filename)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
@scripts.record_as_run!(filename)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module SchemaEvolutionManager
|
2
|
+
|
3
|
+
# Container for common args, mainly to have stricter validation on
|
4
|
+
# inputs. Tried to use GetoptLong but could not write solid unit
|
5
|
+
# tests around it... so we have our own internal simple implementation.
|
6
|
+
class Args
|
7
|
+
|
8
|
+
if !defined?(FLAGS_WITH_ARGUMENTS)
|
9
|
+
FLAGS_WITH_ARGUMENTS = {
|
10
|
+
:artifact_name => "Specifies the name of the artifact. Tag will be appeneded to this name",
|
11
|
+
:user => "Connect to the database as this username instead of the default",
|
12
|
+
:host => "Specifies the host name of the machine on which the server is running",
|
13
|
+
:port => "Specifies the port on which the server is running",
|
14
|
+
:name => "Specifies the name of the database to which to connect",
|
15
|
+
:url => "Connect to the database as this username instead of the default",
|
16
|
+
:dir => "Path to a directory",
|
17
|
+
:tag => "A git tag (e.g. 0.0.1)",
|
18
|
+
:prefix => "Configure installer to use this prefix"
|
19
|
+
}
|
20
|
+
|
21
|
+
FLAGS_NO_ARGUMENTS = {
|
22
|
+
:dry_run => "Include flag to echo commands that will run without actually executing them",
|
23
|
+
:help => "Display help",
|
24
|
+
:verbose => "Enable verbose logging of all system calls",
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :artifact_name, :host, :port, :name, :prefix, :url, :user, :dir, :dry_run, :tag
|
29
|
+
|
30
|
+
# args: Actual string arguments
|
31
|
+
# :required => list of parameters that are required
|
32
|
+
# :optional => list of parameters that are optional
|
33
|
+
def initialize(args, opts={})
|
34
|
+
Preconditions.assert_class_or_nil(args, String)
|
35
|
+
required = (opts.delete(:required) || []).map { |flag| format_flag(flag) }
|
36
|
+
optional = (opts.delete(:optional) || []).map { |flag| format_flag(flag) }
|
37
|
+
Preconditions.assert_class(required, Array)
|
38
|
+
Preconditions.assert_class(optional, Array)
|
39
|
+
Preconditions.assert_empty_opts(opts)
|
40
|
+
Preconditions.check_state(optional.size + required.size > 0,
|
41
|
+
"Must have at least 1 optional or required parameter")
|
42
|
+
|
43
|
+
if !optional.include?(:help)
|
44
|
+
optional << :help
|
45
|
+
end
|
46
|
+
if !optional.include?(:verbose)
|
47
|
+
optional << :verbose
|
48
|
+
end
|
49
|
+
|
50
|
+
found_arguments = parse_string_arguments(args)
|
51
|
+
missing = required.select { |field| blank?(found_arguments[field]) }
|
52
|
+
|
53
|
+
@artifact_name = found_arguments.delete(:artifact_name)
|
54
|
+
@host = found_arguments.delete(:host)
|
55
|
+
@port = found_arguments.delete(:port)
|
56
|
+
@name = found_arguments.delete(:name)
|
57
|
+
@prefix = found_arguments.delete(:prefix)
|
58
|
+
@url = found_arguments.delete(:url)
|
59
|
+
@user = found_arguments.delete(:user)
|
60
|
+
@dir = found_arguments.delete(:dir)
|
61
|
+
@tag = found_arguments.delete(:tag)
|
62
|
+
|
63
|
+
@dry_run = found_arguments.delete(:dry_run)
|
64
|
+
@help = found_arguments.delete(:help)
|
65
|
+
@verbose = found_arguments.delete(:verbose)
|
66
|
+
|
67
|
+
Preconditions.check_state(found_arguments.empty?,
|
68
|
+
"Did not handle all flags: %s" % found_arguments.keys.join(" "))
|
69
|
+
|
70
|
+
if @help
|
71
|
+
RdocUsage.printAndExit(0)
|
72
|
+
end
|
73
|
+
|
74
|
+
if @verbose
|
75
|
+
Library.set_verbose(true)
|
76
|
+
end
|
77
|
+
|
78
|
+
if !missing.empty?
|
79
|
+
missing_fields_error(required, optional, missing)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Hack to minimize bleeding from STDIN. Returns an instance of Args class
|
84
|
+
def Args.from_stdin(opts)
|
85
|
+
values = ARGV.join(" ")
|
86
|
+
Args.new(values, opts)
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
def blank?(value)
|
91
|
+
value.to_s.strip == ""
|
92
|
+
end
|
93
|
+
|
94
|
+
def missing_fields_error(required, optional, fields)
|
95
|
+
Preconditions.assert_class(fields, Array)
|
96
|
+
Preconditions.check_state(!fields.empty?, "Missing fields cannot be empty")
|
97
|
+
|
98
|
+
title = fields.size == 1 ? "Missing parameter" : "Missing parameters"
|
99
|
+
sorted = fields.sort_by { |f| f.to_s }
|
100
|
+
|
101
|
+
puts "**************************************************"
|
102
|
+
puts "ERROR: #{title}: #{sorted.join(", ")}"
|
103
|
+
puts "**************************************************"
|
104
|
+
puts help_parameters("Required parameters", required)
|
105
|
+
puts help_parameters("Optional parameters", optional)
|
106
|
+
exit(1)
|
107
|
+
end
|
108
|
+
|
109
|
+
def help_parameters(title, parameters)
|
110
|
+
docs = []
|
111
|
+
if !parameters.empty?
|
112
|
+
docs << ""
|
113
|
+
docs << title
|
114
|
+
docs << "-------------------"
|
115
|
+
parameters.each do |flag|
|
116
|
+
documentation = FLAGS_WITH_ARGUMENTS[flag] || FLAGS_NO_ARGUMENTS[flag]
|
117
|
+
Preconditions.check_not_null(documentation, "No documentation found for flag[%s]" % flag)
|
118
|
+
docs << " --#{flag}"
|
119
|
+
docs << " " + documentation
|
120
|
+
docs << ""
|
121
|
+
end
|
122
|
+
end
|
123
|
+
docs.join("\n")
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def parse_string_arguments(args)
|
128
|
+
Preconditions.assert_class_or_nil(args, String)
|
129
|
+
found = {}
|
130
|
+
index = 0
|
131
|
+
values = args.to_s.strip.split(/\s+/)
|
132
|
+
while index < values.length do
|
133
|
+
flag = format_flag(values[index])
|
134
|
+
index += 1
|
135
|
+
|
136
|
+
if FLAGS_WITH_ARGUMENTS.has_key?(flag)
|
137
|
+
found[flag] = values[index]
|
138
|
+
index += 1
|
139
|
+
|
140
|
+
elsif FLAGS_NO_ARGUMENTS.has_key?(flag)
|
141
|
+
found[flag] = true
|
142
|
+
|
143
|
+
else
|
144
|
+
raise "Unknown flag[%s]" % flag
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
found
|
149
|
+
end
|
150
|
+
|
151
|
+
# Strip leading dashes and convert to symbol
|
152
|
+
def format_flag(flag)
|
153
|
+
Preconditions.assert_class(flag, String)
|
154
|
+
flag.sub(/^\-\-/, '').to_sym
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|