MangUpdate 0.0.1

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