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

RobotWebTools / rclnodejs / 18369502876

09 Oct 2025 07:56AM UTC coverage: 83.114% (-1.2%) from 84.337%
18369502876

Pull #1283

github

web-flow
Merge 0306a614e into 8762f1359
Pull Request #1283: Prebuildify

801 of 1060 branches covered (75.57%)

Branch coverage included in aggregate %.

61 of 103 new or added lines in 24 files covered. (59.22%)

1980 of 2286 relevant lines covered (86.61%)

483.34 hits per line

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

48.62
/lib/native_loader.js
1
'use strict';
2

3
const fs = require('fs');
26✔
4
const path = require('path');
26✔
5
const debug = require('debug')('rclnodejs');
26✔
6

7
// Cached native module
8
let nativeModule = null;
26✔
9

10
// Simplified loader: only use prebuilt binaries with exact Ubuntu/ROS2/arch match
11
// Note: Prebuilt binaries are only supported on Linux (Ubuntu) platform
12
function customFallbackLoader() {
13
  // Prebuilt binaries are only for Linux platform
14
  if (process.platform !== 'linux') {
26!
NEW
15
    debug('Prebuilt binaries are only supported on Linux platform');
×
NEW
16
    return null;
×
17
  }
18

19
  const rosDistro = process.env.ROS_DISTRO;
26✔
20
  const arch = process.arch;
26✔
21
  let ubuntuCodename = null;
26✔
22

23
  // Detect Ubuntu codename
24
  try {
26✔
25
    const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
26✔
26
    const match = osRelease.match(/^VERSION_CODENAME=(.*)$/m);
26✔
27
    if (match) {
26!
28
      ubuntuCodename = match[1].trim();
26✔
29
    }
30
  } catch (e) {
NEW
31
    debug('Could not detect Ubuntu codename:', e.message);
×
32
  }
33

34
  // Require all three components for exact match
35
  if (!rosDistro || !ubuntuCodename || !arch) {
26!
NEW
36
    debug(
×
37
      `Missing environment info - ROS: ${rosDistro}, Ubuntu: ${ubuntuCodename}, Arch: ${arch}`
38
    );
NEW
39
    return null;
×
40
  }
41

42
  const prebuildDir = path.join(
26✔
43
    __dirname,
44
    '..',
45
    'prebuilds',
46
    `${process.platform}-${arch}`
47
  );
48

49
  if (!fs.existsSync(prebuildDir)) {
26!
50
    debug('No prebuilds directory found');
26✔
51
    return null;
26✔
52
  }
53

NEW
54
  try {
×
55
    // Look for exact match binary: {ros_distro}-{ubuntu_codename}-{arch}-rclnodejs.node
NEW
56
    const exactMatchFilename = `${rosDistro}-${ubuntuCodename}-${arch}-rclnodejs.node`;
×
NEW
57
    const exactMatchPath = path.join(prebuildDir, exactMatchFilename);
×
58

NEW
59
    if (fs.existsSync(exactMatchPath)) {
×
NEW
60
      debug(`Found exact match binary: ${exactMatchFilename}`);
×
NEW
61
      return require(exactMatchPath);
×
62
    }
63

NEW
64
    debug(`No exact match found for: ${exactMatchFilename}`);
×
NEW
65
    return null;
×
66
  } catch (e) {
NEW
67
    debug('Error in simplified prebuilt loader:', e.message);
×
68
  }
69

NEW
70
  return null;
×
71
}
72

73
// Simplified prebuilt binary loader: exact match or build from source
74
function loadNativeAddon() {
75
  if (nativeModule) {
26!
NEW
76
    return nativeModule;
×
77
  }
78

79
  // Environment variable to force building from source
80
  if (process.env.RCLNODEJS_FORCE_BUILD === '1') {
26!
NEW
81
    debug('Forcing build from source (RCLNODEJS_FORCE_BUILD=1)');
×
82

83
    // Trigger actual compilation
NEW
84
    const { execSync } = require('child_process');
×
NEW
85
    try {
×
NEW
86
      debug('Running forced node-gyp rebuild...');
×
NEW
87
      execSync('npm run rebuild', {
×
88
        stdio: 'inherit',
89
        cwd: __dirname + '/..',
90
        timeout: 300000, // 5 minute timeout
91
      });
92

93
      // Load the newly built binary
NEW
94
      nativeModule = require('bindings')('rclnodejs');
×
NEW
95
      debug('Successfully force compiled and loaded from source');
×
NEW
96
      return nativeModule;
×
97
    } catch (compileError) {
NEW
98
      debug('Forced compilation failed:', compileError.message);
×
NEW
99
      throw new Error(
×
100
        `Failed to force build rclnodejs from source: ${compileError.message}`
101
      );
102
    }
103
  }
104

105
  const rosDistro = process.env.ROS_DISTRO;
26✔
106
  const ubuntuCodename = detectUbuntuCodename();
26✔
107

108
  debug(
26✔
109
    `Platform: ${process.platform}, Arch: ${process.arch}, Ubuntu: ${ubuntuCodename || 'unknown'}, ROS: ${rosDistro || 'unknown'}`
52!
110
  );
111

112
  // Prebuilt binaries are only supported on Linux (Ubuntu)
113
  if (process.platform === 'linux') {
26!
114
    // Try exact match prebuilt binary first
115
    try {
26✔
116
      const prebuiltModule = customFallbackLoader();
26✔
117
      if (prebuiltModule) {
26!
NEW
118
        nativeModule = prebuiltModule;
×
NEW
119
        return nativeModule;
×
120
      }
121
    } catch (e) {
NEW
122
      debug('Exact match prebuilt loading failed:', e.message);
×
123
    }
124

125
    debug(
26✔
126
      'No exact match prebuilt binary found, falling back to build from source'
127
    );
128
  } else {
NEW
129
    debug(
×
130
      `Platform ${process.platform} does not support prebuilt binaries, will try existing build or compile from source`
131
    );
132
  }
133

134
  // No exact match found or non-Linux platform, fall back to existing binary or build from source
135

136
  try {
26✔
137
    // Try to find existing built binary first (works on all platforms)
138
    // The 'bindings' module will search standard locations like:
139
    // - build/Release/rclnodejs.node
140
    // - build/Debug/rclnodejs.node
141
    // - compiled/{node_version}/{platform}/{arch}/rclnodejs.node
142
    // etc.
143
    nativeModule = require('bindings')('rclnodejs');
26✔
144
    debug('Found and loaded existing built binary');
26✔
145
    return nativeModule;
26✔
146
  } catch {
NEW
147
    debug('No existing built binary found, triggering compilation...');
×
148

149
    // Trigger actual compilation
NEW
150
    const { execSync } = require('child_process');
×
NEW
151
    try {
×
NEW
152
      debug('Running node-gyp rebuild...');
×
NEW
153
      execSync('npm run rebuild', {
×
154
        stdio: 'inherit',
155
        cwd: __dirname + '/..',
156
        timeout: 300000, // 5 minute timeout
157
      });
158

159
      // Try to load the newly built binary
NEW
160
      nativeModule = require('bindings')('rclnodejs');
×
NEW
161
      debug('Successfully compiled and loaded from source');
×
NEW
162
      return nativeModule;
×
163
    } catch (compileError) {
NEW
164
      debug('Compilation failed:', compileError.message);
×
NEW
165
      throw new Error(
×
166
        `Failed to build rclnodejs from source: ${compileError.message}`
167
      );
168
    }
169
  }
170
}
171

172
function detectUbuntuCodename() {
173
  if (process.platform !== 'linux') {
26!
NEW
174
    return null;
×
175
  }
176

177
  try {
26✔
178
    const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
26✔
179
    const match = osRelease.match(/^VERSION_CODENAME=(.*)$/m);
26✔
180
    return match ? match[1].trim() : null;
26!
181
  } catch {
NEW
182
    return null;
×
183
  }
184
}
185

186
// Export the native module
187
module.exports = loadNativeAddon();
26✔
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