• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

suculent / thinx-device-api / #252646970

27 Oct 2017 03:17PM UTC coverage: 12.466% (+1.3%) from 11.197%
#252646970

push

suculent
added support for displaying/exporting extended SigFox attributes

37 of 1808 branches covered (2.05%)

Branch coverage included in aggregate %.

735 of 4385 relevant lines covered (16.76%)

0.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

8.68
/lib/thinx/builder.js
1
/** This THiNX-RTM API module is responsible for managing builds and should be offloadable to another server. */
2

3
var Builder = (function() {
1✔
4

5
        var app_config = require("../../conf/config.json");
1✔
6
        if (typeof(process.env.CIRCLE_USERNAME) !== "undefined") {
1!
7
                console.log("» Configuring for Circle CI...");
×
8
                app_config = require("../../conf/config-test.json");
×
9
        }
10
        var db = app_config.database_uri;
1✔
11
        var ROOT = app_config.project_root;
1✔
12

13
        var uuidV1 = require("uuid/v1");
1✔
14
        var mkdirp = require("mkdirp");
1✔
15
        var exec = require("child_process");
1✔
16
        var fs = require("fs");
1✔
17
        var path = require("path");
1✔
18
        var finder = require("fs-finder");
1✔
19

20
        var prefix = "";
1✔
21
        try {
1✔
22
                var pfx_path = app_config.project_root + '/conf/.thx_prefix';
1✔
23
                if (fs.existsSync(pfx_path)) {
1!
24
                        prefix = fs.readFileSync(pfx_path) + "_";
×
25
                }
26
        } catch (e) {
27
                //console.log(e);
28
        }
29

30
        var devicelib = require("nano")(db).use(prefix + "managed_devices");
1✔
31
        var userlib = require("nano")(db).use(prefix + "managed_users");
1✔
32

33
        var apienv = require("./apienv");
1✔
34
        var blog = require("./buildlog");
1✔
35
        var repository = require("./repository");
1✔
36
        var apikey = require("./apikey");
1✔
37
        var v = require("./version");
1✔
38

39
        var thinx_json_template = require("../../builder.thinx.dist.json");
1✔
40

41
        // private
42
        var _private = {
1✔
43

44
                buildCommand: function(build_id, owner, git, udid, dryrun) {
45

46
                        if (typeof(owner) === "undefined") {
×
47
                                console.log("owner is undefined, exiting!");
×
48
                                return false;
×
49
                        }
50

51
                        if (typeof(git) === "undefined") {
×
52
                                console.log("git is undefined, exiting!");
×
53
                                return false;
×
54
                        }
55

56
                        blog.log(build_id, owner, udid, "Build started...");
×
57

58
                        console.log("[builder] [BUILD_STARTED] Executing build chain...");
×
59
                        console.log("[builder] Fetching device " + udid + " for owner " + owner);
×
60

61
                        devicelib.get(udid, function(err, device) {
×
62

63
                                if (err) {
×
64
                                        return {
×
65
                                                success: false,
66
                                                error: "no_such_udid"
67
                                        };
68
                                }
69

70
                                var build_template = require("../../builder.thinx.json");
×
71

72
                                // From `builder`
73

74
                                var OWNER_ID_HOME = ROOT + "/" + "data/" + owner;
×
75
                                var BUILD_PATH = OWNER_ID_HOME + "/" + udid + "/" + build_id;
×
76
                                var LOG_PATH = BUILD_PATH + "/build.log";
×
77

78
                                //
79
                                // Embedded Authentication
80
                                //
81

82
                                console.log("[builder] Fetching API Keys...");
×
83

84
                                apikey.list(owner, function(success, json_keys) {
×
85

86
                                        if (!success) {
×
87
                                                console.log("API Key list failed. " + json_keys);
×
88
                                                if (typeof(callback) !== "undefined") {
×
89
                                                        callback(false, "owner_has_no_api_keys"); // using first API key by default until we'll have initial API key based on user creation.
×
90
                                                }
91
                                                return;
×
92
                                        }
93

94

95
                                        var last_key_hash = null;
×
96
                                        var api_key = null;
×
97

98
                                        // deprecated
99
                                        if (typeof(device.keyhash) !== "undefined") {
×
100
                                                last_key_hash = device.keyhash;
×
101
                                        }
102

103
                                        if (typeof(device.lastkey) !== "undefined") {
×
104
                                                last_key_hash = device.lastkey;
×
105
                                        }
106

107
                                        for (var key in json_keys) {
×
108
                                                var kdata = json_keys[key];
×
109
                                                if (kdata.hash == last_key_hash) {
×
110
                                                        api_key = kdata.key;
×
111
                                                        console.log("[builder] Injecting API Key with hash: " + kdata.hash);
×
112
                                                        break;
×
113
                                                }
114
                                        }
115

116
                                        //
117
                                        // Create deployment path
118
                                        //
119

120
                                        mkdirp(BUILD_PATH, function(err) {
×
121
                                                if (err) {
×
122
                                                        console.log("[builder] " + err);
×
123
                                                        return {
×
124
                                                                success: false,
125
                                                                error: err
126
                                                        };
127
                                                } else {
128

129
                                                        console.log("[builder] Build path:" + BUILD_PATH + " created.");
×
130

131
                                                        //
132
                                                        // Fetch GIT repository
133
                                                        //
134

135
                                                        console.log("[builder] Pre-fetching " + git + "...");
×
136

137
                                                        var SHELL_FETCH = "cd " + BUILD_PATH + "; git clone " + git +
×
138
                                                                "; cd * ; git submodule update --init --recursive";
139
                                                        var fetch_result = exec.execSync(SHELL_FETCH);
×
140
                                                        console.log("[builder] Builder GIT Fetch result: " +
×
141
                                                                fetch_result);
142

143
                                                        var directories = fs.readdirSync(BUILD_PATH).filter(
×
144
                                                                file => fs.lstatSync(path.join(BUILD_PATH, file)).isDirectory()
×
145
                                                        );
146

147
                                                        console.log("Directories: " + JSON.stringify(directories));
×
148

149
                                                        // Adjust build path
150
                                                        var XBUILD_PATH = BUILD_PATH + "/" + directories[0];
×
151

152
                                                        if (directories.length > 1) {
×
153
                                                                XBUILD_PATH = BUILD_PATH + "/" + directories[1]; // 1 is always git
×
154
                                                        }
155

156
                                                        if (directories.length == 1) {
×
157
                                                                XBUILD_PATH = BUILD_PATH + "/" + directories[0];
×
158
                                                        }
159

160
                                                        console.log("XBUILD_PATH: " + XBUILD_PATH);
×
161

162
                                                        repository.getPlatform(XBUILD_PATH, function(success, platform) {
×
163

164
                                                                if (!success) {
×
165
                                                                        console.log("[builder] failed on unknown platform" +
×
166
                                                                                platform);
167
                                                                        return;
×
168
                                                                }
169

170
                                                                var platform_descriptor = require("../../platforms/" +
×
171
                                                                        platform + "/descriptor.json");
172

173
                                                                console.log("[builder] Platform: " + platform);
×
174

175
                                                                var commit_id = exec.execSync("cd " + XBUILD_PATH +
×
176
                                                                        "; git rev-list --all --max-count=1").toString();
177

178
                                                                var rev_command = "git rev-list --all --count";
×
179
                                                                var git_revision = exec.execSync("cd " + XBUILD_PATH + "; " +
×
180
                                                                        rev_command).toString();
181

182
                                                                console.log("[builder] Trying to fetch GIT tag...");
×
183

184
                                                                // --> Safe version of the pattern, should be extracted as fn.
185
                                                                var git_tag = null;
×
186
                                                                var tag_command = "git describe --abbrev=0 --tags";
×
187
                                                                try {
×
188
                                                                        git_tag = exec.execSync("cd " + XBUILD_PATH + "; " +
×
189
                                                                                tag_command).toString();
190
                                                                } catch (e) {
191
                                                                        console.log(
×
192
                                                                                "[builder] TODO: HIDE THIS: Exception while getting git tag: " +
193
                                                                                e
194
                                                                        );
195
                                                                        git_tag = "1.0";
×
196
                                                                }
197
                                                                if (git_tag === null) {
×
198
                                                                        git_tag = "1.0";
×
199
                                                                }
200
                                                                // <--
201

202
                                                                var REPO_VERSION = (git_tag + "." + git_revision).replace("\n", "");
×
203
                                                                var BUILD_DATE = new Date();
×
204
                                                                var HEADER_FILE_NAME = platform_descriptor.header;
×
205

206
                                                                console.log("[builder] REPO_VERSION (TAG+REV) [unused var]: '" + REPO_VERSION.replace(
×
207
                                                                        "\n", "") + "'");
208

209
                                                                var header_file = null;
×
210
                                                                try {
×
211
                                                                        console.log("Finding " + HEADER_FILE_NAME + " in " +
×
212
                                                                                XBUILD_PATH);
213
                                                                        header_file = finder.from(XBUILD_PATH).findFiles(
×
214
                                                                                HEADER_FILE_NAME)[0];
215
                                                                        console.log("[builder] found header_file: " + header_file);
×
216
                                                                } catch (e) {
217
                                                                        console.log(
×
218
                                                                                "TODO: FAIL HERE: Exception while getting header file, use FINDER instead!: " +
219
                                                                                e);
220
                                                                }
221

222
                                                                if (header_file === null) {
×
223
                                                                        header_file = XBUILD_PATH / HEADER_FILE_NAME;
×
224
                                                                        console.log("header_file empty, assigning path: " +
×
225
                                                                                header_file);
226
                                                                }
227

228
                                                                console.log("[builder] Final header_file: " + header_file);
×
229

230
                                                                //
231
                                                                // Fetch API Envs and create header file
232
                                                                //
233

234
                                                                apienv.list(owner,
×
235
                                                                        function(success, api_envs) {
236
                                                                                if (success) {
×
237

238
                                                                                        var thinx_json = thinx_json_template;
×
239

240
                                                                                        for (var api_env in api_envs) {
×
241
                                                                                                thinx_json[api_env] = api_envs[api_env];
×
242
                                                                                        }
243

244
                                                                                        // Attach/replace with important data
245
                                                                                        thinx_json.THINX_ALIAS = device.alias;
×
246
                                                                                        thinx_json.THINX_OWNER = device.owner;
×
247
                                                                                        thinx_json.THINX_API_KEY = api_key; // inferred from last_key_hash
×
248
                                                                                        thinx_json.THINX_COMMIT_ID = commit_id;
×
249
                                                                                        thinx_json.THINX_FIRMWARE_VERSION_SHORT = git_tag;
×
250
                                                                                        thinx_json.THINX_FIRMWARE_VERSION = git + git_tag;
×
251
                                                                                        thinx_json.THINX_UDID = udid;
×
252
                                                                                        thinx_json.THINX_APP_VERSION = v.revision();
×
253

254
                                                                                        thinx_json.THINX_CLOUD_URL = app_config.base_url;
×
255
                                                                                        thinx_json.THINX_MQTT_URL = app_config.mqtt_server;
×
256
                                                                                        thinx_json.THINX_AUTO_UPDATE = true; // device.autoUptate
×
257
                                                                                        thinx_json.THINX_MQTT_PORT = app_config.mqtt_port;
×
258
                                                                                        thinx_json.THINX_API_PORT = app_config.secure_port;
×
259
                                                                                        thinx_json.THINX_PROXY = "thinx.local";
×
260
                                                                                        thinx_json.THINX_PLATFORM = platform;
×
261
                                                                                        thinx_json.THINX_AUTO_UPDATE = device.auto_update;
×
262

263
                                                                                        fs.writeFile(XBUILD_PATH + "/thinx_build.json", JSON.stringify(
×
264
                                                                                                thinx_json), function(err) {
265
                                                                                                if (err) {
×
266
                                                                                                        return console.log("[builder] " + err);
×
267
                                                                                                } else {
268

269
                                                                                                        console.log(
×
270
                                                                                                                "[builder] Calling pre-builder to generate headers from thinx_build.json..."
271
                                                                                                        );
272

273
                                                                                                        if (XBUILD_PATH.indexOf("undefined") !== -1) {
×
274
                                                                                                                return console.log("XBUILD_PATH_ERROR:" +
×
275
                                                                                                                        XBUILD_PATH);
276
                                                                                                        }
277

278
                                                                                                        var PRE = "cd " + ROOT + "; " + ROOT +
×
279
                                                                                                                "/pre-builder --json=" + XBUILD_PATH +
280
                                                                                                                "/thinx_build.json --workdir=" + XBUILD_PATH +
281
                                                                                                                " --root=" + ROOT;
282

283
                                                                                                        console.log("Pre-building with command: " + PRE);
×
284
                                                                                                        var presult = exec.execSync(PRE);
×
285
                                                                                                        console.log("[builder] Pre-build result: " +
×
286
                                                                                                                presult.toString());
287

288
                                                                                                        console.log(
×
289
                                                                                                                "[builder] Starting build environment...");
290

291
                                                                                                        var CMD = "cd " + ROOT + ";" + ROOT +
×
292
                                                                                                                "/builder --owner=" + owner +
293
                                                                                                                " --udid=" + udid +
294
                                                                                                                " --git=" +
295
                                                                                                                git + " --id=" + build_id + " --workdir=" +
296
                                                                                                                XBUILD_PATH;
297

298
                                                                                                        if (dryrun === true) {
×
299
                                                                                                                CMD = CMD + " --dry-run";
×
300
                                                                                                        }
301

302
                                                                                                        if (udid === null) {
×
303
                                                                                                                console.log("[builder] Cannot build without udid!");
×
304
                                                                                                                return;
×
305
                                                                                                        }
306

307
                                                                                                        apienv.list(owner, function(success, keys) {
×
308

309
                                                                                                                if (!success) {
×
310
                                                                                                                        console.log(
×
311
                                                                                                                                "[builder] Custom Environment Variables not loaded."
312
                                                                                                                        );
313
                                                                                                                } else {
314
                                                                                                                        var stringVars = JSON.stringify(keys);
×
315
                                                                                                                        console.log(
×
316
                                                                                                                                "[builder] Build with Custom Environment Variables: " +
317
                                                                                                                                stringVars);
318
                                                                                                                        CMD = CMD + " --env=" + stringVars;
×
319
                                                                                                                }
320

321
                                                                                                                console.log("[builder] Building in shell: " + CMD);
×
322

323
                                                                                                                var shell = exec.spawn(CMD, {
×
324
                                                                                                                        shell: true
325
                                                                                                                });
326

327
                                                                                                                console.log("[OID:" + owner +
×
328
                                                                                                                        "] [BUILD_STARTED] Running normal-exec... from " +
329
                                                                                                                        __dirname);
330

331
                                                                                                                shell.stdout.on("data", function(data) {
×
332
                                                                                                                        console.log("[OID:" + owner + "] [builder] [LOG] [STDOUT] " +
×
333
                                                                                                                                data.toString());
334
                                                                                                                });
335

336
                                                                                                                shell.stderr.on("data", function(data) {
×
337
                                                                                                                        // console.log("[OID:" + owner + "] [builder] [LOG] [STDERR] " + data);
338
                                                                                                                });
339

340
                                                                                                                shell.on("exit", function(code) {
×
341
                                                                                                                        console.log("[OID:" + owner +
×
342
                                                                                                                                "] [BUILD_COMPLETED] [builder] with code " +
343
                                                                                                                                code
344
                                                                                                                        );
345
                                                                                                                });
346

347
                                                                                                        });
348
                                                                                                }
349
                                                                                        });
350
                                                                                } else {
351
                                                                                        console.log("[builder] [APIEnv] Listing failed:" +
×
352
                                                                                                object);
353
                                                                                }
354
                                                                        });
355
                                                        });
356
                                                }
357
                                        });
358
                                });
359
                        });
360
                }
361
        };
362

363
        // public
364
        var _public = {
1✔
365

366
                build: function(owner, build, callback) {
367

368
                        var build_id = uuidV1();
×
369
                        var udid;
370

371
                        var dryrun = false;
×
372
                        if (typeof(build.dryrun) !== "undefined") {
×
373
                                dryrun = build.dryrun;
×
374
                        }
375

376
                        if (typeof(build.udid) !== "undefined") {
×
377
                                if (build.udid === null) {
×
378
                                        callback(false, {
×
379
                                                success: false,
380
                                                status: "missing_device_udid"
381
                                        });
382
                                        return;
×
383
                                }
384
                                udid = build.udid;
×
385
                        } else {
386
                                console.log("NOT Assigning empty build.udid! " + build.udid);
×
387
                        }
388

389
                        if (typeof(build.source_id) === "undefined") {
×
390
                                callback(false, {
×
391
                                        success: false,
392
                                        status: "missing_source_id"
393
                                });
394
                                return;
×
395
                        }
396

397
                        if (typeof(owner) === "undefined") {
×
398
                                callback(false, {
×
399
                                        success: false,
400
                                        status: "missing_owner"
401
                                });
402
                                return;
×
403
                        }
404

405
                        devicelib.view("devicelib", "devices_by_owner", {
×
406
                                "key": owner,
407
                                "include_docs": true
408
                        }, function(err, body) {
409

410
                                if (err) {
×
411
                                        if (err.toString() == "Error: missing") {
×
412
                                                callback(false, {
×
413
                                                        success: false,
414
                                                        status: "no_devices"
415
                                                });
416
                                        }
417
                                        console.log("[builder] /api/build: Error: " + err.toString());
×
418
                                        return;
×
419
                                }
420

421
                                var rows = body.rows; // devices returned
×
422
                                var device = null;
×
423

424
                                for (var row in rows) {
×
425
                                        //if (!rows.hasOwnProperty(row)) continue;
426
                                        //if (!rows[row].hasOwnProperty("doc")) continue;
427
                                        device = rows[row].doc;
×
428
                                        if (!device.hasOwnProperty("udid")) continue;
×
429
                                        var db_udid = device.udid;
×
430

431
                                        var device_owner = "";
×
432
                                        if (typeof(device.owner) !== "undefined") {
×
433
                                                device_owner = device.owner;
×
434
                                        } else {
435
                                                device_owner = owner;
×
436
                                        }
437

438
                                        if (device_owner.indexOf(owner) !== -1) {
×
439
                                                if (udid.indexOf(db_udid) != -1) {
×
440
                                                        udid = device.udid; // target device ID
×
441
                                                        break;
×
442
                                                }
443
                                        }
444
                                }
445

446
                                console.log("Building for device: " + JSON.stringify(device));
×
447

448
                                // Converts build.git to git url by seeking in users' repos
449
                                userlib.get(owner, function(err, doc) {
×
450

451
                                        if (err) {
×
452
                                                console.log("[builder] " + err);
×
453
                                                callback(false, {
×
454
                                                        success: false,
455
                                                        status: "device_fetch_error"
456
                                                });
457
                                                return;
×
458
                                        }
459

460
                                        if (typeof(doc) === "undefined") {
×
461
                                                callback(false, "no_such_owner", build_id);
×
462
                                                return;
×
463
                                        }
464

465
                                        var git = null;
×
466

467
                                        // Finds first source with given source_id
468
                                        var sources = Object.keys(doc.repos);
×
469

470
                                        console.log("[builder] searching: " + doc.repos + " in: " + JSON.stringify(sources));
×
471

472
                                        for (var index in sources) {
×
473
                                                //if (typeof(doc.repos) === "undefined") continue;
474
                                                //if (!sources.hasOwnProperty(index)) continue;
475
                                                //if (!doc.repos.hasOwnProperty(sources[index])) continue;
476
                                                var source = doc.repos[sources[index]];
×
477
                                                var source_id = sources[index];
×
478
                                                if (typeof(source_id) === "undefined") {
×
479
                                                        console.log("[builder] source_id undefined: " + source_id);
×
480
                                                        continue;
×
481
                                                }
482
                                                if (source_id.indexOf(build.source_id) !== -1) {
×
483
                                                        git = source.url;
×
484
                                                        console.log("[builder] git found: " + git);
×
485
                                                        break;
×
486
                                                }
487
                                        }
488

489
                                        if ((typeof(udid) === "undefined" || build === null) ||
×
490
                                                (typeof(owner) === "undefined" || owner === null || owner === "") ||
491
                                                (typeof(git) === "undefined" || git === null || git === "")) {
492
                                                callback(false, {
×
493
                                                        success: false,
494
                                                        status: "invalid_params"
495
                                                });
496
                                                return;
×
497
                                        }
498

499
                                        console.log("[builder] build_id: " + build_id);
×
500
                                        console.log("[builder] udid: " + udid);
×
501
                                        console.log(
×
502
                                                "[builder] owner: " +
503
                                                owner);
504
                                        console.log("[builder] git: " + git);
×
505

506
                                        // Tag device asynchronously with last build ID
507
                                        //devicelib.destroy(device._id, device._rev, function(err) {
508

509
                                        /*
510
                                        if (err) {
511
                                                console.log("[builder] DATABASE CORRUPTION ISSUE!");
512
                                                console.log(err);
513
                                                return;
514
                                        }*/
515

516
                                        device.build_id = build_id;
×
517
                                        delete device._rev;
×
518
                                        delete device._id;
×
519

520
                                        console.log("Build atomically updating device with " + JSON.stringify(device));
×
521

522
                                        devicelib.atomic("devicelib", "modify", device.udid, device, function(error, body) {
×
523
                                                if (error) {
×
524
                                                        console.log(error);
×
525
                                                        devicelib.insert(device, device.udid,
×
526
                                                                function(err, body,
527
                                                                        header) {
528
                                                                        if (err) {
×
529
                                                                                console.log("[builder] " + err, body);
×
530
                                                                        }
531
                                                                });
532
                                                }
533
                                        });
534

535
                                        if (dryrun === false) {
×
536
                                                callback(true, {
×
537
                                                        success: true,
538
                                                        status: "BUILDING",
539
                                                        build_id: build_id
540
                                                });
541
                                        } else {
542
                                                callback(true, {
×
543
                                                        success: true,
544
                                                        status: "DRY-RUN",
545
                                                        build_id: build_id
546
                                                });
547
                                        }
548

549
                                        _private.buildCommand(build_id, owner, git, udid, dryrun);
×
550

551
                                });
552
                        });
553
                },
554

555
                supportedLanguages: function() {
556
                        var languages_path = app_config.project_root + "/languages";
×
557
                        var languages = fs.readdirSync(languages_path).filter(
×
558
                                file => fs.lstatSync(path.join(languages_path, file)).isDirectory()
×
559
                        );
560
                        //console.log("Supported languages: " + JSON.stringify(languages));
561
                        return languages;
×
562
                },
563

564
                supportedExtensions: function() {
565
                        var languages_path = app_config.project_root + "/languages";
×
566
                        var languages = _public.supportedLanguages();
×
567
                        var extensions = [];
×
568
                        for (var lindex in languages) {
×
569
                                var dpath = languages_path + "/" + languages[lindex] +
×
570
                                        "/descriptor.json";
571
                                var descriptor = require(dpath);
×
572
                                if (typeof(descriptor) !== "undefined") {
×
573
                                        var xts = descriptor.extensions;
×
574
                                        for (var eindex in xts) {
×
575
                                                extensions.push(xts[eindex]);
×
576
                                        }
577
                                } else {
578
                                        console.log("No Language descriptor found at " + dpath);
×
579
                                }
580
                        }
581
                        return extensions;
×
582
                }
583

584
        };
585

586
        return _public;
1✔
587

588
})();
589

590
exports.build = Builder.build;
1✔
591
exports.supportedLanguages = Builder.supportedLanguages;
1✔
592
exports.supportedExtensions = Builder.supportedExtensions;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc