1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
# -*- coding: utf-8 -*-
require 'miquire'
require 'plugin'
require 'miquire_to_spec'
# プラグインのロードに関すること
module Miquire::Plugin
class << self
using Miquire::ToSpec
include Enumerable
# ロードパスの配列を返す。
# ロードパスに追加したい場合は、以下のようにすればいい
#
# Miquire::Plugin.loadpath << 'pathA' << 'pathB'
def loadpath
@loadpath ||= [] end
# プラグインのファイル名(フルパス)で繰り返す。
def each(&block)
iterated = Set.new
detected = []
loadpath.reverse.each { |path|
Dir[File.join(File.expand_path(path), '*')].each { |file|
if FileTest.directory?(file) and FileTest.exist?(File.join(file, File.basename(file))+'.rb')
file = File.join(file, File.basename(file))+'.rb'
elsif not file.end_with?('.rb'.freeze)
next end
plugin_name = File.basename(file, '.rb')
if not iterated.include? plugin_name
iterated << plugin_name
detected << file end } }
detected.sort_by{ |a|
[:bundle == get_kind(a) ? 0 : 1, a]
}.each(&block) end
def each_spec
each{ |path|
spec = get_spec path
yield spec if spec } end
def to_hash
result = {}
each_spec{ |spec|
result[spec[:slug].to_sym] = spec }
result end
# 受け取ったパスにあるプラグインのスラッグを返す
# ==== Args
# [path] パス(String)
# ==== Return
# プラグインスラッグ(Symbol)
def get_slug(path)
type_strict path => String
spec = get_spec(path)
if spec
spec[:slug]
else
File.basename(path, ".rb").to_sym end end
# specファイルがあればそれを返す
# ==== Args
# [path] パス(String)
# ==== Return
# specファイルの内容か、存在しなければnil
def get_spec(path)
type_strict path => String
plugin_dir = FileTest.directory?(path) ? path : File.dirname(path)
spec_filename = File.join(plugin_dir, ".mikutter.yml")
deprecated_spec = false
unless FileTest.exist? spec_filename
spec_filename = File.join(plugin_dir, "spec")
deprecated_spec = true end
if FileTest.exist? spec_filename
YAML.load_file(spec_filename).symbolize
.merge(kind: get_kind(path),
path: plugin_dir,
deprecated_spec: deprecated_spec)
elsif FileTest.exist? path
{ slug: File.basename(path, ".rb").to_sym,
kind: get_kind(path),
path: plugin_dir,
deprecated_spec: false } end end
def get_spec_by_slug(slug)
type_strict slug => Symbol
to_hash[slug] end
# プラグインがthirdpartyかbundleかを返す
def get_kind(path)
type_strict path => String
if Environment::PLUGIN_PATH.any?(&path.method(:start_with?))
:bundle
else
:thirdparty end end
def load_all
each_spec do |spec|
load spec
rescue Miquire::LoadError => e
::Plugin.call(:modify_activity,
kind: "system",
title: "#{spec[:slug]} load failed",
date: Time.new,
exception: e,
description: e.to_s)
end
end
def satisfy_mikutter_version?(spec)
if defined?(spec[:depends][:mikutter]) and spec[:depends][:mikutter]
version = Environment::Version.new(*(spec[:depends][:mikutter].split(".").map(&:to_i) + ([0]*4))[0...4])
if Environment::VERSION < version
raise Miquire::LoadError, "plugin #{spec[:slug]}: #{Environment::NAME} version too old (#{spec[:depends][:mikutter]} required, but #{Environment::NAME} version is #{Environment::VERSION})"
return false end end
true
end
def depended_plugins(_spec, recursive: false)
spec = _spec.to_spec
unless spec
error "spec #{_spec.inspect}"
return false
end
if spec.dig(:depends, :plugin)
if recursive
Array(spec.dig(:depends, :plugin)).map { |s| Array(s).first.to_sym }.flat_map { |s|
depended_plugins(s, recursive: recursive).map { |d| d[:slug].to_sym }
}.uniq.map { |d| d.to_spec }
else
Array(spec.dig(:depends, :plugin)).map do |s|
Array(s).first.to_sym&.to_spec
end
end
else
[]
end
end
def load(_spec)
return false unless _spec
spec = _spec.to_spec
return false unless spec
return true if ::Plugin.instance_exist?(spec[:slug])
return false unless satisfy_mikutter_version?(spec)
atomic do
depended_plugins(spec).each do |depend|
raise Miquire::LoadError, "plugin #{spec[:slug].inspect} was not loaded because dependent plugin #{depend.inspect} was not loaded." unless load(depend)
rescue Miquire::LoadError => err
raise Miquire::LoadError, "plugin #{spec[:slug].inspect} was not loaded because dependent plugin was not loaded. previous error is:\n#{err.to_s}"
end
notice "plugin loaded: " + File.join(spec[:path], "#{spec[:slug]}.rb")
::Plugin.create(spec[:slug].to_sym) do
self.spec = spec end
Kernel.load File.join(spec[:path], "#{spec[:slug]}.rb")
if spec[:deprecated_spec]
title = "#{spec[:slug]}: specファイルは非推奨になりました。"
Plugin.call(:modify_activity,
{ plugin: spec[:slug],
kind: "error",
title: title,
date: Time.now,
spec: spec,
description: "#{title}\n代わりに.mikutter.ymlを使ってください。"}) end
true end
end
end
end
|