Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a platform variant for installing a musl binary #1836

Merged
merged 15 commits into from
Dec 18, 2016
Merged

Add a platform variant for installing a musl binary #1836

merged 15 commits into from
Dec 18, 2016

Conversation

lox
Copy link
Contributor

@lox lox commented Dec 16, 2016

This adds a new element platformvariant to the naming scheme for precompiled binding binaries:

{platform}_{platformvariant}-{arch}-{abiversion}_binding

This allows for statically compiled musl binaries to be made available for Alpine Linux.

The check for whether this is needed is done by detecting symbols in the node binary, as suggested in #1589 (comment). I don't love this approach, but it's a whole lot simpler than exec'ing out to ldd.

See #1589 for more details on background.

Tests:

$ docker run -v "$PWD:/code" --rm -w /code node:7-alpine node scripts/install.js 
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.0.0/linux_musl-x64-51_binding.node 
$ docker run -v "$PWD:/code" --rm -w /code node:7 node scripts/install.js 
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.0.0/linux-x64-51_binding.node

if (fs.readFileSync(process.execPath).indexOf('libc.musl-x86_64.so.1') != -1) {
return 'musl';
}
return 'glibc';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to just return empty unless it's musl. Would simplify the code above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, fair.

if (process.platform !== 'linux') {
return '';
}
if (fs.readFileSync(process.execPath).indexOf('libc.musl-x86_64.so.1') !== -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs.readFileSync can throw

var contents = '';
try {
  contents = fs.readFileSync('foo.bar');
  if (contents.indexOf('libc.musl-x86_64.so.1') !== -1) {
    return 'musl';
  }
} catch (err) { }
return ''

Copy link

@S-YOU S-YOU Dec 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess node 0.x readFileSync return Buffer and its Buffer don't have .indexOf, and ci is failing on those. You might need to do like

EDIT: OUTDATED

fs.readFileSync(process.execPath).toString().indexOf('libc.musl-x86_64.so.1') > 0

also why I used > 0 instead of !== -1 is that it should never be 0, becuase it is not a valid executable, if you match it at 0.

EDIT: .toString() is slower, and unneeded on non 0.x, so longer version here

EDIT2: OUTDATED

try {
  var muslName = 'libc.musl-x86_64.so.1';
  var contents = fs.readFileSync(process.execPath);
  var hasMusl = contents.indexOf ? contents.indexOf(muslName) > 0 : contents.toString().indexOf(muslName) > 0;
  if (hasMusl) {
    return 'musl';
  }
} catch (err) { console.log (err); }
  return '';
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, both excellent points. Addressing.

var contents = '';
try {
contents = fs.readFileSync('foo.bar').toString();
if (contents.indexOf('libc.musl-x86_64.so.1') !== -1) {
Copy link

@S-YOU S-YOU Dec 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I sent comment while you are updating this.
toString is slow on where Buffer.indexOf is available. so this would be longer version.

contents = fs.readFileSync('foo.bar');
if (!contents.indexOf) {
  contents = contents.toString();
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starts to get a bit micro-optimization-y for my tastes, but sure.

@lox
Copy link
Contributor Author

lox commented Dec 17, 2016

This last failure has me baffled.

@S-YOU
Copy link

S-YOU commented Dec 17, 2016

if (!contents.indexOf) {
contents = contents.toString();
}
if (contents.indexOf('libc.musl-x86_64.so.1') !== -1) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping @ncopa can you confirm it's ok to cover all Alpine releases or should we look for a wider pattern?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you asking whether this test will work for all Alpine releases? If so, yes.

@shouze
Copy link

shouze commented Dec 17, 2016

LGTM, thx @lox, asked @ncopa to validate the musl check ;)

}
var contents = '';
try {
contents = fs.readFileSync('foo.bar');
Copy link

@S-YOU S-YOU Dec 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, its not 'foo.bar', its process.execPath

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much fail.

@gmaliar
Copy link

gmaliar commented Dec 17, 2016

Hey guys, I've PR'ed on top of @lox because I've hit a few more issues down the road with the linux_musl variant.

@lox can merge it in https://github.com/lox/node-sass/pull/3 and it's passing CI.

https://travis-ci.org/gmaliar/node-sass/builds/184758295

Guy Maliar and others added 2 commits December 17, 2016 15:08
fix getPlatformVariant, getHumanPlatform and getBinaryPath
@lox
Copy link
Contributor Author

lox commented Dec 17, 2016

Thanks @gmaliar!

var contents = '';
try {
contents = fs.readFileSync(process.execPath);
if (!contents.indexOf) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you able to figure out how contents wasn't a string or buffer? This intent of line isn't clear.

Copy link

@S-YOU S-YOU Dec 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just tried on 0.10. 0.12 and 7, they all return Buffer, indexOf is not available in 0.10 and 0.12

%docker run --rm -it mhart/alpine-node:0.12 sh                                                                    
# node
> fs.readFileSync(process.execPath)
<Buffer 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 03 00 3e 00 01 00 00 00 43 b3 2a 00 00 00 00 00 40 00 00 00 00 00 00 00 78 64 fa 00 00 00 00 00 00 00 ... >
> fs.readFileSync(process.execPath).indexOf
undefined
%docker run --rm -it mhart/alpine-node:7 sh   
# node
> fs.readFileSync(process.execPath)
<Buffer 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 03 00 3e 00 01 00 00 00 11 03 57 00 00 00 00 00 40 00 00 00 00 00 00 00 f8 1d 26 02 00 00 00 00 00 00 ... >
> fs.readFileSync(process.execPath).indexOf
[Function: indexOf]

Docs says, buf.indexOf is added in v1.5.0
https://nodejs.org/api/buffer.html#buffer_buf_indexof_value_byteoffset_encoding

Copy link

@S-YOU S-YOU Dec 18, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and performance difference with/without .toString() on node 7.0

> console.time('find');fs.readFileSync(process.execPath).indexOf('libc.musl-x86_64.so.1') !== -1;console.timeEnd('find') 
find: 15.800ms

> console.time('find');fs.readFileSync(process.execPath).toString().indexOf('libc.musl-x86_64.so.1') !== -1;console.timeEnd('find')
find: 325.538ms

Also I think toString will use additional memory like 20M binary x UTF16 = 40M, If I am not wrong.

Of course there will be better performance by reading file by chunks, stop when found, but that's too much code to add, in my opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the clarification @S-YOU. I've gone back to lazily tostring'ing.

@xzyfer
Copy link
Contributor

xzyfer commented Dec 18, 2016

Pushed some minor cleanups. Happy 🚢 this when CI is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants