/wheels/Plugins.cfc

http://raihan.googlecode.com/ · ColdFusion CFScript · 282 lines · 278 code · 4 blank · 0 comment · 1 complexity · 4c81bbf6aff83fc7055008fe665c97b5 MD5 · raw file

  1. <cfcomponent output="false">
  2. <cfset variables.$class = {}>
  3. <cfset variables.$class.plugins = {}>
  4. <cfset variables.$class.mixins = {}>
  5. <cfset variables.$class.mixableComponents = "application,dispatch,controller,model,cache,base,connection,microsoftsqlserver,mysql,oracle,postgresql,h2">
  6. <cfset variables.$class.incompatiblePlugins = "">
  7. <cfset variables.$class.dependantPlugins = "">
  8. <cffunction name="init">
  9. <cfargument name="pluginPath" type="string" required="true" hint="relative path to the plugin folder">
  10. <cfargument name="deletePluginDirectories" type="boolean" required="false" default="#application.wheels.deletePluginDirectories#">
  11. <cfargument name="overwritePlugins" type="boolean" required="false" default="#application.wheels.overwritePlugins#">
  12. <cfargument name="loadIncompatiblePlugins" type="boolean" required="false" default="#application.wheels.loadIncompatiblePlugins#">
  13. <cfargument name="wheelsEnvironment" type="string" required="false" default="#application.wheels.environment#">
  14. <cfargument name="wheelsVersion" type="string" required="false" default="#application.wheels.version#">
  15. <cfset var loc = {}>
  16. <cfset structAppend(variables.$class, arguments)>
  17. <!--- handle pathing for different operating systems --->
  18. <cfset variables.$class.pluginPathFull = ReplaceNoCase(ExpandPath(variables.$class.pluginPath), "\", "/", "all")>
  19. <!--- extract out plugins --->
  20. <cfset $pluginsExtract()>
  21. <!--- remove orphan plugin directories --->
  22. <cfif variables.$class.deletePluginDirectories>
  23. <cfset $pluginDelete()>
  24. </cfif>
  25. <!--- process plugins --->
  26. <cfset $pluginsProcess()>
  27. <!--- process mixins --->
  28. <cfset $processMixins()>
  29. <!--- incompatibility --->
  30. <cfset $determineIncompatible()>
  31. <!--- dependancies --->
  32. <cfset $determinDependancy()>
  33. <cfreturn this>
  34. </cffunction>
  35. <cffunction name="$pluginFolders" returntype="struct">
  36. <cfset var loc = {}>
  37. <cfset loc.plugins = {}>
  38. <cfset loc.folders = $folders()>
  39. <cfloop query="loc.folders">
  40. <cfset loc.temp = {}>
  41. <cfset loc.temp.name = name>
  42. <cfset loc.temp.folderPath = $fullPathToPlugin(lcase(name))>
  43. <cfset loc.temp.componentName = lcase(name) & "." & name>
  44. <cfset loc.plugins[name] = loc.temp>
  45. </cfloop>
  46. <cfreturn loc.plugins>
  47. </cffunction>
  48. <cffunction name="$pluginFiles" returntype="struct">
  49. <cfset var loc = {}>
  50. <!--- get all plugin zip files --->
  51. <cfset loc.files = $files()>
  52. <cfset loc.plugins = {}>
  53. <cfloop query="loc.files">
  54. <cfset loc.name = ListFirst(name, "-")>
  55. <cfset loc.temp = {}>
  56. <cfset loc.temp.file = $fullPathToPlugin(name)>
  57. <cfset loc.temp.name = name>
  58. <cfset loc.temp.folderPath = $fullPathToPlugin(loc.name)>
  59. <cfset loc.temp.folderExists = directoryExists(loc.temp.folderPath)>
  60. <cfset loc.plugins[loc.name] = loc.temp>
  61. </cfloop>
  62. <cfreturn loc.plugins>
  63. </cffunction>
  64. <cffunction name="$pluginsExtract">
  65. <cfset var loc = {}>
  66. <!--- get all plugin zip files --->
  67. <cfset loc.plugins = $pluginFiles()>
  68. <cfloop collection="#loc.plugins#" item="loc.p">
  69. <cfset loc.plugin = loc.plugins[loc.p]>
  70. <cfif not loc.plugin.folderExists OR (loc.plugin.folderExists AND variables.$class.overwritePlugins)>
  71. <cfif not loc.plugin.folderExists>
  72. <cfdirectory action="create" directory="#loc.plugin.folderPath#">
  73. </cfif>
  74. <cfzip action="unzip" destination="#loc.plugin.folderPath#" file="#loc.plugin.file#" overwrite="true" />
  75. </cfif>
  76. </cfloop>
  77. </cffunction>
  78. <cffunction name="$pluginDelete">
  79. <cfset var loc = {}>
  80. <!--- get all plugin folders --->
  81. <cfset loc.folders = $pluginFolders()>
  82. <!--- get all plugin zip files --->
  83. <cfset loc.files = $pluginFiles()>
  84. <!--- put zip files into a list --->
  85. <cfset loc.files = StructKeyList(loc.files)>
  86. <!--- loop through the plugins folders --->
  87. <cfloop collection="#loc.folders#" item="loc.iFolder">
  88. <cfset loc.folder = loc.folders[loc.iFolder]>
  89. <!--- see if a folder is in the list of plugin files --->
  90. <cfif !ListContainsNoCase(loc.files, loc.folder.name)>
  91. <cfdirectory action="delete" directory="#loc.folder.folderPath#" recurse="true">
  92. </cfif>
  93. </cfloop>
  94. </cffunction>
  95. <cffunction name="$pluginsProcess">
  96. <cfset var loc = {}>
  97. <cfset loc.plugins = $pluginFolders()>
  98. <cfset loc.wheelsVersion = SpanExcluding(variables.$class.wheelsVersion, " ")>
  99. <cfloop collection="#loc.plugins#" item="loc.iPlugins">
  100. <cfset loc.plugin = createobject("component", $componentPathToPlugin(loc.iPlugins)).init()>
  101. <cfif not StructKeyExists(loc.plugin, "version") OR ListFind(loc.plugin.version, loc.wheelsVersion) OR variables.$class.loadIncompatiblePlugins>
  102. <cfset variables.$class.plugins[loc.iPlugins] = loc.plugin>
  103. <cfif StructKeyExists(loc.plugin, "version") AND not ListFind(loc.plugin.version, loc.wheelsVersion)>
  104. <cfset variables.$class.incompatiblePlugins = ListAppend(variables.$class.incompatiblePlugins, loc.iPlugins)>
  105. </cfif>
  106. </cfif>
  107. </cfloop>
  108. </cffunction>
  109. <cffunction name="$determineIncompatible">
  110. <cfset var loc = {}>
  111. <cfset loc.excludeMethods = "init,version,pluginVersion">
  112. <cfset loc.loadedMethods = {}>
  113. <cfloop collection="#variables.$class.plugins#" item="loc.iPlugins">
  114. <cfset loc.plugin = variables.$class.plugins[loc.iPlugins]>
  115. <cfloop collection="#loc.plugin#" item="loc.method">
  116. <cfif not ListFindNoCase(loc.excludeMethods, loc.method)>
  117. <cfif StructKeyExists(loc.loadedMethods, loc.method)>
  118. <cfthrow type="Wheels.IncompatiblePlugin" message="#loc.iPlugins# is incompatible with a previously installed plugin." extendedInfo="Make sure none of the plugins you have installed override the same Wheels functions.">
  119. <cfelse>
  120. <cfset loc.loadedMethods[loc.method] = "">
  121. </cfif>
  122. </cfif>
  123. </cfloop>
  124. </cfloop>
  125. </cffunction>
  126. <cffunction name="$determinDependancy">
  127. <cfset var loc = {}>
  128. <cfloop collection="#variables.$class.plugins#" item="loc.iPlugins">
  129. <cfset loc.pluginMeta = GetMetaData(variables.$class.plugins[loc.iPlugins])>
  130. <cfif StructKeyExists(loc.pluginMeta, "dependency")>
  131. <cfloop list="#loc.pluginMeta.dependency#" index="loc.iDependency">
  132. <cfset loc.iDependency = trim(loc.iDependency)>
  133. <cfif not StructKeyExists(variables.$class.plugins, loc.iDependency)>
  134. <cfset variables.$class.dependantPlugins = ListAppend(variables.$class.dependantPlugins, Reverse(SpanExcluding(Reverse(loc.pluginMeta.name), ".")) & "|" & loc.iDependency)>
  135. </cfif>
  136. </cfloop>
  137. </cfif>
  138. </cfloop>
  139. </cffunction>
  140. <!--- mixins --->
  141. <cffunction name="$processMixins">
  142. <cfset var loc = {}>
  143. <!--- setup a container for each mixableComponents type --->
  144. <cfloop list="#variables.$class.mixableComponents#" index="loc.iMixableComponents">
  145. <cfset variables.$class.mixins[loc.iMixableComponents] = {}>
  146. </cfloop>
  147. <cfloop collection="#variables.$class.plugins#" item="loc.iPlugin">
  148. <!--- reference the plugin --->
  149. <cfset loc.plugin = variables.$class.plugins[loc.iPlugin]>
  150. <!--- grab meta data of the plugin --->
  151. <cfset loc.pluginMeta = GetMetaData(loc.plugin)>
  152. <cfif not StructKeyExists(loc.pluginMeta, "environment") OR ListFindNoCase(loc.pluginMeta.environment, variables.$class.wheelsEnvironment)>
  153. <!--- by default and for backwards compatibility, we inject all methods into all objects --->
  154. <cfset loc.pluginMixins = "global">
  155. <cfif StructKeyExists(loc.pluginMeta, "mixin")>
  156. <!--- if the component has a default mixin value, assign that value --->
  157. <cfset loc.pluginMixins = loc.pluginMeta["mixin"]>
  158. </cfif>
  159. <!--- loop through all plugin methods and enter injection info accordingly (based on the mixin value on the method or the default one set on the entire component) --->
  160. <cfset loc.pluginMethods = StructKeyList(loc.plugin)>
  161. <cfloop list="#loc.pluginMethods#" index="loc.iPluginMethods">
  162. <cfif IsCustomFunction(loc.plugin[loc.iPluginMethods]) AND loc.iPluginMethods NEQ "init">
  163. <cfset loc.methodMeta = GetMetaData(loc.plugin[loc.iPluginMethods])>
  164. <cfset loc.methodMixins = loc.pluginMixins>
  165. <cfif StructKeyExists(loc.methodMeta, "mixin")>
  166. <cfset loc.methodMixins = loc.methodMeta["mixin"]>
  167. </cfif>
  168. <!--- mixin all methods except those marked as none --->
  169. <cfif loc.methodMixins NEQ "none">
  170. <cfloop list="#variables.$class.mixableComponents#" index="loc.iMixableComponent">
  171. <cfif loc.methodMixins EQ "global" OR ListFindNoCase(loc.methodMixins, loc.iMixableComponent)>
  172. <cfset variables.$class.mixins[loc.iMixableComponent][loc.iPluginMethods] = loc.plugin[loc.iPluginMethods]>
  173. </cfif>
  174. </cfloop>
  175. </cfif>
  176. </cfif>
  177. </cfloop>
  178. </cfif>
  179. </cfloop>
  180. </cffunction>
  181. <!--- getters --->
  182. <cffunction name="getPlugins">
  183. <cfreturn variables.$class.plugins>
  184. </cffunction>
  185. <cffunction name="getIncompatiblePlugins">
  186. <cfreturn variables.$class.incompatiblePlugins>
  187. </cffunction>
  188. <cffunction name="getDependantPlugins">
  189. <cfreturn variables.$class.dependantPlugins>
  190. </cffunction>
  191. <cffunction name="getMixins">
  192. <cfreturn variables.$class.mixins>
  193. </cffunction>
  194. <cffunction name="getMixableComponents">
  195. <cfreturn variables.$class.mixableComponents>
  196. </cffunction>
  197. <cffunction name="inspect">
  198. <cfreturn variables>
  199. </cffunction>
  200. <!--- private methods --->
  201. <cffunction name="$fullPathToPlugin">
  202. <cfargument name="folder" type="string" required="true">
  203. <cfreturn ListAppend(variables.$class.pluginPathFull, arguments.folder, "/")>
  204. </cffunction>
  205. <cffunction name="$componentPathToPlugin">
  206. <cfargument name="folder" type="string" required="true">
  207. <cfset var loc = {}>
  208. <cfset loc.path = [ListChangeDelims(variables.$class.pluginPath, ".", "/"), arguments.folder, arguments.folder]>
  209. <cfreturn ArrayToList(loc.path, ".")>
  210. </cffunction>
  211. <cffunction name="$folders" returntype="query">
  212. <cfset var q = "">
  213. <cfdirectory action="list" directory="#variables.$class.pluginPathFull#" type="dir" name="q">
  214. <cfquery name="q" dbtype="query">
  215. select * from q where name not like '.%'
  216. </cfquery>
  217. <cfreturn q>
  218. </cffunction>
  219. <cffunction name="$files" returntype="query">
  220. <cfset var q = "">
  221. <cfdirectory directory="#variables.$class.pluginPathFull#" action="list" filter="*.zip" type="file" sort="name DESC" name="q">
  222. <cfquery name="q" dbtype="query">
  223. select * from q where name not like '.%'
  224. </cfquery>
  225. <cfreturn q>
  226. </cffunction>
  227. </cfcomponent>