1 | var fs = require('fs'),
|
2 | path = require('path'),
|
3 | helpers = require('./helpers'),
|
4 | async = require('async'),
|
5 | _ = require ('underscore'),
|
6 | logger = require('./logger')();
|
7 |
|
8 | /**
|
9 | * Filters will be applied to a certain type to decide if that
|
10 | * item should be included in the list to be returned.
|
11 | * You can match extensions, do sanity checks (valid JSON), etc.
|
12 | */
|
13 | var filters = {
|
14 | "dashboards" : function (dashboardPath){
|
15 | try {
|
16 | var contentJSON = JSON.parse(fs.readFileSync(dashboardPath));
|
17 | return (contentJSON.enabled !== false);
|
18 | }
|
19 | catch (e){
|
20 | logger.error ('## ERROR ## ' + dashboardPath + ' has an invalid format or file doesn\'t exist\n');
|
21 | return false;
|
22 | }
|
23 | }
|
24 | };
|
25 |
|
26 | module.exports = {
|
27 |
|
28 | /**
|
29 | * Returns relative path to packages path based on item type.
|
30 | * The main purpose of this function is to be able to handle the different way
|
31 | * widgets and jobs paths are resolved compared to the way dashboards paths are.
|
32 | *
|
33 | * @param {string} name item name to match. It can be namespaced. i.e: atlassian#widget1, widget1
|
34 | * @param {string} itemType item type in plural. ('dashboards', 'jobs', 'widgets')
|
35 | * @param {string} extension : filter result by extension
|
36 | *
|
37 | * @return {string} relative path to item: jobs/job1/job1.js
|
38 | */
|
39 |
|
40 | //TODO: refactor to remove the extension paramater
|
41 |
|
42 | resolve_location : function (name, itemType, extension){
|
43 | var use_directory_level = ((itemType==="widgets") || (itemType==="jobs"));
|
44 | if (use_directory_level){
|
45 | // jobs/job1/job1.js
|
46 | return path.join(itemType, name, name + extension);
|
47 | }
|
48 | else{
|
49 | // dashboards/dashboard.json
|
50 | return path.join(itemType, name + extension);
|
51 | }
|
52 | },
|
53 |
|
54 | /**
|
55 | * Get the items that match the particular filter.
|
56 | *
|
57 | * @param {[string]} items : list of file paths
|
58 | * @param {string} name item name to match. It can be namespaced. i.e: atlassian#widget1, widget1
|
59 | * @param {string} itemType item type in plural. ('dashboards', 'jobs', 'widgets')
|
60 | * @param {string} extension : filter result by extension
|
61 | */
|
62 |
|
63 | resolve_candidates : function(items, name, itemType, extension){
|
64 | var searchCriteria = "";
|
65 | if (name.indexOf("#") > -1){
|
66 | var packageName = name.split("#")[0];
|
67 | var itemParsedName = name.split("#")[1];
|
68 | //package/jobs/job1/job1.js
|
69 | searchCriteria = path.join(packageName, this.resolve_location(itemParsedName, itemType, extension));
|
70 | }
|
71 | else{
|
72 | //jobs/job1/job1.js
|
73 | searchCriteria = this.resolve_location(name, itemType, extension);
|
74 | }
|
75 |
|
76 | searchCriteria = path.sep + searchCriteria;
|
77 |
|
78 | return items.filter(function(item){ return item.indexOf(searchCriteria) > -1; });
|
79 | },
|
80 |
|
81 | /**
|
82 | * Return first candidate found matching name, type and extension
|
83 | *
|
84 | * @param {[string]} packagesPath : list of directories to find packages in.
|
85 | * @param {string} itemName item name to match. It can be namespaced. i.e: atlassian#widget1, widget1
|
86 | * @param {string} itemType item type in plural. ('dashboards', 'jobs', 'widgets')
|
87 | * @param {string} extension : filter result by extension
|
88 | */
|
89 |
|
90 | get_first: function (packagesPath, itemName, itemType, extension, callback) {
|
91 | var thiz = this;
|
92 | this.get(packagesPath, itemType, extension, function(err, items){
|
93 | if (err){ return callback(err); }
|
94 |
|
95 | var candidates = thiz.resolve_candidates(items, itemName, itemType, extension);
|
96 | callback(null, candidates.length ? candidates[0] : null);
|
97 | });
|
98 | },
|
99 |
|
100 |
|
101 | /**
|
102 | * Return list of items found in any package within packagesPath
|
103 | *
|
104 | * @param {[string]} packagesPath : list of directories to find packages in.
|
105 | * @param {string} itemType item type in plural. ('dashboards', 'jobs', 'widgets')
|
106 | * @param {string} extension : filter result by extension
|
107 | */
|
108 |
|
109 | get : function (packagesPath, itemType, extension, callback) {
|
110 | this.getByPackage(packagesPath, itemType, extension, function (err, results){
|
111 | if (err){ return callback(err);}
|
112 | var items = [];
|
113 | results.forEach(function(package){
|
114 | items = items.concat(package.items);
|
115 | });
|
116 | callback(err, items);
|
117 | });
|
118 | },
|
119 |
|
120 | /**
|
121 | * Return list of items found in any package within packagesPath
|
122 | * Items are returned separated by package
|
123 | *
|
124 | * @param {[string]} packagesPath : list of directories to find packages in.
|
125 | * @param {string} itemType item type in plural. ('dashboards', 'jobs', 'widgets')
|
126 | * @param {string} extension : filter result by extension
|
127 | */
|
128 |
|
129 | getByPackage : function (packagesPath, itemType, extension, callback) {
|
130 |
|
131 | var thiz = this;
|
132 |
|
133 | if (!Array.isArray(packagesPath)){
|
134 | packagesPath = [packagesPath];
|
135 | }
|
136 |
|
137 | function readItemsFromPackageDir (dir, cb){
|
138 | var package = {dir : dir};
|
139 |
|
140 | var itemDir = path.join(dir, itemType);
|
141 | if (!fs.existsSync(itemDir)){
|
142 | package.items = [];
|
143 | return cb(null, package);
|
144 | }
|
145 |
|
146 | // this functions parses:
|
147 | // - packages/default/<itemType>/*
|
148 | // - packages/otherpackages/<itemType>/*
|
149 | // for dashboards, or:
|
150 | // - packages/default/<itemType>/*/*.js
|
151 | // - packages/otherpackages/<itemType>/*/*.js
|
152 | // for jobs and widgets
|
153 | fs.readdir(itemDir, function(err, items){
|
154 | if (err){ return cb (err); }
|
155 |
|
156 | var selected_items = [];
|
157 | items.forEach(function(item_name){
|
158 | var item = path.join(itemDir, item_name);
|
159 | var stat = fs.statSync(item);
|
160 | if (stat.isDirectory()){
|
161 | // /job/job1/job1.js
|
162 | item = path.join(item, item_name + extension);
|
163 | }
|
164 |
|
165 | if (path.extname(item) === extension){
|
166 | if (fs.existsSync(item)){
|
167 | selected_items.push(item);
|
168 | }
|
169 | }
|
170 | });
|
171 |
|
172 | if (filters[itemType]){ // change to use custom filters for itemType
|
173 | selected_items = selected_items.filter(filters[itemType]);
|
174 | }
|
175 |
|
176 | package.items = selected_items;
|
177 | return cb(null, package);
|
178 | });
|
179 | }
|
180 |
|
181 |
|
182 | // this function read all the packages from the provided directory packagesPath:
|
183 | // - packages/default/*
|
184 | // - packages/otherpackages/*
|
185 | // and calls readItemsFromPackageDir for every one of them
|
186 |
|
187 | function fillPackages (packagesPath, cb){
|
188 | fs.readdir(packagesPath, function(err, allPackagesDir){
|
189 | if (err){ return cb(err); }
|
190 |
|
191 | // convert to absolute path
|
192 | allPackagesDir = allPackagesDir.map(function(partialDir){
|
193 | return path.join(packagesPath, partialDir);});
|
194 |
|
195 | // get only valid directories
|
196 | allPackagesDir = allPackagesDir.filter(function(dir){
|
197 | return fs.statSync(dir).isDirectory();});
|
198 |
|
199 | // read items from every package and flatten results
|
200 | async.map (allPackagesDir, readItemsFromPackageDir, function(err, results){
|
201 | if (err){
|
202 | return cb(err);
|
203 | }
|
204 | cb(err, _.flatten(results));
|
205 | });
|
206 | });
|
207 | }
|
208 |
|
209 | // loop over all the packages paths, call fillPackages to get the right files on them
|
210 | // and then flatten the results in a single array
|
211 | async.map (packagesPath.filter(fs.existsSync), fillPackages, function(err, results){
|
212 | if (err){ return callback(err); }
|
213 | callback(null, _.flatten(results));
|
214 | });
|
215 | }
|
216 | }; |
\ | No newline at end of file |