hmx_client 0.0.5 → 0.0.6
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/bin/hmx +15 -23
- data/lib/hmx/client.rb +106 -17
- data/lib/hmx/command/base.rb +194 -0
- data/lib/hmx/command/bootstrap.rb +18 -0
- data/lib/hmx/command/clone.rb +77 -0
- data/lib/hmx/command/config.rb +67 -0
- data/lib/hmx/command/dump.rb +67 -0
- data/lib/hmx/command/fn.rb +43 -0
- data/lib/hmx/command/fountain.rb +46 -0
- data/lib/hmx/command/get.rb +20 -0
- data/lib/hmx/command/getContent.rb +20 -0
- data/lib/hmx/command/help.rb +114 -0
- data/lib/hmx/command/query.rb +22 -0
- data/lib/hmx/command/session.rb +35 -0
- data/lib/hmx/command/task.rb +32 -0
- data/lib/hmx/command/type.rb +45 -0
- data/lib/hmx/command/user.rb +68 -0
- data/lib/hmx/command/view.rb +155 -0
- data/lib/hmx/command.rb +140 -0
- data/lib/hmx/helpers.rb +61 -0
- data/lib/hmx/hmx.rb +125 -16
- data/lib/hmx/version.rb +1 -1
- data/lib/hmx_client.rb +1 -1
- metadata +24 -6
data/bin/hmx
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
begin
|
3
|
+
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /mingw32/
|
4
|
+
rescue Exception => e
|
5
|
+
puts e.message
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'cli-colorize'
|
2
9
|
|
3
10
|
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
11
|
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
@@ -10,32 +17,17 @@ require 'hmx_client'
|
|
10
17
|
include HmxClient
|
11
18
|
|
12
19
|
$stdout.sync = true
|
20
|
+
$folder = nil
|
21
|
+
$file = nil
|
22
|
+
$outFile = nil
|
13
23
|
$debug = false
|
14
24
|
|
15
|
-
options = {
|
16
|
-
:api => 'http://localhost:9999',
|
17
|
-
:user => 'amkimian',
|
18
|
-
:password => 'password'
|
19
|
-
}
|
20
|
-
|
21
|
-
ARGV.options do |o|
|
22
|
-
o.on("-a apiUrl", "--api") { |api| options[:api] = api }
|
23
|
-
o.on("-u user", "--user") { |user| options[:user] = user }
|
24
|
-
o.on("-d", "--debug") { $debug = true }
|
25
|
-
o.parse!
|
26
|
-
end
|
27
|
-
|
28
25
|
begin
|
29
26
|
args = ARGV.dup
|
30
27
|
ARGV.clear
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
28
|
+
command = args.shift.strip rescue 'help'
|
29
|
+
HmxClient::Command.load
|
30
|
+
HmxClient::Command.run(command, args)
|
31
|
+
rescue HmxException => info
|
32
|
+
abort "General HMX Exception - #{info.msg['message']}"
|
35
33
|
end
|
36
|
-
|
37
|
-
__END__
|
38
|
-
Usage: hmx [OPTIONS] command
|
39
|
-
|
40
|
-
hmx test alan
|
41
|
-
|
data/lib/hmx/client.rb
CHANGED
@@ -4,9 +4,8 @@ module HmxClient
|
|
4
4
|
class Client
|
5
5
|
FILE = File.expand_path("~/.hmxConfig")
|
6
6
|
|
7
|
-
def initialize(args
|
7
|
+
def initialize(args)
|
8
8
|
@args = args
|
9
|
-
@options = options
|
10
9
|
loadConfig!
|
11
10
|
end
|
12
11
|
|
@@ -14,13 +13,17 @@ module HmxClient
|
|
14
13
|
|
15
14
|
def loadConfig!
|
16
15
|
# Load the config from the save file
|
17
|
-
@config =
|
18
|
-
|
16
|
+
@config = if File.exist?(FILE)
|
17
|
+
File.open(FILE) { |file| Marshal.load(file) }
|
18
|
+
else
|
19
|
+
{}
|
20
|
+
end
|
21
|
+
RestClient.proxy = @config[:proxy] if @config.has_key?(:proxy)
|
19
22
|
end
|
20
23
|
def storeConfig(keyName, keyValue)
|
21
24
|
# Update the config hashMap and persist it
|
22
25
|
@config[keyName] = keyValue
|
23
|
-
File.open(FILE, 'w+') { |f|
|
26
|
+
File.open(FILE, 'w+') { |f| Marshal.dump(@config, f) }
|
24
27
|
end
|
25
28
|
def run!
|
26
29
|
command = @args.shift || @options[:command]
|
@@ -46,33 +49,119 @@ module HmxClient
|
|
46
49
|
storeConfig(:api, @args.shift)
|
47
50
|
when "partition"
|
48
51
|
storeConfig(:partition, @args.shift)
|
52
|
+
when "proxy"
|
53
|
+
proxy = @args.shift
|
54
|
+
storeConfig(:proxy, proxy)
|
55
|
+
RestClient.proxy = proxy
|
49
56
|
else
|
50
57
|
abort "Unknown config command"
|
51
58
|
end
|
52
59
|
end
|
60
|
+
def genout(content)
|
61
|
+
puts content
|
62
|
+
File.open($outFile, 'w') { | f | puts "And writing to #{$outFile} "
|
63
|
+
f.write(content) } unless $outFile.nil?
|
64
|
+
end
|
53
65
|
def get
|
54
66
|
h = getapi
|
55
|
-
|
67
|
+
genout JSON.pretty_generate(h.getData(@args))
|
56
68
|
end
|
57
69
|
def getData
|
58
70
|
h = getapi
|
59
|
-
|
71
|
+
genout h.getContent(@args)
|
60
72
|
end
|
61
73
|
def putSimpleData
|
62
74
|
h = getapi
|
63
|
-
|
75
|
+
genout JSON.pretty_generate(h.putSimpleData(@args))
|
76
|
+
end
|
77
|
+
def put
|
78
|
+
h = getapi
|
79
|
+
genout JSON.pretty_generate(h.putData(@args))
|
64
80
|
end
|
65
81
|
def query
|
66
82
|
h = getapi
|
67
|
-
|
68
|
-
end
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
83
|
+
genout h.query(@args.shift, nil)
|
84
|
+
end
|
85
|
+
def view
|
86
|
+
h = getapi
|
87
|
+
viewData = h.runView(@args.shift, JSON.parse(@args.shift))
|
88
|
+
resp = ''
|
89
|
+
viewData.each { | line |
|
90
|
+
line.each { | cell | resp = resp + "%20.20s\t" % cell }
|
91
|
+
resp = resp + "\n"
|
92
|
+
}
|
93
|
+
genout resp
|
94
|
+
end
|
95
|
+
# Take all of the documents for a type and put it into the folder passed, one per file
|
96
|
+
def dumpType
|
97
|
+
h = getapi
|
98
|
+
displayNames = h.query(@args.shift, nil)
|
99
|
+
puts displayNames
|
100
|
+
displayNames.each { | displayName |
|
101
|
+
fileName = $folder + "/" + displayName
|
102
|
+
puts "FileName will be #{ fileName } "
|
103
|
+
Dir.mkdir(File.dirname(fileName)) if !Dir.exist?(File.dirname(fileName))
|
104
|
+
puts "DisplayName is #{ displayName } "
|
105
|
+
File.open(fileName, 'w') { |f| f.write(h.getData([displayName])) } }
|
106
|
+
end
|
107
|
+
# Take all of the documents in a folder for a type (the opposite of dumpType above)
|
108
|
+
# and simply put them back in
|
109
|
+
def loadType
|
110
|
+
h = getapi
|
111
|
+
typeName = @args.shift
|
112
|
+
folderName = $folder + "/" + typeName
|
113
|
+
Dir.foreach(folderName) { | f |
|
114
|
+
puts "Working with #{ f }"
|
115
|
+
fullFile = folderName + "/" + f
|
116
|
+
if (File.file?(fullFile))
|
117
|
+
content = File.open(fullFile) { | h |
|
118
|
+
c = '';
|
119
|
+
while(line = h.gets)
|
120
|
+
c = c + line
|
121
|
+
end
|
122
|
+
c
|
123
|
+
}
|
124
|
+
puts "Content is #{ content } "
|
125
|
+
h.putData(JSON.parse(content))
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
def deleteData
|
130
|
+
h = getapi
|
131
|
+
h.deleteData(@args.shift)
|
132
|
+
end
|
133
|
+
def getTypes
|
134
|
+
h = getapi
|
135
|
+
genout JSON.pretty_generate(h.getTypes)
|
136
|
+
end
|
137
|
+
def getType
|
138
|
+
h = getapi
|
139
|
+
genout JSON.pretty_generate(h.getType(@args.shift))
|
140
|
+
end
|
141
|
+
def getFn
|
142
|
+
h = getapi
|
143
|
+
genout h.getFn(@args)
|
144
|
+
end
|
145
|
+
def putFn
|
146
|
+
h = getapi
|
147
|
+
genout h.putFn(@args)
|
148
|
+
end
|
149
|
+
# Add a user, given a name (more can be added through a low level api)
|
150
|
+
def user
|
151
|
+
h = getapi
|
152
|
+
case command = @args.shift
|
153
|
+
when "add"
|
154
|
+
username = @args.shift
|
155
|
+
password = Digest::MD5::hexdigest(@args.shift)
|
156
|
+
|
157
|
+
user = { "MXUser" => { "hashPassword" => password , "apiKey" => false, "userName" => username, "fullName" => username }}
|
158
|
+
genout JSON.pretty_generate(h.putSimpleData([ "sys.user/#{ username}", JSON.generate(user)]))
|
159
|
+
when "delete"
|
160
|
+
username = @args.shift
|
161
|
+
h.deleteData("sys.user/#{username}")
|
162
|
+
when "list"
|
163
|
+
puts h.query("sys.user", nil)
|
164
|
+
end
|
76
165
|
end
|
77
166
|
end
|
78
167
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "hmx/command"
|
3
|
+
require 'cli-colorize'
|
4
|
+
require 'hmx/helpers'
|
5
|
+
|
6
|
+
class HmxClient::Command::Base
|
7
|
+
include HmxClient::Helpers
|
8
|
+
include CLIColorize
|
9
|
+
|
10
|
+
def self.namespace
|
11
|
+
self.to_s.split("::").last.downcase
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :args
|
15
|
+
attr_reader :options
|
16
|
+
|
17
|
+
FILE = File.expand_path("~/.hmxConfig")
|
18
|
+
|
19
|
+
def initialize(args=[], options={})
|
20
|
+
@args = args
|
21
|
+
@options = options
|
22
|
+
loadConfig!
|
23
|
+
end
|
24
|
+
|
25
|
+
def loadConfig!
|
26
|
+
# Load the config from the save file
|
27
|
+
@config = if File.exist?(FILE)
|
28
|
+
File.open(FILE) { |file| Marshal.load(file) }
|
29
|
+
else
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
RestClient.proxy = @config[:proxy] if @config.has_key?(:proxy)
|
33
|
+
end
|
34
|
+
def storeConfig(keyName, keyValue)
|
35
|
+
# Update the config hashMap and persist it
|
36
|
+
if (keyName == :password)
|
37
|
+
keyValue = Digest::MD5.hexdigest(keyValue)
|
38
|
+
end
|
39
|
+
@config[keyName] = keyValue
|
40
|
+
writeConfig
|
41
|
+
end
|
42
|
+
def removeConfig(keyName)
|
43
|
+
@config.delete keyName
|
44
|
+
writeConfig
|
45
|
+
end
|
46
|
+
def writeConfig
|
47
|
+
File.open(FILE, 'w+') { |f| Marshal.dump(@config, f) }
|
48
|
+
end
|
49
|
+
def hmx
|
50
|
+
if @hmx.nil?
|
51
|
+
@hmx = Hmx.new
|
52
|
+
@hmx.login(@config)
|
53
|
+
writeConfig
|
54
|
+
end
|
55
|
+
@hmx
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def self.inherited(klass)
|
61
|
+
help = extract_help_from_caller(caller.first)
|
62
|
+
HmxClient::Command.register_namespace(
|
63
|
+
:name => klass.namespace,
|
64
|
+
:description => help.split("\n").first
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.method_added(method)
|
69
|
+
return if self == HmxClient::Command::Base
|
70
|
+
return if private_method_defined?(method)
|
71
|
+
return if protected_method_defined?(method)
|
72
|
+
|
73
|
+
help = extract_help_from_caller(caller.first)
|
74
|
+
resolved_method = (method.to_s == "index") ? nil : method.to_s
|
75
|
+
default_command = [ self.namespace, resolved_method ].compact.join(":")
|
76
|
+
command = extract_command(help) || default_command
|
77
|
+
banner = extract_banner(help) || command
|
78
|
+
permute = !banner.index("*")
|
79
|
+
banner.gsub!("*", "")
|
80
|
+
|
81
|
+
HmxClient::Command.register_command(
|
82
|
+
:klass => self,
|
83
|
+
:method => method,
|
84
|
+
:namespace => self.namespace,
|
85
|
+
:command => command,
|
86
|
+
:banner => banner,
|
87
|
+
:help => help,
|
88
|
+
:summary => extract_summary(help),
|
89
|
+
:description => extract_description(help),
|
90
|
+
:options => extract_options(help),
|
91
|
+
:permute => permute
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.alias_command(new, old)
|
96
|
+
raise "no such command: #{old}" unless HmxClient::Command.commands[old]
|
97
|
+
HmxClient::Command.command_aliases[new] = old
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Parse the caller format and identify the file and line number as identified
|
102
|
+
# in : http://www.ruby-doc.org/core/classes/Kernel.html#M001397. This will
|
103
|
+
# look for a colon followed by a digit as the delimiter. The biggest
|
104
|
+
# complication is windows paths, which have a color after the drive letter.
|
105
|
+
# This regex will match paths as anything from the beginning to a colon
|
106
|
+
# directly followed by a number (the line number).
|
107
|
+
#
|
108
|
+
# Examples of the caller format :
|
109
|
+
# * c:/Ruby192/lib/.../lib/heroku/command/addons.rb:8:in `<module:Command>'
|
110
|
+
# * c:/Ruby192/lib/.../heroku-2.0.1/lib/heroku/command/pg.rb:96:in `<class:Pg>'
|
111
|
+
# * /Users/ph7/...../xray-1.1/lib/xray/thread_dump_signal_handler.rb:9
|
112
|
+
#
|
113
|
+
def self.extract_help_from_caller(line)
|
114
|
+
# pull out of the caller the information for the file path and line number
|
115
|
+
if line =~ /^(.+?):(\d+)/
|
116
|
+
return extract_help($1, $2)
|
117
|
+
end
|
118
|
+
raise "unable to extract help from caller: #{line}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.extract_help(file, line)
|
122
|
+
buffer = []
|
123
|
+
lines = File.read(file).split("\n")
|
124
|
+
|
125
|
+
catch(:done) do
|
126
|
+
(line.to_i-2).downto(0) do |i|
|
127
|
+
case lines[i].strip[0..0]
|
128
|
+
when "", "#" then buffer << lines[i]
|
129
|
+
else throw(:done)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
buffer.map! do |line|
|
135
|
+
line.strip.gsub(/^#/, "")
|
136
|
+
end
|
137
|
+
|
138
|
+
buffer.reverse.join("\n").strip
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.extract_command(help)
|
142
|
+
extract_banner(help).to_s.split(" ").first
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.extract_banner(help)
|
146
|
+
help.split("\n").first
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.extract_summary(help)
|
150
|
+
extract_description(help).split("\n").first
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.extract_description(help)
|
154
|
+
lines = help.split("\n").map { |l| l.strip }
|
155
|
+
lines.shift
|
156
|
+
lines.reject do |line|
|
157
|
+
line =~ /^-(.+)#(.+)/
|
158
|
+
end.join("\n").strip
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.extract_options(help)
|
162
|
+
help.split("\n").map { |l| l.strip }.select do |line|
|
163
|
+
line =~ /^-(.+)#(.+)/
|
164
|
+
end.inject({}) do |hash, line|
|
165
|
+
description = line.split("#", 2).last.strip
|
166
|
+
long = line.match(/--([A-Za-z\- ]+)/)[1].strip
|
167
|
+
short = line.match(/-([A-Za-z ])/)[1].strip
|
168
|
+
hash.update(long.split(" ").first => { :desc => description, :short => short, :long => long })
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def extract_option(name, default=true)
|
173
|
+
key = name.gsub("--", "").to_sym
|
174
|
+
return unless options[key]
|
175
|
+
value = options[key] || default
|
176
|
+
block_given? ? yield(value) : value
|
177
|
+
end
|
178
|
+
|
179
|
+
def confirm_mismatch?
|
180
|
+
options[:confirm] && (options[:confirm] != options[:app])
|
181
|
+
end
|
182
|
+
|
183
|
+
def dout(msg)
|
184
|
+
if (!HmxClient::Command.fileOut.nil?)
|
185
|
+
realFile = File.expand_path(HmxClient::Command.fileOut)
|
186
|
+
File.open(realFile, 'w') { | f |
|
187
|
+
display("Writing to #{ realFile }")
|
188
|
+
f.write(msg) }
|
189
|
+
end
|
190
|
+
puts colorize(msg, :yellow)
|
191
|
+
#display(green(msg))
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "hmx/command/base"
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module HmxClient::Command
|
5
|
+
|
6
|
+
# Bootstrap a default configuration
|
7
|
+
#
|
8
|
+
class Bootstrap < Base
|
9
|
+
|
10
|
+
# bootstrap
|
11
|
+
#
|
12
|
+
# Bootstrap a default configuration into this partition
|
13
|
+
def index
|
14
|
+
hmx.bootstrap
|
15
|
+
puts "Done."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "hmx/command/base"
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module HmxClient::Command
|
5
|
+
|
6
|
+
# Clone a partition or setup a partition from a clone
|
7
|
+
#
|
8
|
+
class Clone < Base
|
9
|
+
|
10
|
+
# clone
|
11
|
+
#
|
12
|
+
# Create a clone file for the current partition
|
13
|
+
def index
|
14
|
+
# Clone the type information
|
15
|
+
# Clone these built in types (i.e. the content)
|
16
|
+
# Clone other types as defined by the command line
|
17
|
+
extraTypes = args
|
18
|
+
types = [ 'sys.user', 'sys.config', 'sys.ent', 'sys.egroup', 'sys.trigger', 'sys.view' ]
|
19
|
+
extraTypes.each { | et | types << et }
|
20
|
+
types.each { | t | dumpTypeAndData(t) }
|
21
|
+
end
|
22
|
+
|
23
|
+
# clone:load
|
24
|
+
#
|
25
|
+
# Load a file that was created using hmx clone
|
26
|
+
# The file basically contains a series of types (documents separated by << >>)
|
27
|
+
# and data (separated by [[ ]])
|
28
|
+
def load
|
29
|
+
# We define the file as being the input file on the command line (--file-in)
|
30
|
+
if (HmxClient::Command.fileIn.nil?)
|
31
|
+
raise CommandFailed, "Usage: hmx clone:load --file-in=<filename>"
|
32
|
+
end
|
33
|
+
realFile = File.expand_path(HmxClient::Command.fileIn)
|
34
|
+
File.open(realFile, 'r') { | f |
|
35
|
+
currentDoc = ''
|
36
|
+
isType = false
|
37
|
+
while(line = f.gets)
|
38
|
+
if (line[0] == '#')
|
39
|
+
elsif (line[0] == '<' && line[1] == '<')
|
40
|
+
currentDoc = ''
|
41
|
+
isType = true
|
42
|
+
elsif (line[0] == '>' && line[1] == '>')
|
43
|
+
if isType
|
44
|
+
print '.'
|
45
|
+
hmx.updateType(JSON.parse(currentDoc))
|
46
|
+
end
|
47
|
+
currentDoc = ''
|
48
|
+
elsif (line[0] == '[' && line[1] == '[')
|
49
|
+
currentDoc = ''
|
50
|
+
isType = false
|
51
|
+
elsif (line[0] == ']' && line[1] == ']')
|
52
|
+
if (!isType)
|
53
|
+
print 'x'
|
54
|
+
hmx.putData([currentDoc])
|
55
|
+
end
|
56
|
+
currentDoc = ''
|
57
|
+
else
|
58
|
+
currentDoc = currentDoc + line
|
59
|
+
end
|
60
|
+
end
|
61
|
+
}
|
62
|
+
puts ""
|
63
|
+
puts "Done"
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
def dumpTypeAndData(typeName)
|
68
|
+
puts "####### #{ typeName } "
|
69
|
+
puts "<<"
|
70
|
+
puts JSON.generate(hmx.getType(typeName))
|
71
|
+
puts ">>"
|
72
|
+
puts "####### Data for #{ typeName } "
|
73
|
+
displayNames = hmx.query(typeName, nil)
|
74
|
+
displayNames.each { | d | puts("[["); puts JSON.generate(hmx.getData([d])); puts("]]") }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "hmx/command/base"
|
2
|
+
|
3
|
+
module HmxClient::Command
|
4
|
+
|
5
|
+
# Manage app config vars
|
6
|
+
#
|
7
|
+
class Config < Base
|
8
|
+
|
9
|
+
# config
|
10
|
+
#
|
11
|
+
# display the config vars for an app
|
12
|
+
#
|
13
|
+
# -s, --shell # output config vars in shell format
|
14
|
+
#
|
15
|
+
def index
|
16
|
+
display_vars(@config, :long => true, :shell => false)
|
17
|
+
end
|
18
|
+
|
19
|
+
# config:add KEY1=VALUE1 ...
|
20
|
+
#
|
21
|
+
# add one or more config vars
|
22
|
+
#
|
23
|
+
def add
|
24
|
+
unless args.size > 0 and args.all? { |a| a.include?('=') }
|
25
|
+
raise CommandFailed, "Usage: hmx config:add <key>=<value> [<key2>=<value2> ...]"
|
26
|
+
end
|
27
|
+
|
28
|
+
args.inject({}) do |vars, arg|
|
29
|
+
key, value = arg.split('=', 2)
|
30
|
+
storeConfig(key.to_sym,value)
|
31
|
+
end
|
32
|
+
|
33
|
+
display_vars(@config, :indent => 2)
|
34
|
+
end
|
35
|
+
|
36
|
+
# config:remove KEY1 [KEY2 ...]
|
37
|
+
#
|
38
|
+
# remove a config var
|
39
|
+
#
|
40
|
+
def remove
|
41
|
+
raise CommandFailed, "Usage: hmx config:remove KEY1 [KEY2 ...]" if args.empty?
|
42
|
+
|
43
|
+
args.each do |key|
|
44
|
+
removeConfig(key.to_sym)
|
45
|
+
display_vars(@config, :indent => 2)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
def display_vars(vars, options={})
|
51
|
+
max_length = vars.map { |v| v[0].to_s.size }.max
|
52
|
+
vars.keys.sort.each do |key|
|
53
|
+
if options[:shell]
|
54
|
+
display "#{key}=#{vars[key]}"
|
55
|
+
else
|
56
|
+
spaces = ' ' * (max_length - key.to_s.size)
|
57
|
+
display "#{' ' * (options[:indent] || 0)}#{key}#{spaces} => #{format(vars[key], options)}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def format(value, options)
|
63
|
+
return value if options[:long] || value.to_s.size < 36
|
64
|
+
value[0, 16] + '...' + value[-16, 16]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "hmx/command/base"
|
2
|
+
|
3
|
+
module HmxClient::Command
|
4
|
+
|
5
|
+
# Dump data from a type in hmx and load it back again
|
6
|
+
#
|
7
|
+
class Dump < Base
|
8
|
+
|
9
|
+
# dump
|
10
|
+
#
|
11
|
+
# Dump data from hmx into the local filesystem. Used
|
12
|
+
# as a preface to a backup, or a change then restore
|
13
|
+
#
|
14
|
+
# <typeName> <folderPath>
|
15
|
+
def index
|
16
|
+
unless args.size > 0
|
17
|
+
raise CommandFailed, "Usage: hmx dump <typeName> <folderPath>"
|
18
|
+
end
|
19
|
+
# The filenames will come from the name of the type and their displayName, appended onto
|
20
|
+
# the folder path given. We will also attempt to create the folder path and the type
|
21
|
+
# sub folder
|
22
|
+
typeName = args.shift
|
23
|
+
rootFolder = args.shift
|
24
|
+
|
25
|
+
Dir.mkdir(rootFolder) if !Dir.exist?(rootFolder)
|
26
|
+
Dir.mkdir(rootFolder + "/" + typeName) if !Dir.exist?(rootFolder + "/" + typeName)
|
27
|
+
displayNames = hmx.query(typeName, nil)
|
28
|
+
displayNames.each { | displayName |
|
29
|
+
fileName = rootFolder + "/" + displayName
|
30
|
+
display "Writing to #{ fileName }"
|
31
|
+
File.open(fileName, 'w') { | f | f.write(JSON.pretty_generate(hmx.getData([displayName]))) }
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# dump:load
|
36
|
+
#
|
37
|
+
# Load data that has previously been dumped using the main dump command
|
38
|
+
#
|
39
|
+
# <typeName> <folderPath>
|
40
|
+
#
|
41
|
+
# The real path for the files is in the folder formed by concatenating the typename to the rootFolder
|
42
|
+
def load
|
43
|
+
unless args.size > 0
|
44
|
+
raise CommandFailed, "Usage: hmx dump:load <typeName> <folderPath>"
|
45
|
+
end
|
46
|
+
typeName = args.shift
|
47
|
+
rootFolder = args.shift
|
48
|
+
|
49
|
+
folderName = rootFolder + "/" + typeName
|
50
|
+
Dir.foreach(folderName) { | f |
|
51
|
+
display "Loading #{ f } "
|
52
|
+
fullFile = folderName + "/" + f
|
53
|
+
if (File.file?(fullFile))
|
54
|
+
content = File.open(fullFile) { | h |
|
55
|
+
c = '';
|
56
|
+
while(line = h.gets)
|
57
|
+
c = c + line
|
58
|
+
end
|
59
|
+
c
|
60
|
+
}
|
61
|
+
puts "Content is #{ content } "
|
62
|
+
hmx.putData([content])
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "hmx/command/base"
|
2
|
+
|
3
|
+
module HmxClient::Command
|
4
|
+
|
5
|
+
# Load and Save functions in hmx
|
6
|
+
#
|
7
|
+
class Fn < Base
|
8
|
+
|
9
|
+
# fn
|
10
|
+
#
|
11
|
+
# Manipulate HMX functions
|
12
|
+
#
|
13
|
+
#
|
14
|
+
def index
|
15
|
+
unless args.size > 0
|
16
|
+
raise CommandFailed, "Usage: hmx fn <fnName>"
|
17
|
+
end
|
18
|
+
dout hmx.getFn([args.shift])
|
19
|
+
end
|
20
|
+
|
21
|
+
# fn:list
|
22
|
+
#
|
23
|
+
# List all functions in HMX
|
24
|
+
#
|
25
|
+
def list
|
26
|
+
fns = hmx.query("fn", nil)
|
27
|
+
fns.each { | f |
|
28
|
+
display f.rpartition('/')[2]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# fn:put
|
33
|
+
#
|
34
|
+
# Create or update a function
|
35
|
+
#
|
36
|
+
def put
|
37
|
+
unless args.size > 0
|
38
|
+
raise CommandFailed, "Usage: hmx fn:put <fnName> <f:function>"
|
39
|
+
end
|
40
|
+
dout hmx.putFn(args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|