hmx_client 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|