Project

General

Profile

Feature #32938 » alt-0001-Extract-Redmine-PluginLoader-from-Redmine-Plugin.patch

Takashi Kato, 2021-10-27 11:57

View differences:

config/initializers/30-redmine.rb
5 5
I18n.config.available_locales = nil
6 6

  
7 7
require 'redmine'
8
require 'redmine/plugin_loader'
8 9

  
9 10
# Load the secret token from the Redmine configuration file
10 11
secret = Redmine::Configuration['secret_token']
......
17 18
  OpenIdAuthentication.store = openid_authentication_store.presence || :memory
18 19
end
19 20

  
20
Redmine::Plugin.load
21
Redmine::PluginLoader.load
22
plugin_assets_reloader = Redmine::PluginLoader.create_assets_reloader
21 23

  
22
plugin_assets_dirs = {}
23
Redmine::Plugin.all.each do |plugin|
24
  plugin_assets_dirs[plugin.assets_directory] = ["*"]
25
end
26
plugin_assets_reloader = ActiveSupport::FileUpdateChecker.new([], plugin_assets_dirs) do
27
  Redmine::Plugin.mirror_assets
28
end
29 24
Rails.application.reloaders << plugin_assets_reloader
30 25
unless Redmine::Configuration['mirror_plugins_assets_on_startup'] == false
31 26
  plugin_assets_reloader.execute
lib/redmine/plugin.rb
52 52
  class Plugin
53 53
    # Absolute path to the directory where plugins are located
54 54
    cattr_accessor :directory
55
    self.directory = File.join(Rails.root, 'plugins')
55
    self.directory = PluginLoader.directory
56 56

  
57 57
    # Absolute path to the plublic directory where plugins assets are copied
58 58
    cattr_accessor :public_directory
59
    self.public_directory = File.join(Rails.root, 'public', 'plugin_assets')
59
    self.public_directory = PluginLoader.public_directory
60 60

  
61 61
    @registered_plugins = {}
62 62
    @used_partials = {}
63 63

  
64
    attr_accessor :path
65

  
64 66
    class << self
65 67
      attr_reader :registered_plugins
66 68
      private :new
......
102 104
        raise PluginNotFound, "Plugin not found. The directory for plugin #{p.id} should be #{p.directory}."
103 105
      end
104 106

  
107
      p.path = PluginLoader.directories{ |d| d.dir == p.directory }
108

  
105 109
      # Adds plugin locales if any
106 110
      # YAML translation files should be found under <plugin>/config/locales/
107 111
      Rails.application.config.i18n.load_path += Dir.glob(File.join(p.directory, 'config', 'locales', '*.yml'))
......
113 117
        ActionMailer::Base.prepend_view_path(view_path)
114 118
      end
115 119

  
116
      # Add the plugin directories to rails autoload paths
117
      engine_cfg = Rails::Engine::Configuration.new(p.directory)
118
      engine_cfg.paths.add 'lib', eager_load: true
119
      Rails.application.config.eager_load_paths += engine_cfg.eager_load_paths
120
      Rails.application.config.autoload_once_paths += engine_cfg.autoload_once_paths
121
      Rails.application.config.autoload_paths += engine_cfg.autoload_paths
122
      ActiveSupport::Dependencies.autoload_paths +=
123
        engine_cfg.eager_load_paths + engine_cfg.autoload_once_paths + engine_cfg.autoload_paths
124

  
125 120
      # Defines plugin setting if present
126 121
      if p.settings
127 122
        Setting.define_plugin_setting p
......
174 169
      registered_plugins[id.to_sym].present?
175 170
    end
176 171

  
177
    def self.load
178
      Dir.glob(File.join(self.directory, '*')).sort.each do |directory|
179
        if File.directory?(directory)
180
          lib = File.join(directory, "lib")
181
          if File.directory?(lib)
182
            $:.unshift lib
183
            ActiveSupport::Dependencies.autoload_paths += [lib]
184
          end
185
          initializer = File.join(directory, "init.rb")
186
          if File.file?(initializer)
187
            require initializer
188
          end
189
        end
190
      end
191
      Redmine::Hook.call_hook :after_plugins_loaded
192
    end
193

  
194 172
    def initialize(id)
195 173
      @id = id.to_sym
196 174
    end
......
205 183

  
206 184
    # Returns the absolute path to the plugin assets directory
207 185
    def assets_directory
208
      File.join(directory, 'assets')
186
      path.assedts_dir
209 187
    end
210 188

  
211 189
    def <=>(plugin)
......
441 419
      settings && settings.is_a?(Hash) && !settings[:partial].blank?
442 420
    end
443 421

  
444
    def mirror_assets
445
      source = assets_directory
446
      destination = public_directory
447
      return unless File.directory?(source)
448

  
449
      source_files = Dir[source + "/**/*"]
450
      source_dirs = source_files.select {|d| File.directory?(d)}
451
      source_files -= source_dirs
452

  
453
      unless source_files.empty?
454
        base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
455
        begin
456
          FileUtils.mkdir_p(base_target_dir)
457
        rescue => e
458
          raise "Could not create directory #{base_target_dir}: " + e.message
459
        end
460
      end
461

  
462
      source_dirs.each do |dir|
463
        # strip down these paths so we have simple, relative paths we can
464
        # add to the destination
465
        target_dir = File.join(destination, dir.gsub(source, ''))
466
        begin
467
          FileUtils.mkdir_p(target_dir)
468
        rescue => e
469
          raise "Could not create directory #{target_dir}: " + e.message
470
        end
471
      end
472

  
473
      source_files.each do |file|
474
        begin
475
          target = File.join(destination, file.gsub(source, ''))
476
          unless File.exist?(target) && FileUtils.identical?(file, target)
477
            FileUtils.cp(file, target)
478
          end
479
        rescue => e
480
          raise "Could not copy #{file} to #{target}: " + e.message
481
        end
482
      end
483
    end
484

  
485
    # Mirrors assets from one or all plugins to public/plugin_assets
486
    def self.mirror_assets(name=nil)
487
      if name.present?
488
        find(name).mirror_assets
489
      else
490
        all.each do |plugin|
491
          plugin.mirror_assets
492
        end
493
      end
494
    end
495

  
496 422
    # The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)
497 423
    def migration_directory
498 424
      File.join(directory, 'db', 'migrate')
lib/redmine/plugin_loader.rb
1
# frozen_string_literal: true
2

  
3
# Redmine - project management software
4
# Copyright (C) 2006-2021  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
module Redmine
21
  class PluginPath
22
    attr_reader :assets_dir, :initializer
23

  
24
    def initialize(dir)
25
      @dir = dir
26
      @assets_dir = File.join dir, 'assets'
27
      @initializer = File.join dir, 'init.rb'
28
    end
29

  
30
    def run_initializer
31
      load initializer if has_initializer?
32
    end
33

  
34
    def to_s
35
      @dir
36
    end
37

  
38
    def mirror_assets
39
      return unless has_assets_dir?
40

  
41
      source_files = Dir["#{assets_dir}/**/*"]
42
      source_dirs = source_files.select { |d| File.directory?(d)}
43
      source_files -= source_dirs
44
      unless source_files.empty?
45
        base_target_dir = File.join(PluginLoader.public_directory, File.dirname(source_files.first).gsub(assets_dir, ''))
46
        begin
47
          FileUtils.mkdir_p(base_target_dir)
48
        rescue => e
49
          raise "Could not create directory #{base_target_dir}: " + e.message
50
        end
51
      end
52
      source_dirs.each do |dir|
53
        # strip down these paths so we have simple, relative paths we can
54
        # add to the destination
55
        target_dir = File.join(PluginLoader.public_directory, dir.gsub(assets_dir, ''))
56
        begin
57
          FileUtils.mkdir_p(target_dir)
58
        rescue => e
59
          raise "Could not create directory #{target_dir}: " + e.message
60
        end
61
      end
62
      source_files.each do |file|
63
        target = File.join(PluginLoader.public_directory, file.gsub(assets_dir, ''))
64
        unless File.exist?(target) && FileUtils.identical?(file, target)
65
          FileUtils.cp(file, target)
66
        end
67
      rescue => e
68
        raise "Could not copy #{file} to #{target}: " + e.message
69
      end
70
    end
71

  
72
    def has_assets_dir?
73
      File.directory?(@assets_dir)
74
    end
75

  
76
    def has_initializer?
77
      File.file?(@initializer)
78
    end
79
  end
80

  
81
  class PluginLoader
82
    # Absolute path to the directory where plugins are located
83
    cattr_accessor :directory
84
    self.directory = Rails.root.join('plugins')
85

  
86
    # Absolute path to the plublic directory where plugins assets are copied
87
    cattr_accessor :public_directory
88
    self.public_directory = Rails.root.join('public/plugin_assets')
89

  
90
    def self.create_assets_reloader
91
      plugin_assets_dirs = {}
92
      @plugin_directories.each do |dir|
93
        plugin_assets_dirs[dir.assets_dir] = ['*']
94
      end
95
      ActiveSupport::FileUpdateChecker.new([], plugin_assets_dirs) do
96
        mirror_assets
97
      end
98
    end
99

  
100
    def self.load
101
      setup
102
      add_autoload_paths
103

  
104
      Rails.application.config.to_prepare do
105
        PluginLoader.directories.each(&:run_initializer)
106

  
107
        Redmine::Hook.call_hook :after_plugins_loaded
108
      end
109
    end
110

  
111
    def self.setup
112
      @plugin_directories = []
113

  
114
      Dir.glob(File.join(directory, '*')).sort.each do |directory|
115
        next unless File.directory?(directory)
116

  
117
        @plugin_directories << PluginPath.new(directory)
118
      end
119
    end
120

  
121
    def self.add_autoload_paths
122
      directories.each do |directory|
123
        # Add the plugin directories to rails autoload paths
124
        engine_cfg = Rails::Engine::Configuration.new(directory.to_s)
125
        engine_cfg.paths.add 'lib', eager_load: true
126
        Rails.application.config.eager_load_paths += engine_cfg.eager_load_paths
127
        Rails.application.config.autoload_once_paths += engine_cfg.autoload_once_paths
128
        Rails.application.config.autoload_paths += engine_cfg.autoload_paths
129
      end
130
    end
131

  
132
    def self.directories
133
      @plugin_directories
134
    end
135

  
136
    def self.mirror_assets
137
      directories.each(&:mirror_assets)
138
    end
139
  end
140
end
(12-12/16)