PageRenderTime 25ms CodeModel.GetById 15ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

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