haplo 2.1.0-java
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.
- 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
|