haplo 2.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.txt +17 -0
- data/bin/haplo-plugin +3 -0
- data/haplo.gemspec +18 -0
- data/lib/CertificateBundle.pem +3952 -0
- data/lib/auth.rb +168 -0
- data/lib/check.rb +60 -0
- data/lib/custom.rb +73 -0
- data/lib/haplo-templates.jar +0 -0
- data/lib/hmac.rb +12 -0
- data/lib/js.jar +0 -0
- data/lib/js_min.js +38 -0
- data/lib/js_syntax_test.js +88 -0
- data/lib/jshint.js +4359 -0
- data/lib/local_config.rb +28 -0
- data/lib/manifest.rb +44 -0
- data/lib/minimise.rb +68 -0
- data/lib/misc.rb +8 -0
- data/lib/new_plugin.rb +88 -0
- data/lib/notifications.rb +89 -0
- data/lib/packing.rb +62 -0
- data/lib/plugin.rb +227 -0
- data/lib/plugin_tool.rb +197 -0
- data/lib/run.rb +67 -0
- data/lib/schema_requirements.rb +63 -0
- data/lib/server.rb +143 -0
- data/lib/syntax_checking.rb +120 -0
- data/lib/uglifyjs/parse-js.js +1342 -0
- data/lib/uglifyjs/process.js +2011 -0
- data/lib/uglifyjs/squeeze-more.js +69 -0
- data/lib/usage.txt +81 -0
- data/lib/version.txt +1 -0
- data/lib/watchers.rb +39 -0
- metadata +76 -0
data/lib/local_config.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
module LocalConfig
|
5
|
+
|
6
|
+
LOCAL_CONFIG_FILENAME = "server.config.json"
|
7
|
+
|
8
|
+
def self.load
|
9
|
+
if File.exist? LOCAL_CONFIG_FILENAME
|
10
|
+
@@local_config = JSON.parse(File.open(LOCAL_CONFIG_FILENAME) { |f| f.read })
|
11
|
+
else
|
12
|
+
@@local_config = {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_list(list_name)
|
17
|
+
lookup = @@local_config[list_name]
|
18
|
+
return [] unless lookup
|
19
|
+
list = []
|
20
|
+
server_name = PluginTool.get_server_hostname
|
21
|
+
list.concat(lookup['*']) if lookup.has_key?('*')
|
22
|
+
list.concat(lookup[server_name]) if server_name && lookup.has_key?(server_name)
|
23
|
+
list
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/manifest.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
# NOTE: Also update packing.rb if this changes
|
5
|
+
ALLOWED_PLUGIN_DIRS = ['js', 'static', 'template', 'test', 'data']
|
6
|
+
|
7
|
+
def self.generate_manifest(directory)
|
8
|
+
manifest = Hash.new
|
9
|
+
Dir.glob("#{directory}/**/*").sort.each do |pathname|
|
10
|
+
# Ignore directories
|
11
|
+
next unless File.file? pathname
|
12
|
+
# Ignore Emacs backup files
|
13
|
+
next if pathname =~ /\~\z/
|
14
|
+
# Check file
|
15
|
+
filename = pathname.slice(directory.length + 1, pathname.length)
|
16
|
+
raise "Bad filename for #{filename}" unless filename =~ /\A([a-zA-Z0-9_\/\-]+\/)?([a-z0-9_-]+\.[a-z0-9]+)\z/
|
17
|
+
dir = $1
|
18
|
+
name = $2
|
19
|
+
if dir != nil
|
20
|
+
dir = dir.gsub(/\/\z/,'')
|
21
|
+
raise "Bad directory #{dir}" unless dir =~ /\A([a-zA-Z0-9_\-]+)[a-zA-Z0-9_\/\-]*\z/
|
22
|
+
raise "Bad root directory #{$1}" unless ALLOWED_PLUGIN_DIRS.include?($1)
|
23
|
+
end
|
24
|
+
# Get hash of file
|
25
|
+
digest = File.open(pathname) { |f| Digest::SHA256.hexdigest(f.read) }
|
26
|
+
# And add to manifest
|
27
|
+
manifest[filename] = digest
|
28
|
+
end
|
29
|
+
manifest
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.determine_manifest_changes(from, to)
|
33
|
+
changes = []
|
34
|
+
from.each_key do |name|
|
35
|
+
changes << [name, :delete] unless to.has_key?(name)
|
36
|
+
end
|
37
|
+
to.each do |name,hash|
|
38
|
+
changes << [name, hash] unless from[name] == hash
|
39
|
+
end
|
40
|
+
changes
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
data/lib/minimise.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
class Minimiser
|
5
|
+
Context = Java::OrgMozillaJavascript::Context
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
# Load UglifyJS into a JavaScript interpreter
|
9
|
+
raise "Another JS Context is active" unless nil == Context.getCurrentContext()
|
10
|
+
@cx = Context.enter();
|
11
|
+
@cx.setLanguageVersion(Context::VERSION_1_7)
|
12
|
+
@javascript_scope = @cx.initStandardObjects()
|
13
|
+
['js_min.js','uglifyjs/parse-js.js','uglifyjs/process.js','uglifyjs/squeeze-more.js'].each do |filename|
|
14
|
+
js = File.open("#{File.dirname(__FILE__)}/#{filename}") { |f| f.read }
|
15
|
+
@cx.evaluateString(@javascript_scope, js, "<#{filename}>", 1, nil);
|
16
|
+
end
|
17
|
+
@js_min = @javascript_scope.get("js_min", @javascript_scope);
|
18
|
+
end
|
19
|
+
|
20
|
+
def process(data, filename)
|
21
|
+
if filename =~ /\.js\z/
|
22
|
+
# JavaScript - use UglifyJS loaded into the JavaScript interpreter
|
23
|
+
@js_min.call(@cx, @javascript_scope, @javascript_scope, [data])
|
24
|
+
|
25
|
+
elsif filename =~ /\.html\z/
|
26
|
+
# Simple processing of HTML
|
27
|
+
# Remove HTML comments
|
28
|
+
html = data.gsub(/\<\!\-\-.+?\-\-\>/m,'')
|
29
|
+
# Remove indents
|
30
|
+
html.gsub!(/^\s+/,'')
|
31
|
+
# Remove any unnecessary line breaks (fairly conservative)
|
32
|
+
html.gsub!(/\>[\r\n]+\</m,'><')
|
33
|
+
html.gsub!(/([\>}])[\r\n]+([\<{])/m,'\1\2')
|
34
|
+
html
|
35
|
+
|
36
|
+
elsif filename =~ /\.css\z/
|
37
|
+
# Simple processing of CSS
|
38
|
+
css = data.gsub(/(^|\s)\/\*.+?\*\/($|\s)/m,'') # remove C style comments
|
39
|
+
out = []
|
40
|
+
css.split(/[\r\n]+/).each do |line|
|
41
|
+
line.chomp!; line.gsub!(/^\s+/,''); line.gsub!(/\s+$/,'')
|
42
|
+
line.gsub!(/\s+/,' ') # contract spaces
|
43
|
+
line.gsub!(/\s*:\s*/,':') # remove unnecessary spaces
|
44
|
+
if line =~ /\S/
|
45
|
+
out << line
|
46
|
+
end
|
47
|
+
end
|
48
|
+
css = out.join("\n")
|
49
|
+
# Remove unnecessary line endings
|
50
|
+
css.gsub!(/[\r\n]*(\{[^\}]+\})/m) do |m|
|
51
|
+
$1.gsub(/[\r\n]/m,'')
|
52
|
+
end
|
53
|
+
css
|
54
|
+
|
55
|
+
else
|
56
|
+
# No processing
|
57
|
+
data
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def finish
|
62
|
+
Context.exit()
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
data/lib/misc.rb
ADDED
data/lib/new_plugin.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
def self.make_new_plugin(plugin_name)
|
5
|
+
unless plugin_name =~ /\A[a-z0-9_]+\z/ && plugin_name.length > 8
|
6
|
+
end_on_error "Bad plugin name - must use a-z0-9_ only, and more than 8 characters."
|
7
|
+
end
|
8
|
+
if File.exist?(plugin_name)
|
9
|
+
end_on_error "File or directory #{plugin_name} already exists"
|
10
|
+
end
|
11
|
+
FileUtils.mkdir(plugin_name)
|
12
|
+
['js', 'static', 'template', 'test'].each do |dir|
|
13
|
+
FileUtils.mkdir("#{plugin_name}/#{dir}")
|
14
|
+
end
|
15
|
+
random = java.security.SecureRandom.new()
|
16
|
+
rbytes = Java::byte[20].new
|
17
|
+
random.nextBytes(rbytes)
|
18
|
+
install_secret = String.from_java_bytes(rbytes).unpack('H*').join
|
19
|
+
plugin_url_fragment = plugin_name.gsub('_','-')
|
20
|
+
File.open("#{plugin_name}/plugin.json",'w') do |file|
|
21
|
+
file.write(<<__E)
|
22
|
+
{
|
23
|
+
"pluginName": "#{plugin_name}",
|
24
|
+
"pluginAuthor": "TODO Your Company",
|
25
|
+
"pluginVersion": 1,
|
26
|
+
"displayName": "#{plugin_name.split('_').map {|e| e.capitalize} .join(' ')}",
|
27
|
+
"displayDescription": "TODO Longer description of plugin",
|
28
|
+
"installSecret": "#{install_secret}",
|
29
|
+
"apiVersion": 4,
|
30
|
+
"load": [
|
31
|
+
"js/#{plugin_name}.js"
|
32
|
+
],
|
33
|
+
"respond": ["/do/#{plugin_url_fragment}"]
|
34
|
+
}
|
35
|
+
__E
|
36
|
+
end
|
37
|
+
File.open("#{plugin_name}/js/#{plugin_name}.js",'w') do |file|
|
38
|
+
file.write(<<__E)
|
39
|
+
|
40
|
+
P.respond("GET", "/do/#{plugin_url_fragment}/example", [
|
41
|
+
], function(E) {
|
42
|
+
E.render({
|
43
|
+
pageTitle: "Example page"
|
44
|
+
});
|
45
|
+
});
|
46
|
+
|
47
|
+
__E
|
48
|
+
end
|
49
|
+
File.open("#{plugin_name}/template/example.html",'w') do |file|
|
50
|
+
file.write(<<__E)
|
51
|
+
<p>This is an example template.</p>
|
52
|
+
__E
|
53
|
+
end
|
54
|
+
File.open("#{plugin_name}/test/#{plugin_name}_test1.js",'w') do |file|
|
55
|
+
file.write(<<__E)
|
56
|
+
|
57
|
+
t.test(function() {
|
58
|
+
|
59
|
+
// For documentation, see
|
60
|
+
// http://docs.haplo.org/dev/plugin/tests
|
61
|
+
|
62
|
+
t.assert(true);
|
63
|
+
|
64
|
+
});
|
65
|
+
|
66
|
+
__E
|
67
|
+
end
|
68
|
+
File.open("#{plugin_name}/requirements.schema",'w') do |file|
|
69
|
+
file.write("\n\n\n")
|
70
|
+
end
|
71
|
+
puts <<__E
|
72
|
+
|
73
|
+
Plugin #{plugin_name} has been created. Run
|
74
|
+
|
75
|
+
haplo-plugin -p #{plugin_name}
|
76
|
+
|
77
|
+
to upload it to the server, then visit
|
78
|
+
|
79
|
+
https://<HOSTNAME>/do/#{plugin_url_fragment}/example
|
80
|
+
|
81
|
+
to see a sample page.
|
82
|
+
|
83
|
+
See http://docs.haplo.org/dev/plugin for more information.
|
84
|
+
|
85
|
+
__E
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
@@notification_options = nil
|
5
|
+
@@notification_have_suppressed_first_system_audit_entry = false
|
6
|
+
@@notification_announce_reconnect = false
|
7
|
+
|
8
|
+
def self.start_notifications(options)
|
9
|
+
@@notification_options = options
|
10
|
+
@@notification_queue_name = nil
|
11
|
+
Thread.new do
|
12
|
+
while true
|
13
|
+
begin
|
14
|
+
self.do_notifications
|
15
|
+
rescue => e
|
16
|
+
puts "NOTICE: Lost notification connection, will attempt to reconnect soon."
|
17
|
+
@@notification_announce_reconnect = true
|
18
|
+
sleep(5) # throttle errors
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.do_notifications
|
25
|
+
http = make_http_connection
|
26
|
+
puts "NOTICE: Notification connection established." if @@notification_announce_reconnect
|
27
|
+
while true
|
28
|
+
sleep(0.25) # small throttle of requests
|
29
|
+
path = '/api/development-plugin-loader/get-notifications'
|
30
|
+
path << "?queue=#{@@notification_queue_name}" if @@notification_queue_name
|
31
|
+
request = Net::HTTP::Get.new(path)
|
32
|
+
setup_request(request)
|
33
|
+
# Server uses long-polling, and will respond after a long timeout, or when a notification
|
34
|
+
# has been queued for sending to this process.
|
35
|
+
response = http.request(request)
|
36
|
+
if response.kind_of?(Net::HTTPOK)
|
37
|
+
@@notification_queue_name = response['X-Queue-Name']
|
38
|
+
begin
|
39
|
+
decode_and_handle_notifications response.body
|
40
|
+
rescue
|
41
|
+
puts "NOTICE: Error handling notification from server."
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise "Bad response"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.decode_and_handle_notifications(encoded)
|
50
|
+
size = encoded.length
|
51
|
+
pos = 0
|
52
|
+
while pos < (size - 12)
|
53
|
+
type = encoded[pos, 4]
|
54
|
+
data_size = encoded[pos + 4, 8].to_i(16)
|
55
|
+
data = encoded[pos + 12, data_size]
|
56
|
+
pos += 12 + data_size
|
57
|
+
handle_notification(type, data)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.handle_notification(type, data)
|
62
|
+
case type
|
63
|
+
when 'log '
|
64
|
+
# Output from console.log()
|
65
|
+
puts "LOG:#{data}"
|
66
|
+
when 'audt'
|
67
|
+
decoded = JSON.parse(data)
|
68
|
+
kind = decoded.find { |name,value| name == 'auditEntryType' }.last
|
69
|
+
if kind =~ /\A[A-Z\-]+\z/
|
70
|
+
# System audit entry - suppressed by default
|
71
|
+
unless @@notification_options.show_system_audit
|
72
|
+
unless @@notification_have_suppressed_first_system_audit_entry
|
73
|
+
@@notification_have_suppressed_first_system_audit_entry = true
|
74
|
+
puts "NOTICE: System audit trail entries are not being shown. Run with --show-system-audit to display."
|
75
|
+
end
|
76
|
+
return
|
77
|
+
end
|
78
|
+
end
|
79
|
+
puts "AUDIT -------------------------------------------"
|
80
|
+
decoded.each do |key, value|
|
81
|
+
puts sprintf("%22s: %s", key, value.to_s)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
puts "WARNING: Unknown notification received from server. Upgrade the plugin tool using 'jgem update haplo'."
|
85
|
+
sleep(5) # throttle problematic responses
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/lib/packing.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
PACKING_ACCEPTABLE_FILENAME = /\A(js|static|template|test|data)\/([a-z0-9_-]+\/)*[a-z0-9_-]+\.[a-z0-9]+\z/
|
5
|
+
PACKING_ACCEPTABLE_EXCEPTIONS = ['plugin.json', 'requirements.schema', 'global.js', 'certificates-temp-http-api.pem']
|
6
|
+
PACKING_EXCLUDE = ['developer.json']
|
7
|
+
|
8
|
+
def self.pack_plugin(plugin_name, output_directory)
|
9
|
+
# Get filenames and sort
|
10
|
+
files = Dir.glob("#{plugin_name}/**/*").map do |filename|
|
11
|
+
if File.file? filename
|
12
|
+
filename[plugin_name.length+1, filename.length]
|
13
|
+
else
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end .select { |f| !PACKING_EXCLUDE.include?(f) }.compact.sort
|
17
|
+
# Check each filename is acceptable
|
18
|
+
files.each do |filename|
|
19
|
+
unless filename =~ PACKING_ACCEPTABLE_FILENAME || PACKING_ACCEPTABLE_EXCEPTIONS.include?(filename)
|
20
|
+
puts "File '#{filename}' has an unacceptable filename"
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
# Clean output directory
|
25
|
+
output_plugin_dir = "#{output_directory}/#{plugin_name}"
|
26
|
+
puts "Output directory: #{output_plugin_dir}"
|
27
|
+
if File.exist? output_plugin_dir
|
28
|
+
puts "Removing old output directory #{output_plugin_dir}"
|
29
|
+
FileUtils.rm_r(output_plugin_dir)
|
30
|
+
end
|
31
|
+
# Make file structure
|
32
|
+
FileUtils.mkdir(output_plugin_dir)
|
33
|
+
# Process each file, building a manifest
|
34
|
+
puts "Processing files:"
|
35
|
+
manifest = ''
|
36
|
+
minimiser = PluginTool::Minimiser.new
|
37
|
+
files.each do |filename|
|
38
|
+
puts " #{filename}"
|
39
|
+
data = File.open("#{plugin_name}/#{filename}") { |f| f.read }
|
40
|
+
# Minimise file?
|
41
|
+
unless filename =~ /\Ajs\//
|
42
|
+
data = minimiser.process(data, filename)
|
43
|
+
end
|
44
|
+
hash = Digest::SHA256.hexdigest(data)
|
45
|
+
# Make sure output directory exists, write file
|
46
|
+
output_pathname = "#{output_plugin_dir}/#{filename}"
|
47
|
+
output_directory = File.dirname(output_pathname)
|
48
|
+
FileUtils.mkdir_p(output_directory) unless File.directory?(output_directory)
|
49
|
+
File.open(output_pathname, "w") { |f| f.write data }
|
50
|
+
# Filename entry in Manifest
|
51
|
+
manifest << "F #{hash} #{filename}\n"
|
52
|
+
end
|
53
|
+
minimiser.finish
|
54
|
+
# Write manifest and version
|
55
|
+
File.open("#{output_plugin_dir}/manifest", "w") { |f| f.write manifest }
|
56
|
+
version = Digest::SHA256.hexdigest(manifest)
|
57
|
+
File.open("#{output_plugin_dir}/version", "w") { |f| f.write "#{version}\n" }
|
58
|
+
# All done
|
59
|
+
puts "Version: #{version}\nPlugin packed."
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/plugin.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
|
2
|
+
module PluginTool
|
3
|
+
|
4
|
+
class Plugin
|
5
|
+
DEFAULT_PLUGIN_LOAD_PRIORITY = 9999999
|
6
|
+
|
7
|
+
def initialize(name, options)
|
8
|
+
@name = name
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
attr_accessor :name
|
12
|
+
attr_accessor :plugin_dir
|
13
|
+
attr_accessor :loaded_plugin_id
|
14
|
+
|
15
|
+
# ---------------------------------------------------------------------------------------------------------
|
16
|
+
|
17
|
+
@@pending_apply = []
|
18
|
+
|
19
|
+
# ---------------------------------------------------------------------------------------------------------
|
20
|
+
|
21
|
+
def start
|
22
|
+
# Check to see if the plugin is valid
|
23
|
+
unless File.file?("#{@name}/plugin.json")
|
24
|
+
end_on_error "Plugin #{@name} does not exist (no plugin.json file)"
|
25
|
+
end
|
26
|
+
# Setup for using the plugin
|
27
|
+
@plugin_dir = @name
|
28
|
+
end_on_error "logic error" unless @plugin_dir =~ /\A[a-zA-Z0-9_-]+\z/
|
29
|
+
@loaded_plugin_id = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def plugin_load_priority
|
33
|
+
pj = File.open("#{@plugin_dir}/plugin.json") { |f| JSON.parse(f.read) }
|
34
|
+
pj['loadPriority'] || DEFAULT_PLUGIN_LOAD_PRIORITY
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_banner
|
38
|
+
puts "Plugin: #{@plugin_dir}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup_for_server
|
42
|
+
# Make the first empty manifest (may be replaced from server)
|
43
|
+
@current_manifest = {}
|
44
|
+
|
45
|
+
# If minimisation is active, clear the current manifest so all files are uploaded again.
|
46
|
+
if @options.minimiser != nil
|
47
|
+
@current_manifest = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
# See if the plugin has already been registered with the server
|
51
|
+
s_found_info = PluginTool.post_with_json_response("/api/development-plugin-loader/find-registration", {:name => @name})
|
52
|
+
if s_found_info["found"]
|
53
|
+
# Store info returned by the server
|
54
|
+
@loaded_plugin_id = s_found_info["plugin_id"]
|
55
|
+
@current_manifest = s_found_info["manifest"]
|
56
|
+
end
|
57
|
+
|
58
|
+
# If there isn't an existing plugin registered, create a new one
|
59
|
+
if @loaded_plugin_id == nil
|
60
|
+
s_create_info = PluginTool.post_with_json_response("/api/development-plugin-loader/create")
|
61
|
+
end_on_error "Couldn't communicate successfully with server." if s_create_info["protocol_error"]
|
62
|
+
end_on_error "Failed to create plugin on server" unless s_create_info["plugin_id"] != nil
|
63
|
+
@loaded_plugin_id = s_create_info["plugin_id"]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# ---------------------------------------------------------------------------------------------------------
|
68
|
+
|
69
|
+
def exclude_files_from_syntax_check
|
70
|
+
@exclude_files_from_syntax_check ||= begin
|
71
|
+
# developer.json file might contain some files which should not be syntax checked
|
72
|
+
exclude_files_from_check = []
|
73
|
+
developer_json_pathname = "#{@plugin_dir}/developer.json"
|
74
|
+
if File.exist? developer_json_pathname
|
75
|
+
developer_json = JSON.parse(File.read(developer_json_pathname))
|
76
|
+
if developer_json['excludeFromSyntaxCheck'].kind_of?(Array)
|
77
|
+
exclude_files_from_check = developer_json['excludeFromSyntaxCheck']
|
78
|
+
end
|
79
|
+
end
|
80
|
+
exclude_files_from_check
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# ---------------------------------------------------------------------------------------------------------
|
85
|
+
|
86
|
+
def command(cmd)
|
87
|
+
case cmd
|
88
|
+
when 'license-key'
|
89
|
+
application_id = @options.args.first
|
90
|
+
if application_id == nil || application_id !~ /\A\d+\z/
|
91
|
+
end_on_error "Numeric application ID must be specified"
|
92
|
+
end
|
93
|
+
generate_license_key(application_id)
|
94
|
+
|
95
|
+
when 'pack'
|
96
|
+
PluginTool.pack_plugin(@name, @options.output)
|
97
|
+
|
98
|
+
when 'reset-db'
|
99
|
+
puts "Resetting database on server for #{@name}..."
|
100
|
+
reset_result = PluginTool.post_with_json_response("/api/development-plugin-loader/resetdb/#{@loaded_plugin_id}")
|
101
|
+
end_on_error "Couldn't remove old database tables" unless reset_result["result"] == 'success'
|
102
|
+
apply_result = PluginTool.post_with_json_response("/api/development-plugin-loader/apply", :plugins => @loaded_plugin_id)
|
103
|
+
end_on_error "Couldn't apply changes" unless apply_result["result"] == 'success'
|
104
|
+
puts "Done."
|
105
|
+
|
106
|
+
when 'uninstall'
|
107
|
+
puts "Uninstalling plugin #{@name} from server..."
|
108
|
+
reset_result = PluginTool.post_with_json_response("/api/development-plugin-loader/uninstall/#{@loaded_plugin_id}")
|
109
|
+
end_on_error "Couldn't uninstall plugin" unless reset_result["result"] == 'success'
|
110
|
+
puts "Done."
|
111
|
+
|
112
|
+
when 'test'
|
113
|
+
puts "Running tests..."
|
114
|
+
params = {}
|
115
|
+
params["test"] = @options.args.first unless @options.args.empty?
|
116
|
+
test_result = PluginTool.post_with_json_response("/api/development-plugin-loader/run-tests/#{@loaded_plugin_id}", params)
|
117
|
+
end_on_error "Couldn't run tests" unless test_result["result"] == 'success'
|
118
|
+
puts
|
119
|
+
puts test_result["output"] || ''
|
120
|
+
puts test_result["summary"] || "(unknown results)"
|
121
|
+
|
122
|
+
when 'develop'
|
123
|
+
# do nothing here
|
124
|
+
|
125
|
+
else
|
126
|
+
end_on_error "Unknown command '#{cmd}'"
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# ---------------------------------------------------------------------------------------------------------
|
132
|
+
|
133
|
+
def develop_setup
|
134
|
+
end
|
135
|
+
|
136
|
+
def develop_scan_and_upload(first_run)
|
137
|
+
should_apply = first_run
|
138
|
+
next_manifest = PluginTool.generate_manifest(@plugin_dir)
|
139
|
+
if !(next_manifest.has_key?("plugin.json"))
|
140
|
+
# If the plugin.json file is deleted, just uninstall the plugin from the server
|
141
|
+
command('uninstall')
|
142
|
+
@is_uninstalled = true
|
143
|
+
return
|
144
|
+
elsif @is_uninstalled
|
145
|
+
should_apply = true
|
146
|
+
end
|
147
|
+
changes = PluginTool.determine_manifest_changes(@current_manifest, next_manifest)
|
148
|
+
upload_failed = false
|
149
|
+
changes.each do |filename, action|
|
150
|
+
filename =~ /\A(.*?\/)?([^\/]+)\z/
|
151
|
+
params = {:filename => $2}
|
152
|
+
params[:directory] = $1.gsub(/\/\z/,'') if $1
|
153
|
+
if action == :delete
|
154
|
+
puts " #{@name}: Deleting #{filename}"
|
155
|
+
PluginTool.post_with_json_response("/api/development-plugin-loader/delete-file/#{@loaded_plugin_id}", params)
|
156
|
+
else
|
157
|
+
puts " #{@name}: Uploading #{filename}"
|
158
|
+
data = File.open("#{@plugin_dir}/#{filename}") { |f| f.read }
|
159
|
+
hash = action
|
160
|
+
# Minimise file before uploading?
|
161
|
+
if @options.minimiser != nil && filename =~ /\A(static|template)\//
|
162
|
+
size_before = data.length
|
163
|
+
data = @options.minimiser.process(data, filename)
|
164
|
+
size_after = data.length
|
165
|
+
hash = Digest::SHA256.hexdigest(data)
|
166
|
+
puts " minimisation: #{size_before} -> #{size_after} (#{(size_after * 100) / size_before}%)"
|
167
|
+
end
|
168
|
+
r = PluginTool.post_with_json_response("/api/development-plugin-loader/put-file/#{@loaded_plugin_id}", params, {:file => [filename, data]})
|
169
|
+
if r["result"] == 'success'
|
170
|
+
# If the file was uploaded successfully, but the hash didn't match, abort now
|
171
|
+
end_on_error "#{@name}: Disagreed with server about uploaded file hash: local=#{hash}, remote=#{r["hash"]}" unless hash == r["hash"]
|
172
|
+
else
|
173
|
+
# Otherwise mark as a failed upload to stop an apply operation which will fail
|
174
|
+
upload_failed = true
|
175
|
+
end
|
176
|
+
PluginTool.syntax_check(self, filename) if filename =~ /\.(js|hsvt)\z/i
|
177
|
+
end
|
178
|
+
end
|
179
|
+
if upload_failed
|
180
|
+
puts "\n#{@name}: Not applying changes due to failure\n\n"
|
181
|
+
else
|
182
|
+
if !(changes.empty?) || should_apply
|
183
|
+
@@pending_apply.push(self) unless @@pending_apply.include?(self)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
@current_manifest = next_manifest
|
187
|
+
end
|
188
|
+
|
189
|
+
# ---------------------------------------------------------------------------------------------------------
|
190
|
+
|
191
|
+
def self.do_apply
|
192
|
+
return if @@pending_apply.empty?
|
193
|
+
puts "Applying changes on server: #{@@pending_apply.map { |p| p.name } .join(', ')}"
|
194
|
+
r = PluginTool.post_with_json_response("/api/development-plugin-loader/apply", {
|
195
|
+
:plugins => @@pending_apply.map { |p| p.loaded_plugin_id }.join(' ')
|
196
|
+
})
|
197
|
+
if r["result"] == 'success'
|
198
|
+
@@pending_apply = []
|
199
|
+
else
|
200
|
+
puts "\n\nDidn't apply changes on server\n\n"
|
201
|
+
PluginTool.beep
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# ---------------------------------------------------------------------------------------------------------
|
206
|
+
|
207
|
+
def generate_license_key(application_id)
|
208
|
+
info = File.open("#{@plugin_dir}/plugin.json") { |f| JSON.parse(f.read) }
|
209
|
+
if info["installSecret"] == nil
|
210
|
+
end_on_error "#{@name}: No installSecret specified in plugin.json"
|
211
|
+
end
|
212
|
+
license_key = HMAC::SHA1.sign(info["installSecret"], "application:#{application_id}")
|
213
|
+
puts <<__E
|
214
|
+
|
215
|
+
Plugin: #{@name}
|
216
|
+
Application: #{application_id}
|
217
|
+
License key: #{license_key}
|
218
|
+
__E
|
219
|
+
end
|
220
|
+
|
221
|
+
def end_on_error(err)
|
222
|
+
puts err
|
223
|
+
exit 1
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|