Commit | Line | Data |
---|---|---|
a8109e75 AN |
1 | // This file is part of Moodle - http://moodle.org/ |
2 | // | |
3 | // Moodle is free software: you can redistribute it and/or modify | |
4 | // it under the terms of the GNU General Public License as published by | |
5 | // the Free Software Foundation, either version 3 of the License, or | |
6 | // (at your option) any later version. | |
7 | // | |
8 | // Moodle is distributed in the hope that it will be useful, | |
9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | // GNU General Public License for more details. | |
12 | // | |
13 | // You should have received a copy of the GNU General Public License | |
14 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | /** | |
17 | * Helper functions for working with Moodle component names, directories, and sources. | |
18 | * | |
19 | * @copyright 2019 Andrew Nicols <andrew@nicols.co.uk> | |
20 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
21 | */ | |
22 | ||
23 | "use strict"; | |
24 | /* eslint-env node */ | |
25 | ||
26 | /** @var {Object} A list of subsystems in Moodle */ | |
27 | const componentData = {}; | |
28 | ||
29 | /** | |
30 | * Load details of all moodle modules. | |
31 | * | |
32 | * @returns {object} | |
33 | */ | |
34 | const fetchComponentData = () => { | |
35 | const fs = require('fs'); | |
36 | const path = require('path'); | |
37 | const glob = require('glob'); | |
38 | const gruntFilePath = process.cwd(); | |
39 | ||
40 | if (!Object.entries(componentData).length) { | |
41 | componentData.subsystems = {}; | |
42 | componentData.pathList = []; | |
43 | ||
44 | // Fetch the component definiitions from the distributed JSON file. | |
45 | const components = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/components.json`)); | |
46 | ||
47 | // Build the list of moodle subsystems. | |
48 | componentData.subsystems.lib = 'core'; | |
49 | componentData.pathList.push(process.cwd() + path.sep + 'lib'); | |
50 | for (const [component, thisPath] of Object.entries(components.subsystems)) { | |
51 | if (thisPath) { | |
52 | // Prefix "core_" to the front of the subsystems. | |
53 | componentData.subsystems[thisPath] = `core_${component}`; | |
54 | componentData.pathList.push(process.cwd() + path.sep + thisPath); | |
55 | } | |
56 | } | |
57 | ||
58 | // The list of components incldues the list of subsystems. | |
59 | componentData.components = componentData.subsystems; | |
60 | ||
61 | // Go through each of the plugintypes. | |
62 | Object.entries(components.plugintypes).forEach(([pluginType, pluginTypePath]) => { | |
63 | // We don't allow any code in this place..? | |
64 | glob.sync(`${pluginTypePath}/*/version.php`).forEach(versionPath => { | |
65 | const componentPath = fs.realpathSync(path.dirname(versionPath)); | |
66 | const componentName = path.basename(componentPath); | |
67 | const frankenstyleName = `${pluginType}_${componentName}`; | |
68 | componentData.components[`${pluginTypePath}/${componentName}`] = frankenstyleName; | |
69 | componentData.pathList.push(componentPath); | |
70 | ||
71 | // Look for any subplugins. | |
72 | const subPluginConfigurationFile = `${componentPath}/db/subplugins.json`; | |
73 | if (fs.existsSync(subPluginConfigurationFile)) { | |
74 | const subpluginList = JSON.parse(fs.readFileSync(fs.realpathSync(subPluginConfigurationFile))); | |
75 | ||
76 | Object.entries(subpluginList.plugintypes).forEach(([subpluginType, subpluginTypePath]) => { | |
77 | glob.sync(`${subpluginTypePath}/*/version.php`).forEach(versionPath => { | |
78 | const componentPath = fs.realpathSync(path.dirname(versionPath)); | |
79 | const componentName = path.basename(componentPath); | |
80 | const frankenstyleName = `${subpluginType}_${componentName}`; | |
81 | ||
82 | componentData.components[`${subpluginTypePath}/${componentName}`] = frankenstyleName; | |
83 | componentData.pathList.push(componentPath); | |
84 | }); | |
85 | }); | |
86 | } | |
87 | }); | |
88 | }); | |
89 | ||
90 | } | |
91 | ||
92 | return componentData; | |
93 | }; | |
94 | ||
95 | /** | |
96 | * Get the list of paths to build AMD sources. | |
97 | * | |
98 | * @returns {Array} | |
99 | */ | |
100 | const getAmdSrcGlobList = () => { | |
101 | const globList = []; | |
102 | fetchComponentData().pathList.forEach(componentPath => { | |
103 | globList.push(`${componentPath}/amd/src/*.js`); | |
104 | globList.push(`${componentPath}/amd/src/**/*.js`); | |
105 | }); | |
106 | ||
107 | return globList; | |
108 | }; | |
109 | ||
b8693045 AN |
110 | /** |
111 | * Get the list of paths to build YUI sources. | |
112 | * | |
113 | * @param {String} relativeTo | |
114 | * @returns {Array} | |
115 | */ | |
116 | const getYuiSrcGlobList = relativeTo => { | |
117 | const globList = []; | |
118 | fetchComponentData().pathList.forEach(componentPath => { | |
119 | const relativeComponentPath = componentPath.replace(relativeTo, ''); | |
120 | globList.push(`${relativeComponentPath}/yui/src/**/*.js`); | |
121 | }); | |
122 | ||
123 | return globList; | |
124 | }; | |
125 | ||
d7678ab3 AN |
126 | /** |
127 | * Get the list of paths to thirdpartylibs.xml. | |
128 | * | |
129 | * @param {String} relativeTo | |
130 | * @returns {Array} | |
131 | */ | |
132 | const getThirdPartyLibsList = relativeTo => { | |
133 | const fs = require('fs'); | |
134 | ||
135 | return fetchComponentData().pathList | |
136 | .map(componentPath => componentPath.replace(relativeTo, '') + '/thirdpartylibs.xml') | |
137 | .filter(path => fs.existsSync(path)) | |
138 | .sort(); | |
139 | }; | |
140 | ||
a8109e75 AN |
141 | /** |
142 | * Find the name of the component matching the specified path. | |
143 | * | |
144 | * @param {String} path | |
145 | * @returns {String|null} Name of matching component. | |
146 | */ | |
147 | const getComponentFromPath = path => { | |
148 | const componentList = fetchComponentData().components; | |
149 | ||
150 | if (componentList.hasOwnProperty(path)) { | |
151 | return componentList[path]; | |
152 | } | |
153 | ||
154 | return null; | |
155 | }; | |
156 | ||
157 | /** | |
158 | * Check whether the supplied path, relative to the Gruntfile.js, is in a known component. | |
159 | * | |
160 | * @param {String} checkPath The path to check | |
161 | * @returns {String|null} | |
162 | */ | |
163 | const getOwningComponentDirectory = checkPath => { | |
164 | const path = require('path'); | |
165 | ||
91434142 AN |
166 | // Fetch all components into a reverse sorted array. |
167 | // This ensures that components which are within the directory of another component match first. | |
168 | const pathList = Object.keys(fetchComponentData().components).sort().reverse(); | |
169 | for (const componentPath of pathList) { | |
a8109e75 AN |
170 | if (checkPath === componentPath) { |
171 | return componentPath; | |
172 | } | |
173 | if (checkPath.startsWith(componentPath + path.sep)) { | |
174 | return componentPath; | |
175 | } | |
176 | } | |
177 | ||
178 | return null; | |
179 | }; | |
180 | ||
181 | module.exports = { | |
182 | getAmdSrcGlobList, | |
183 | getComponentFromPath, | |
184 | getOwningComponentDirectory, | |
b8693045 | 185 | getYuiSrcGlobList, |
d7678ab3 | 186 | getThirdPartyLibsList, |
a8109e75 | 187 | }; |