MangUpdate 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in MangUpdate.gemspec
4
+ gemspec
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "MangUpdate/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "MangUpdate"
7
+ s.version = MangUpdate::VERSION
8
+ s.authors = ["MOZGIII"]
9
+ s.email = ["mike-n@narod.ru"]
10
+ s.homepage = ""
11
+ s.summary = %q{Use Mupfiles to update your MaNGOS server database.}
12
+ s.description = %q{This is a small gem that will help you with updating your MaNGOS server. It uses Mupfile to keep all database update logic simple.}
13
+
14
+ s.rubyforge_project = "MangUpdate"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+ s.add_runtime_dependency "thor"
25
+ s.add_runtime_dependency "activesupport"
26
+ end
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ MangUpdate
2
+ ==========
3
+
4
+ Installation
5
+ ------------
6
+
7
+ gem install mangupdate
8
+
9
+ Usage
10
+ -----
11
+
12
+ ### WARNING!!!
13
+ **Always check you config with `mangupdate -nl` (dry run and list updates) before using `mangupdate`!**
14
+
15
+ - Create `Mupfile` with `mangupdate init`.
16
+ - Edit and configure `Mupfile` as you need.
17
+ - Run `mangupdate -nl` to check that lists and jobs are configured.
18
+ - Check `Mupfile.dump` file and change numbers there to your server's current revisions.
19
+ - Use `mangupdate` to run the update.
20
+
21
+ Feel free to use `mangupdate -h update` to see all the options available.
22
+
23
+
24
+ Mupfile examples
25
+ ----------------
26
+
27
+ Just use `mangupdate init` to get a basic `Mupfile`.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mangupdate ADDED
@@ -0,0 +1,4 @@
1
+ require "MangUpdate"
2
+ require "MangUpdate/cli"
3
+
4
+ MangUpdate::CLI.start
@@ -0,0 +1,66 @@
1
+ require 'thor'
2
+ require 'MangUpdate/version'
3
+
4
+ module MangUpdate
5
+
6
+ class CLI < Thor
7
+
8
+ default_task :update
9
+
10
+ desc 'update', 'Runs the update'
11
+
12
+ method_option :debug,
13
+ :type => :boolean,
14
+ :default => false,
15
+ :aliases => '-d',
16
+ :banner => 'Print debug messages'
17
+
18
+ method_option :mupfile,
19
+ :type => :string,
20
+ :aliases => '-M',
21
+ :banner => 'Specify a Mupfile'
22
+
23
+ method_option :dry_run,
24
+ :type => :boolean,
25
+ :default => false,
26
+ :aliases => '-n',
27
+ :banner => 'Do not upload SQL files'
28
+
29
+ method_option :list,
30
+ :type => :boolean,
31
+ :default => false,
32
+ :aliases => '-l',
33
+ :banner => 'Print SQL filenames'
34
+
35
+ method_option :nodump,
36
+ :type => :boolean,
37
+ :default => false,
38
+ :banner => 'Do not dump update info'
39
+
40
+ def update
41
+ ::MangUpdate.run(options)
42
+ end
43
+
44
+
45
+ desc 'version', 'Shows the MangUpdate version'
46
+
47
+ map %w(-v --version) => :version
48
+
49
+ def version
50
+ ::MangUpdate::UI.info "MangUpdate version #{ MangUpdate::VERSION }"
51
+ end
52
+
53
+
54
+ desc 'init', 'Generates a Mupfile at the current working directory'
55
+
56
+ method_option :mupfile,
57
+ :type => :string,
58
+ :aliases => '-M',
59
+ :banner => 'Specify a Mupfile path'
60
+
61
+ def init
62
+ ::MangUpdate.initialize_template(options)
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,168 @@
1
+ module MangUpdate
2
+ class Dsl
3
+
4
+ class << self
5
+
6
+ @@options = nil
7
+ @@configs = nil
8
+
9
+ # Evaluate the DSL methods in the `Mupfile`.
10
+ #
11
+ def evaluate_mupfile(options = {})
12
+ raise ArgumentError.new('No option hash passed to evaluate_mupfile!') unless options.is_a?(Hash)
13
+
14
+ @@options = options.dup
15
+ @@configs = {}
16
+
17
+ fetch_mupfile_contents
18
+ instance_eval_mupfile(mupfile_contents)
19
+
20
+ @@configs.each do |key, value|
21
+ @@options[key] = value unless @@options.key?(key)
22
+ end
23
+ @@options
24
+ end
25
+
26
+ def instance_eval_mupfile(contents)
27
+ new.instance_eval(contents, @@options[:mupfile_path], 1)
28
+ rescue
29
+ UI.error "Invalid Mupfile, original error is:\n#{ $! }"
30
+ raise if @@options[:debug]
31
+ exit 1
32
+ end
33
+
34
+ def read_mupfile(mupfile_path)
35
+ @@options[:mupfile_path] = mupfile_path
36
+ @@options[:mupfile_contents] = File.read(mupfile_path)
37
+ rescue
38
+ UI.error("Error reading file #{ mupfile_path }")
39
+ exit 1
40
+ end
41
+
42
+ # Get the content to evaluate and stores it into
43
+ # the options as `:mupfile_contents`.
44
+ #
45
+ def fetch_mupfile_contents
46
+ if @@options[:mupfile_contents]
47
+ UI.info 'Using inline Mupfile.'
48
+ @@options[:mupfile_path] = 'Inline Mupfile'
49
+
50
+ elsif @@options[:mupfile]
51
+ if File.exist?(@@options[:mupfile])
52
+ read_mupfile(@@options[:mupfile])
53
+ UI.info "Using Mupfile at #{ @@options[:mupfile] }."
54
+ else
55
+ UI.error "No Mupfile exists at #{ @@options[:mupfile] }."
56
+ exit 1
57
+ end
58
+
59
+ else
60
+ if File.exist?(mupfile_default_path)
61
+ read_mupfile(mupfile_default_path)
62
+ else
63
+ UI.error 'No Mupfile found, please create one with `mangupdate init`.'
64
+ exit 1
65
+ end
66
+ end
67
+
68
+ if mupfile_contents.empty?
69
+ UI.error "The command file(#{ @@options[:mupfile] }) seems to be empty."
70
+ exit 1
71
+ end
72
+ end
73
+
74
+ def mupfile_contents
75
+ @@options ? @@options[:mupfile_contents] : ''
76
+ end
77
+
78
+ def mupfile_path
79
+ @@options ? @@options[:mupfile_path] : ''
80
+ end
81
+
82
+ def mupfile_default_path
83
+ File.join(Dir.pwd, 'Mupfile')
84
+ end
85
+
86
+ end
87
+
88
+ def initialize
89
+ @tmp = {}
90
+ end
91
+
92
+ def tmp_block(merge_options = {})
93
+ return unless block_given?
94
+ preserve_tmp = @tmp
95
+ @tmp = {} if @tmp.nil? && merge_options
96
+ @tmp = @tmp.merge(merge_options) if @tmp.respond_to?(:merge)
97
+ val = yield
98
+ @tmp = preserve_tmp
99
+ val
100
+ end
101
+
102
+ def list(name)
103
+ tmp_block({ :type => :list, :paths => [] }) do
104
+ yield if block_given?
105
+ MangUpdate.add_list(name, @tmp[:paths])
106
+ end
107
+ end
108
+
109
+ def path(path, options = {})
110
+ raise "path must be called inside of a list block" unless @tmp[:type] == :list
111
+ @tmp[:paths] << [path, options]
112
+ end
113
+
114
+ def job(name)
115
+ # jobs are just for some extra groupping
116
+ tmp_block({ :type => :job, :applies => [] }) do
117
+ yield if block_given?
118
+ MangUpdate.add_job(name, @tmp[:applies])
119
+ end
120
+ end
121
+
122
+ def filtered(options = { :clear => false })
123
+ raise "filtered must be called inside of a job block" unless [:job, :filtered].member?(@tmp[:type])
124
+ filters_new = []
125
+ filters_new = @tmp[:filters] if @tmp[:filters] && !options[:clear]
126
+ tmp_block({ :type => :filtered, :filters => filters_new, :jobname => @tmp[:jobname] }) do
127
+ yield if block_given?
128
+ end
129
+ end
130
+
131
+ def filter(&block)
132
+ raise "filter must be called inside of a filtered block" unless @tmp[:type] == :filtered
133
+ @tmp[:filters] << block
134
+ end
135
+
136
+ def apply(options = {})
137
+ raise "apply must be called inside of a job block" unless [:job, :filtered].member?(@tmp[:type])
138
+ @tmp[:applies] << [:list, options, @tmp[:filters] || []]
139
+ end
140
+
141
+ def config(*args)
142
+ name = args.shift
143
+ case args.size
144
+ when 0
145
+ @@configs[name.downcase.to_sym]
146
+ when 1
147
+ @@configs[name.downcase.to_sym] = args[0]
148
+ else
149
+ raise ArgumentError, "Wrong number of arguments!"
150
+ end
151
+ end
152
+
153
+ def build_lists
154
+ MangUpdate.build_lists
155
+ end
156
+
157
+ def upload_file(filename, database, rev = nil)
158
+ raise "upload_file must be called inside of a job block" unless @tmp[:type] == :job
159
+ @tmp[:applies] << [:file, filename, database, rev]
160
+ end
161
+
162
+ def upload_sql_string(sql, database, rev = nil)
163
+ raise "upload_sql_string must be called inside of a job block" unless @tmp[:type] == :job
164
+ @tmp[:applies] << [:inline, sql, database, rev]
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,44 @@
1
+ require 'yaml'
2
+
3
+ module MangUpdate
4
+ class Dumpfile
5
+
6
+ class << self
7
+ def load(path = "Mupfile.dump")
8
+ from_hash(YAML.load(File.read(path)))
9
+ rescue
10
+ nil
11
+ end
12
+
13
+ def write(dump, path = "Mupfile.dump")
14
+ File.open(path, "wb") do |f|
15
+ f.write dump.to_hash.to_yaml
16
+ end
17
+ end
18
+
19
+ def from_hash(hash)
20
+ dumpfile = self.new
21
+ dumpfile.revs = hash[:revs]
22
+ dumpfile
23
+ end
24
+ end
25
+
26
+ attr_accessor :revs
27
+ def initialize(revs = {})
28
+ @revs = revs
29
+ end
30
+
31
+ def update_revs(revs_new = {})
32
+ revs_new.each do |key, value|
33
+ @revs[key] = value if !@revs.key?(key) || @revs[key] < value
34
+ end
35
+ end
36
+
37
+ def to_hash
38
+ {
39
+ :revs => revs
40
+ }
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,54 @@
1
+ module MangUpdate
2
+ class Job
3
+ attr_reader :name, :updates, :latest_revs
4
+
5
+ def initialize(name, applies)
6
+ @name = name
7
+ @applies = applies
8
+ @updates = nil
9
+ @latest_revs = {}
10
+ end
11
+
12
+ def collect_updates
13
+ @updates = []
14
+ @applies.each do |apply|
15
+ type = apply.shift
16
+ case type
17
+ when :list
18
+ options, filters = apply
19
+
20
+ updates = []
21
+ MangUpdate.lists(options).each do |list|
22
+ next unless list.built?
23
+
24
+ list.updates.each do |update|
25
+ selected = filters.all? do |filter|
26
+ filter.call(update, list)
27
+ end
28
+
29
+ if selected
30
+ @latest_revs[list.name] = update.rev
31
+ updates << update
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ @updates << updates
38
+ when :file
39
+ filename, database, rev = apply
40
+ model = Model::Common.new(filename, database, rev || 0)
41
+ @updates << [ model ]
42
+
43
+ when :inline
44
+ sql, database, rev = apply
45
+ model = Model::InlineSql.new(nil, database, rev || 0, { :sql => sql })
46
+ @updates << [ model ]
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1 @@
1
+ module MangUpdate
2
  class List
1
3
 
2
4
  attr_reader :name, :updates
3
5
  attr_accessor :current_rev
4
6
 
5
7
  def initialize(name, paths)
6
8
  @name = name
7
9
  @paths = []
8
10
  @updates = []
9
11
  @built = false
10
12
  @current_rev = 0
11
13
  add_paths(paths)
12
14
  end
13
15
 
14
16
  def add_paths(paths)
15
17
  paths.each do |path|
16
18
  _path, options = path
17
19
  @paths << Path.new(_path, options)
18
20
  end
19
21
  end
20
22
 
21
23
  def build!
22
24
  @built = true
23
25
  @paths.each do |path|
24
26
  path.scan do |update|
25
27
  @updates << update
26
28
  end
27
29
  end
28
30
  sort_list!(@updates)
29
31
  rescue
30
32
  @built = false
31
33
  raise
32
34
  end
33
35
 
34
36
  def built?
35
37
  @built
36
38
  end
37
39
 
38
40
  private
39
41
 
40
42
  # This sorts the array of updates by it's sort_data field
41
43
  def sort_list!(list)
42
44
  list.sort! do |a,b|
43
45
  a, b = a.sort_data, b.sort_data
44
46
  i = 0
45
47
  i += 1 while a[i] == b[i] && (a[i+1] || b[i+1])
46
48
  if a[i] && b[i]
47
49
  a[i] <=> b[i]
48
50
  else
49
51
  a[i] ? 1 : -1
50
52
  end
51
53
  end
52
54
  list
53
55
  end
54
56
 
55
57
  end
@@ -0,0 +1,38 @@
1
+ module MangUpdate
2
+ module Model
3
+
4
+ autoload :Common, 'MangUpdate/models/common'
5
+ autoload :InlineSql, 'MangUpdate/models/inline_sql'
6
+
7
+ class Base
8
+
9
+ attr_reader :filename, :database, :rev, :info
10
+ attr_accessor :applied
11
+
12
+ def self.build(filename, options = {})
13
+ raise "Do not know how to build #{name}"
14
+
15
+ # Should be overwritten by subclasses with something like self.new ...
16
+ end
17
+
18
+ def initialize(filename, database, rev, info = {})
19
+ @filename = filename
20
+ @database = database
21
+ @rev = rev
22
+ @info = info
23
+ end
24
+
25
+ def sort_data
26
+ [rev]
27
+ end
28
+
29
+ def to_s
30
+ "Rev#{rev} [#{self.class.name}:#{filename}]"
31
+ end
32
+
33
+ def upload
34
+ MangUpdate.upload_file_to_db(filename, database)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ module MangUpdate
2
+ module Model
3
+
4
+ class Common < Base
5
+
6
+ def self.build(filename, options = {})
7
+ data = File.basename(filename, '.sql').split('_')
8
+ self.new filename, data[1], data[0].gsub(/[^0-9]/, '').to_i
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module MangUpdate
2
+ module Model
3
+
4
+ class InlineSql < Base
5
+ attr_reader :sql
6
+
7
+ def self.build(filename, options = {})
8
+ raise "#{name} can not be used as a model"
9
+ end
10
+
11
+ def initialize(filename, database, rev, info = {})
12
+ super("<Inline SQL>", database, rev, info)
13
+ @sql = @info[:sql]
14
+ end
15
+
16
+ def upload
17
+ MangUpdate.upload_inline_sql(sql, database)
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ module MangUpdate
2
+ module Model
3
+
4
+ class MainCore < Base
5
+ APPLY_PRIORITY = 1
6
+
7
+ def self.build(filename, options = {})
8
+ data = File.basename(filename, '.sql').split('_')
9
+ self.new filename, data[2], data[0].to_i, :num => data[1].to_i
10
+ end
11
+
12
+ def sort_data
13
+ [rev, APPLY_PRIORITY, info[:num]]
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module MangUpdate
2
+ module Model
3
+
4
+ class YtdbCore < Base
5
+ APPLY_PRIORITY = 2
6
+
7
+ def self.build(filename, options = {})
8
+ data = File.basename(filename, '.sql').split('_')
9
+ return if data[1] == 'corepatch' # skip all corepatches...
10
+ self.new filename, data[1], data[3].gsub(/[^0-9]/, '').to_i
11
+ end
12
+
13
+ def sort_data
14
+ [rev, APPLY_PRIORITY]
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1 @@
1
+ require 'active_support/inflector'
2
  class Path
1
3
 
2
4
  def initialize(path, options = {})
3
5
  @path = path
4
6
  @options = options
5
7
 
6
8
  @model_class = get_model_class(options[:model] || :common)
7
9
  raise "Unable to load model!" unless @model_class
8
10
  end
9
11
 
10
12
  def scan
11
13
  Dir.glob(@path).each do |file|
12
14
  model = @model_class.build(file, @options)
13
15
  yield(model) if model
14
16
  end
15
17
  end
16
18
 
17
19
  private
18
20
 
19
21
  def get_model_class(name)
20
22
  name = name.to_s
21
23
  file_name = name.underscore
22
24
  const_name = name.camelize
23
25
  try_require = false
24
26
  begin
25
27
  require "MangUpdate/models/#{ file_name }" if try_require
26
28
  ::MangUpdate::Model.const_get(::MangUpdate::Model.constants.find { |c| c.to_s.downcase == const_name.downcase })
27
29
  rescue TypeError
28
30
  unless try_require
29
31
  try_require = true
30
32
  retry
31
33
  else
32
34
  UI.error "Could not find class MangUpdate::Model::#{ const_name }"
33
35
  end
34
36
  rescue LoadError => loadError
35
37
  UI.error "Could not load 'MangUpdate/models/#{ file_name }' or find class MangUpdate::Model::#{ const_name }"
36
38
  UI.error loadError.to_s
37
39
  end
38
40
  end
39
41
 
40
42
  end
@@ -0,0 +1,32 @@
1
+ base_path = "."
2
+ mangos_path = base_path + "/mangos"
3
+ scriptdev2_path = base_path + "/scriptdev2"
4
+
5
+ config :mysql_user, "mangos"
6
+ config :mysql_pass, "mangos"
7
+
8
+ list("Main Core") do
9
+ path "#{mangos_path}/sql/updates/*.sql", :model => :main_core
10
+ end
11
+
12
+ list("Main SD2") do
13
+ path "#{scriptdev2_path}/sql/updates/r*.sql"
14
+ end
15
+
16
+ job("Update all") do
17
+ filtered do
18
+
19
+ # only apply updates that have revision number
20
+ # greater than currently installed revision
21
+ filter do |update, list|
22
+ update.rev > list.current_rev
23
+ end
24
+
25
+ apply
26
+
27
+ end
28
+ end
29
+
30
+ #job("Custom SQL") do
31
+ # upload_file "#{base_path}/mangos_custom.sql", "mangos"
32
+ #end
@@ -0,0 +1,23 @@
1
+ require 'erb'
2
+
3
+ module MangUpdate
4
+ module Templating
5
+ class << self
6
+
7
+ def init_template(options = {})
8
+ b = binding
9
+ template_filename = File.join(File.dirname(__FILE__), "templates", "Mupfile.erb")
10
+
11
+ template = ERB.new(File.read(template_filename))
12
+ template.filename = template_filename
13
+
14
+ result = template.result(b)
15
+
16
+ File.open(options[:mupfile], 'wb') do |f|
17
+ f.puts(result)
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,182 @@
1
+ module MangUpdate
2
+ module UI
3
+ class << self
4
+
5
+ color_enabled = nil
6
+
7
+ # Show an info message.
8
+ #
9
+ # @param [String] message the message to show
10
+ # @option options [Boolean] reset whether to clean the output before
11
+ #
12
+ def info(message, options = { })
13
+ unless in_test_mode?
14
+ reset_line if options[:reset]
15
+ STDERR.puts color(message) if message != ''
16
+ end
17
+ end
18
+
19
+ # Show a red error message that is prefixed with ERROR.
20
+ #
21
+ # @param [String] message the message to show
22
+ # @option options [Boolean] reset whether to clean the output before
23
+ #
24
+ def error(message, options = { })
25
+ unless in_test_mode?
26
+ reset_line if options[:reset]
27
+ STDERR.puts color('ERROR: ', :red) + message
28
+ end
29
+ end
30
+
31
+ # Show a red deprecation message that is prefixed with DEPRECATION.
32
+ #
33
+ # @param [String] message the message to show
34
+ # @option options [Boolean] reset whether to clean the output before
35
+ #
36
+ def deprecation(message, options = { })
37
+ unless in_test_mode?
38
+ reset_line if options[:reset]
39
+ STDERR.puts color('DEPRECATION: ', :red) + message
40
+ end
41
+ end
42
+
43
+ # Show a debug message that is prefixed with DEBUG and a timestamp.
44
+ #
45
+ # @param [String] message the message to show
46
+ # @option options [Boolean] reset whether to clean the output before
47
+ #
48
+ def debug(message, options = { })
49
+ unless in_test_mode?
50
+ reset_line if options[:reset]
51
+ STDERR.puts color("DEBUG (#{Time.now.strftime('%T')}): ", :yellow) + message if ::MangUpdate.options && ::MangUpdate.options[:debug]
52
+ end
53
+ end
54
+
55
+ # Reset a line.
56
+ #
57
+ def reset_line
58
+ STDERR.print(color_enabled? ? "\r\e[0m" : "\r\n")
59
+ end
60
+
61
+ # Clear the output.
62
+ #
63
+ def clear
64
+ system('clear;')
65
+ end
66
+
67
+ private
68
+
69
+ def in_test_mode?
70
+ ENV['MUP_ENV'] == 'test'
71
+ end
72
+
73
+ # Reset a color sequence.
74
+ #
75
+ # @deprecated
76
+ # @param [String] text the text
77
+ #
78
+ def reset_color(text)
79
+ deprecation('UI.reset_color(text) is deprecated, please use color(text, ' ') instead.')
80
+ color(text, '')
81
+ end
82
+
83
+ # Checks if color output can be enabled.
84
+ #
85
+ # @return [Boolean] whether color is enabled or not
86
+ #
87
+ def color_enabled?
88
+ if @color_enabled.nil?
89
+ if RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
90
+ if ENV['ANSICON']
91
+ @color_enabled = true
92
+ else
93
+ @color_enabled = false
94
+ end
95
+ else
96
+ @color_enabled = true
97
+ end
98
+ end
99
+
100
+ @color_enabled
101
+ end
102
+
103
+ # Colorizes a text message. See the constant in the UI class for possible
104
+ # color_options parameters. You can pass optionally :bright, a foreground
105
+ # color and a background color.
106
+ #
107
+ # @example
108
+ #
109
+ # color('Hello World', :red, :bright)
110
+ #
111
+ # @param [String] the text to colorize
112
+ # @param [Array] color_options the color options
113
+ #
114
+ def color(text, *color_options)
115
+ color_code = ''
116
+ color_options.each do |color_option|
117
+ color_option = color_option.to_s
118
+ if color_option != ''
119
+ if !(color_option =~ /\d+/)
120
+ color_option = const_get("ANSI_ESCAPE_#{ color_option.upcase }")
121
+ end
122
+ color_code += ';' + color_option
123
+ end
124
+ end
125
+ color_enabled? ? "\e[0#{ color_code }m#{ text }\e[0m" : text
126
+ end
127
+
128
+ end
129
+
130
+ # Brighten the color
131
+ ANSI_ESCAPE_BRIGHT = '1'
132
+
133
+ # Black foreground color
134
+ ANSI_ESCAPE_BLACK = '30'
135
+
136
+ # Red foreground color
137
+ ANSI_ESCAPE_RED = '31'
138
+
139
+ # Green foreground color
140
+ ANSI_ESCAPE_GREEN = '32'
141
+
142
+ # Yellow foreground color
143
+ ANSI_ESCAPE_YELLOW = '33'
144
+
145
+ # Blue foreground color
146
+ ANSI_ESCAPE_BLUE = '34'
147
+
148
+ # Magenta foreground color
149
+ ANSI_ESCAPE_MAGENTA = '35'
150
+
151
+ # Cyan foreground color
152
+ ANSI_ESCAPE_CYAN = '36'
153
+
154
+ # White foreground color
155
+ ANSI_ESCAPE_WHITE = '37'
156
+
157
+ # Black background color
158
+ ANSI_ESCAPE_BGBLACK = '40'
159
+
160
+ # Red background color
161
+ ANSI_ESCAPE_BGRED = '41'
162
+
163
+ # Green background color
164
+ ANSI_ESCAPE_BGGREEN = '42'
165
+
166
+ # Yellow background color
167
+ ANSI_ESCAPE_BGYELLOW = '43'
168
+
169
+ # Blue background color
170
+ ANSI_ESCAPE_BGBLUE = '44'
171
+
172
+ # Magenta background color
173
+ ANSI_ESCAPE_BGMAGENTA = '45'
174
+
175
+ # Cyan background color
176
+ ANSI_ESCAPE_BGCYAN = '46'
177
+
178
+ # White background color
179
+ ANSI_ESCAPE_BGWHITE = '47'
180
+
181
+ end
182
+ end
@@ -0,0 +1,3 @@
1
+ module MangUpdate
2
+ VERSION = "0.0.1"
3
+ end
data/lib/MangUpdate.rb ADDED
@@ -0,0 +1,161 @@
1
+ module MangUpdate
2
+
3
+ autoload :Dsl, 'MangUpdate/dsl'
4
+ autoload :UI, 'MangUpdate/ui'
5
+ autoload :Templating, 'MangUpdate/templating'
6
+ autoload :List, 'MangUpdate/list'
7
+ autoload :Path, 'MangUpdate/path'
8
+ autoload :Model, 'MangUpdate/model'
9
+ autoload :Job, 'MangUpdate/job'
10
+ autoload :Dumpfile, 'MangUpdate/dumpfile'
11
+
12
+ class << self
13
+ attr_accessor :options
14
+
15
+ def run(options = {})
16
+ @lists = []
17
+ @jobs = []
18
+ @loaded_dumpfile = nil
19
+ @options = Dsl.evaluate_mupfile(options)
20
+
21
+ build_lists
22
+
23
+ load_dumpfile
24
+
25
+ unless check_database_auth_info
26
+ UI.error "Database user and password must be supplied"
27
+ exit 1
28
+ end
29
+
30
+ new_dumpfile = Dumpfile.new
31
+ execute_jobs(new_dumpfile)
32
+
33
+ dump_write(new_dumpfile) unless @options[:nodump]
34
+ end
35
+
36
+ def initialize_template(options = {})
37
+ options = { :mupfile => "Mupfile" }.merge(options)
38
+ if File.exist?(options[:mupfile])
39
+ UI.error "Mupfile already exists at #{ File.expand_path(options[:mupfile]) }"
40
+ exit 1
41
+ end
42
+
43
+ Templating.init_template({ :mupfile => "Mupfile" }.merge(options))
44
+ UI.info "Mupfile generated, feel free to edit it"
45
+ end
46
+
47
+ def lists(filter = nil)
48
+ case filter
49
+ when Hash
50
+ if filter[:except]
51
+ array = filter[:except].kind_of?(Array) ? filter[:except] : [ filter[:except] ]
52
+ @lists.find_all { |list| !array.member?(list.name) }
53
+
54
+ elsif filter[:only]
55
+ array = filter[:only].kind_of?(Array) ? filter[:only] : [ filter[:only] ]
56
+ @lists.find_all { |list| array.member?(list.name) }
57
+
58
+ else
59
+ @lists
60
+
61
+ end
62
+ when String, Symbol
63
+ @lists.find { |list| list.name == filter }
64
+ when Regexp
65
+ @lists.find_all { |list| list.name.to_s =~ filter }
66
+ when Proc
67
+ @lists.find_all { |list| filter.call(list) }
68
+ else
69
+ @lists
70
+ end
71
+ end
72
+
73
+ def add_list(name, paths)
74
+ list = lists(name)
75
+ if list.nil?
76
+ list = List.new(name, paths)
77
+ @lists << list
78
+ else
79
+ unless list.built?
80
+ list.add_paths(paths)
81
+ else
82
+ raise "List #{name} was already built, you can't add more paths to it!"
83
+ end
84
+ end
85
+ list
86
+ end
87
+
88
+ def add_job(name, uploads)
89
+ job = Job.new(name, uploads)
90
+ @jobs << job
91
+ end
92
+
93
+ def build_lists
94
+ fully_built = lists.inject(true) do |valid, list|
95
+ list.build!
96
+ valid &&= list.built?
97
+ end
98
+
99
+ raise "Some lists are not fully built!" unless fully_built
100
+ end
101
+
102
+ def execute_jobs(dumpfile)
103
+ lists.each do |list|
104
+ dumpfile.update_revs({ list.name => list.current_rev })
105
+ end
106
+
107
+ @jobs.each do |job|
108
+ UI.info "Running job: #{job.name}"
109
+
110
+ job.collect_updates
111
+
112
+ dumpfile.update_revs(job.latest_revs)
113
+
114
+ job.updates.flatten.each do |update|
115
+ UI.info update.filename if @options[:list]
116
+ update.upload unless @options[:dry_run]
117
+ end
118
+
119
+ end
120
+ end
121
+
122
+ def check_database_auth_info
123
+ [ :mysql_user, :mysql_pass ].all? do |param|
124
+ @options[param] && !@options[param].empty?
125
+ end
126
+ end
127
+
128
+ def upload_file_to_db(path, database)
129
+ user = @options[:mysql_user]
130
+ pass = @options[:mysql_pass]
131
+ command = %Q[mysql -u"#{user}" -p"#{pass}" -D"#{database}" < "#{path}"]
132
+ UI.debug "SYSTEM: #{command}"
133
+ system command
134
+ end
135
+
136
+ def upload_inline_sql(sql, database = nil)
137
+ user = @options[:mysql_user]
138
+ pass = @options[:mysql_pass]
139
+
140
+ command = %Q[mysql -u"#{user}" -p"#{pass}" -D"#{database}" -B -s -e "#{sql.gsub('"', '\"')}"]
141
+ UI.debug "SYSTEM: #{command}"
142
+ system command
143
+ end
144
+
145
+ def load_dumpfile
146
+ @loaded_dumpfile = Dumpfile.load
147
+
148
+ return unless @loaded_dumpfile
149
+
150
+ @loaded_dumpfile.revs.each do |key, value|
151
+ list = lists(key)
152
+ list.current_rev = value if list
153
+ end
154
+ end
155
+
156
+ def dump_write(dump)
157
+ Dumpfile.write(dump)
158
+ end
159
+
160
+ end
161
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: MangUpdate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - MOZGIII
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-06 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &28246692 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *28246692
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &28245336 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *28245336
36
+ description: This is a small gem that will help you with updating your MaNGOS server.
37
+ It uses Mupfile to keep all database update logic simple.
38
+ email:
39
+ - mike-n@narod.ru
40
+ executables:
41
+ - mangupdate
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - .gitignore
46
+ - Gemfile
47
+ - MangUpdate.gemspec
48
+ - README.md
49
+ - Rakefile
50
+ - bin/mangupdate
51
+ - lib/MangUpdate.rb
52
+ - lib/MangUpdate/cli.rb
53
+ - lib/MangUpdate/dsl.rb
54
+ - lib/MangUpdate/dumpfile.rb
55
+ - lib/MangUpdate/job.rb
56
+ - lib/MangUpdate/list.rb
57
+ - lib/MangUpdate/model.rb
58
+ - lib/MangUpdate/models/common.rb
59
+ - lib/MangUpdate/models/inline_sql.rb
60
+ - lib/MangUpdate/models/main_core.rb
61
+ - lib/MangUpdate/models/ytdb_core.rb
62
+ - lib/MangUpdate/path.rb
63
+ - lib/MangUpdate/templates/Mupfile.erb
64
+ - lib/MangUpdate/templating.rb
65
+ - lib/MangUpdate/ui.rb
66
+ - lib/MangUpdate/version.rb
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: MangUpdate
87
+ rubygems_version: 1.8.10
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Use Mupfiles to update your MaNGOS server database.
91
+ test_files: []