coral_core 0.1.2

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.
@@ -0,0 +1,59 @@
1
+
2
+ module Coral
3
+ module Util
4
+ class Data < Core
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Utilities
8
+
9
+ def self.merge(objects, merge_arrays = false)
10
+ value = nil
11
+ return value unless objects
12
+
13
+ unless objects.is_a?(Array)
14
+ objects = [ objects ]
15
+ end
16
+
17
+ objects.each do |object|
18
+ value = recursive_merge(value, object, merge_arrays)
19
+ end
20
+ return value
21
+ end
22
+
23
+ #---
24
+
25
+ def self.recursive_merge(overrides, data, merge_arrays = false)
26
+ return data unless overrides
27
+ return overrides unless data
28
+
29
+ if overrides.is_a?(Hash)
30
+ overrides.each do |name, override|
31
+ if data.is_a?(Hash)
32
+ if data[name]
33
+ data[name] = recursive_merge(override, data[name])
34
+ else
35
+ begin
36
+ item = override.dup
37
+ rescue TypeError
38
+ item = override
39
+ end
40
+ data[name] = recursive_merge(override, item)
41
+ end
42
+ else
43
+ data = overrides
44
+ end
45
+ end
46
+ elsif merge_arrays && overrides.is_a?(Array)
47
+ if data.is_a?(Array)
48
+ data = data | overrides
49
+ else
50
+ data = overrides
51
+ end
52
+ else
53
+ data = overrides
54
+ end
55
+ return data
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,82 @@
1
+
2
+ module Coral
3
+ module Util
4
+ class Disk < Core
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Properties
8
+
9
+ @@files = {}
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Utilities
13
+
14
+ def self.open(file_name, options = {}, reset = false)
15
+ mode = string(options[:mode])
16
+ separator = ( options[:separator] ? options[:separator] : false )
17
+ description = ( options[:description] ? options[:description] : '' )
18
+
19
+ if @@files.has_key?(file_name) && ! reset
20
+ reset = true if ! mode.empty? && mode != @@files[file_name][:mode]
21
+ end
22
+
23
+ if ! @@files.has_key?(file_name) || ! @@files[file_name][:file] || reset
24
+ @@files[file_name][:file].close if @@files[file_name][:file]
25
+ unless mode.empty?
26
+ @@files[file_name] = {
27
+ :file => File.open(file_name, mode),
28
+ :mode => mode,
29
+ }
30
+ end
31
+ end
32
+ return @@files[file_name][:file]
33
+ end
34
+
35
+ #---
36
+
37
+ def self.read(file_name, options = {})
38
+ options[:mode] = ( options[:mode] ? options[:mode] : 'r' )
39
+ file = open(file_name, options)
40
+
41
+ if file
42
+ return file.read
43
+ end
44
+ return nil
45
+ end
46
+
47
+ #---
48
+
49
+ def self.write(file_name, data, options = {})
50
+ options[:mode] = ( options[:mode] ? options[:mode] : 'w' )
51
+ file = open(file_name, options)
52
+
53
+ if file
54
+ return file.write(data)
55
+ end
56
+ return nil
57
+ end
58
+
59
+ #---
60
+
61
+ def self.log(data, options = {})
62
+ reset = ( options[:file_name] || options[:mode] )
63
+ file = open(( options[:file_name] ? options[:file_name] : 'log.txt' ), options, reset)
64
+ if file
65
+ file.write("--------------------------------------\n") if separator
66
+ file.write("#{description}\n") if description
67
+ file.write("#{data}\n")
68
+ end
69
+ end
70
+
71
+ #---
72
+
73
+ def self.close(file_names = [])
74
+ file_names = @@files.keys unless file_names && ! file_names.empty?
75
+ array(file_names).each do |file_name|
76
+ @@files[file_name][:file].close if @@files[file_name][:file]
77
+ @@files.delete(file_name)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,58 @@
1
+
2
+ module Git
3
+
4
+ #*******************************************************************************
5
+ # Errors
6
+
7
+ class GitDirectoryError < StandardError
8
+ end
9
+
10
+ #*******************************************************************************
11
+ # Base Git definition
12
+
13
+ class Base
14
+
15
+ #-----------------------------------------------------------------------------
16
+ # Constructor / Destructor
17
+
18
+ def initialize(options = {})
19
+ if working_dir = options[:working_directory]
20
+ options[:repository] ||= File.join(working_dir, '.git')
21
+
22
+ if File.file?(options[:repository])
23
+ File.read(options[:repository]).each_line do |line|
24
+ matches = line.match(/^\s*gitdir:\s*(.+)\s*/)
25
+ if matches.length && matches[1]
26
+ options[:repository] = matches[1]
27
+ break
28
+ end
29
+ end
30
+ end
31
+
32
+ if File.directory?(options[:repository])
33
+ options[:index] ||= File.join(options[:repository], 'index')
34
+ else
35
+ raise GitDirectoryError.new("Git repository directory #{options[:repository]} not found for #{working_dir}")
36
+ end
37
+ end
38
+
39
+ if options[:log]
40
+ @logger = options[:log]
41
+ @logger.info("Starting Git")
42
+ else
43
+ @logger = nil
44
+ end
45
+
46
+ @working_directory = options[:working_directory] ? Git::WorkingDirectory.new(options[:working_directory]) : nil
47
+ @repository = options[:repository] ? Git::Repository.new(options[:repository]) : nil
48
+ @index = options[:index] ? Git::Index.new(options[:index], false) : nil
49
+ end
50
+
51
+ #-----------------------------------------------------------------------------
52
+ # Commit extensions
53
+
54
+ def add(path = '.', opts = {})
55
+ self.lib.add(path, opts)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,82 @@
1
+
2
+ module Git
3
+ class Lib
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Commit extensions
7
+
8
+ def add(path = '.', opts = {})
9
+ arr_opts = []
10
+ arr_opts << '-u' if opts[:update]
11
+ if path.is_a?(Array)
12
+ arr_opts += path
13
+ else
14
+ arr_opts << path
15
+ end
16
+ command('add', arr_opts)
17
+ end
18
+
19
+ #---
20
+
21
+ def commit(message, opts = {})
22
+ arr_opts = ['-m', message]
23
+ arr_opts << "--author=\'#{opts[:author]}\'" unless opts[:author] && opts[:author].empty?
24
+ arr_opts << '-a' if opts[:add_all]
25
+ arr_opts << '--allow-empty' if opts[:allow_empty]
26
+ command('commit', arr_opts)
27
+ end
28
+
29
+ #-----------------------------------------------------------------------------
30
+ # Remote extensions
31
+
32
+ def remote_add(name, url, opts = {})
33
+ arr_opts = ['add']
34
+ arr_opts << '-f' if opts[:with_fetch]
35
+ arr_opts << name
36
+ arr_opts << url
37
+
38
+ command('remote', arr_opts)
39
+ end
40
+
41
+ #---
42
+
43
+ def remote_set_url(name, url, opts = {})
44
+ arr_opts = ['set-url']
45
+
46
+ if opts[:add]
47
+ arr_opts << '--add' if opts[:add]
48
+ end
49
+
50
+ if opts[:delete]
51
+ arr_opts << '--delete' if opts[:delete]
52
+ end
53
+
54
+ if opts[:push]
55
+ arr_opts << '--push' if opts[:push]
56
+ end
57
+
58
+ arr_opts << name
59
+ arr_opts << url
60
+
61
+ command('remote', arr_opts)
62
+ end
63
+
64
+ #---
65
+
66
+ def remote_remove(name)
67
+ command('remote', ['rm', name])
68
+ end
69
+
70
+ #-----------------------------------------------------------------------------
71
+ # Utilities
72
+
73
+ def escape(s)
74
+ escaped = s.to_s.gsub('"', '\'')
75
+ if escaped =~ /^\-+/
76
+ escaped
77
+ else
78
+ %Q{"#{escaped}"}
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module Git
3
+ class Remote
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Remote endpoints
7
+
8
+ def set_url(url, opts = {})
9
+ @base.lib.remote_set_url(@name, url, opts)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+
2
+ require 'git'
3
+
4
+ module Git
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Utilities
8
+
9
+ def self.url(host, repo, options = {})
10
+ options[:user] = ( options[:user] ? options[:user] : 'git' )
11
+ options[:auth] = ( options[:auth] ? options[:auth] : true )
12
+
13
+ return options[:user] + ( options[:auth] ? '@' : '://' ) + host + ( options[:auth] ? ':' : '/' ) + repo
14
+ end
15
+ end
@@ -0,0 +1,178 @@
1
+
2
+ module Coral
3
+ module Util
4
+ class Shell < Core
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Utilities
8
+
9
+ def self.exec!(command, options = {})
10
+ min = ( options[:min] ? options[:min].to_i : 1 )
11
+ tries = ( options[:tries] ? options[:tries].to_i : min )
12
+ tries = ( min > tries ? min : tries )
13
+
14
+ info_prefix = ( options[:info_prefix] ? options[:info_prefix] : '' )
15
+ info_suffix = ( options[:info_suffix] ? options[:info_suffix] : '' )
16
+ error_prefix = ( options[:error_prefix] ? options[:error_prefix] : '' )
17
+ error_suffix = ( options[:error_suffix] ? options[:error_suffix] : '' )
18
+
19
+ conditions = Coral::Event.instance(options[:exit], true)
20
+
21
+ $stdout.sync = true
22
+ $stderr.sync = true
23
+
24
+ for i in tries.downto(1)
25
+ ui.info(">> running: #{command}")
26
+
27
+ begin
28
+ t1, output_new, output_orig = pipe_exec_stream!($stdout, conditions, {
29
+ :prefix => info_prefix,
30
+ :suffix => info_suffix,
31
+ }) do |line|
32
+ block_given? ? yield(line) : true
33
+ end
34
+
35
+ t2, error_new, error_orig = pipe_exec_stream!($stderr, conditions, {
36
+ :prefix => error_prefix,
37
+ :suffix => error_suffix,
38
+ }) do |line|
39
+ block_given? ? yield(line) : true
40
+ end
41
+
42
+ system_success = system(command)
43
+
44
+ ensure
45
+ output_success = close_exec_pipe(t1, $stdout, output_orig, output_new)
46
+ error_success = close_exec_pipe(t2, $stderr, error_orig, error_new)
47
+ end
48
+ ui.info('')
49
+
50
+ success = ( system_success && output_success && error_success )
51
+
52
+ min -= 1
53
+ break if success && min <= 0 && conditions.empty?
54
+ end
55
+ unless conditions.empty?
56
+ success = false
57
+ end
58
+
59
+ return success
60
+ end
61
+
62
+ #---
63
+
64
+ def self.exec(command, options = {})
65
+ return exec!(command, options)
66
+ end
67
+
68
+ #---
69
+
70
+ def self.pipe_exec_stream!(output, conditions, options)
71
+ original = output.dup
72
+ read, write = IO.pipe
73
+
74
+ match_prefix = ( options[:match_prefix] ? options[:match_prefix] : 'EXIT' )
75
+
76
+ thread = process_stream!(read, original, options) do |line|
77
+ check_conditions!(line, conditions, match_prefix) do
78
+ block_given? ? yield(line) : true
79
+ end
80
+ end
81
+
82
+ thread.abort_on_exception = false
83
+
84
+ output.reopen(write)
85
+ return thread, write, original
86
+ end
87
+
88
+ #---
89
+
90
+ def self.close_exec_pipe(thread, output, original, write)
91
+ output.reopen(original)
92
+
93
+ write.close
94
+ success = thread.value
95
+ Thread.kill(thread) # Die bastard, die!
96
+
97
+ original.close
98
+ return success
99
+ end
100
+
101
+ #---
102
+
103
+ def self.check_conditions!(line, conditions, match_prefix = '')
104
+ prefix = ''
105
+
106
+ unless ! conditions || conditions.empty?
107
+ conditions.each do |key, event|
108
+ if event.check(line)
109
+ prefix = match_prefix
110
+ conditions.delete(key)
111
+ end
112
+ end
113
+ end
114
+
115
+ result = true
116
+ if block_given?
117
+ result = yield
118
+
119
+ unless prefix.empty?
120
+ case result
121
+ when Hash
122
+ result[:prefix] = prefix
123
+ else
124
+ result = { :success => result, :prefix => prefix }
125
+ end
126
+ end
127
+ end
128
+ return result
129
+ end
130
+
131
+ #---
132
+
133
+ def self.process_stream!(input, output, options)
134
+ return Thread.new do
135
+ success = true
136
+ default_prefix = ( options[:prefix] ? options[:prefix] : '' )
137
+ default_suffix = ( options[:suffix] ? options[:suffix] : '' )
138
+
139
+ begin
140
+ while ( data = input.readpartial(1024) )
141
+ message = data.strip
142
+ newline = ( data[-1,1].match(/\n/) ? true : false )
143
+
144
+ unless message.empty?
145
+ lines = message.split(/\n/)
146
+ lines.each_with_index do |line, index|
147
+ prefix = default_prefix
148
+ suffix = default_suffix
149
+
150
+ if block_given?
151
+ result = yield(line)
152
+
153
+ if result && result.is_a?(Hash)
154
+ prefix = result[:prefix]
155
+ suffix = result[:suffix]
156
+ result = result[:success]
157
+ end
158
+ success = result if success
159
+ end
160
+
161
+ prefix = ( prefix && ! prefix.empty? ? "#{prefix}: " : '' )
162
+ suffix = ( suffix && ! suffix.empty? ? suffix : '' )
163
+ eol = ( index < lines.length - 1 || newline ? "\n" : ' ' )
164
+
165
+ output.write(prefix.lstrip + line + suffix.rstrip + eol)
166
+ end
167
+ end
168
+ end
169
+ rescue EOFError
170
+ end
171
+
172
+ input.close
173
+ success
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
data/lib/coral_core.rb ADDED
@@ -0,0 +1,49 @@
1
+
2
+ home = File.dirname(__FILE__)
3
+
4
+ $:.unshift(home) unless
5
+ $:.include?(home) || $:.include?(File.expand_path(home))
6
+
7
+ #-------------------------------------------------------------------------------
8
+
9
+ require 'rubygems'
10
+
11
+ #---
12
+
13
+ # Include core
14
+ [ :interface, :core ].each do |name|
15
+ require File.join('coral_core', name.to_s + ".rb")
16
+ end
17
+
18
+ # Include utilities
19
+ [ :git, :data, :disk, :shell ].each do |name|
20
+ require File.join('coral_core', 'util', name.to_s + ".rb")
21
+ end
22
+
23
+ # Include Git overrides
24
+ Dir.glob(File.join(home, 'coral_core', 'util', 'git', '*.rb')).each do |file|
25
+ require file
26
+ end
27
+
28
+ # Include data model
29
+ [ :event, :command, :repository, :memory ].each do |name|
30
+ require File.join('coral_core', name.to_s + ".rb")
31
+ end
32
+
33
+ # Include specialized events
34
+ Dir.glob(File.join(home, 'coral_core', 'event', '*.rb')).each do |file|
35
+ require file
36
+ end
37
+
38
+ #*******************************************************************************
39
+ # Coral Core Library
40
+ #
41
+ # This provides core data elements and utilities used in the Coral gems.
42
+ #
43
+ # Author:: Adrian Webb (mailto:adrian.webb@coraltech.net)
44
+ # License:: GPLv3
45
+ module Coral
46
+
47
+ VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
48
+
49
+ end