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

fix logic of register_default_spec #611

Merged
merged 4 commits into from Aug 26, 2013

Conversation

jaggederest
Copy link
Contributor

Register default spec currently only checks the first file to see if it should use the new spec type (i.e. lib/foo.rb) or the old one (i.e. foo.rb).

This patch fixes that misbehavior at the cost of (possibly) going through all files for each require path.

@drbrain
Copy link
Member

drbrain commented Jul 31, 2013

I think this is correct since we can't depend on ordering in #files. @headius, can you check it?

@headius
Copy link
Contributor

headius commented Aug 1, 2013

It was intentional. No code out there generates a default spec with both layouts. Do you have a counter-example?

@headius
Copy link
Contributor

headius commented Aug 1, 2013

By counter-example I mean a case where scanning all the files is necessary. For large default gems it could be prohibitively slow at boot.

@drbrain
Copy link
Member

drbrain commented Aug 1, 2013

If we apply #612 the test for this behavior breaks as bin/ comes first in the list. rdoc is a default gem that would have a bin/ first.

@jaggederest can you change the new_format check to look for bin/ in addition to require_paths so only the first item needs to be checked? I think this will allow us to check only the first item.

I do prefer that the new version doesn't use a loop side-effect to do the checking, it's easier to understand than the three-state new_format variable of the original.

@jaggederest
Copy link
Contributor Author

So here's a question: Is there ever going to be a gem which uses the new format but does not contain the character '/' in the file list, or vice versa? Is there any other way of detecting the format type?

By which I mean we could replace

spec.require_paths.any? {|path| spec.files.any? {|f| f.start_with? path } }

with

spec.files.any? {|f| f.includes?('/') } || spec.require_paths.any? {|path| spec.files.first.start_with? path }

Which would iterate across the files once and the paths once, O(n) instead of the files x paths O(n^2) if we knew that only new-format gems include '/'

Alternately, if that's not true, we could do:

spec.files.any? {|file| file.include?('/') && spec.require_paths.any? {|path| file.start_with? path }}

Which reduces the files to the subset that could include a require path (e.g. not those that are, say ABOUT, or aardvark.yml, or something sorting before 'bin' located in the root directory)

Also to note it's only O(n^2) in the case that it's the old format - how many gems are the old format and also have many files and require paths? New format should bail out of the short circuit within a couple iterations.

@headius
Copy link
Contributor

headius commented Aug 2, 2013

Ruby 2.0 default gems are in the old format, so it would be O(n^2) on all Ruby 2.0 installs for the gems they have as default.

I guess I'm still not seeing what the failure case is here for the simpler logic. Can you provide a real-world example of a default gem spec that would break?

@drbrain
Copy link
Member

drbrain commented Aug 2, 2013

@headius right now it is fine, but with #612 applied this test fails: https://travis-ci.org/rubygems/rubygems/jobs/9715205#L106

@jaggederest old format gems look like this (YAML):

$ gem spec rdoc -v 4.0.0 files
---
- rdoc.rb
- rdoc/alias.rb
[…]
- rdoc/top_level.rb
- bin/rdoc
- bin/ri
$ gem spec io-console files
---
- io/console/size.rb
- extconf.rb

New format will have an extra lib/ on the items that currently don't (for the rdoc example).

There's no guarantee the first item in an old-format gem won't have a /.

@jaggederest
Copy link
Contributor Author

Did some back of the envelope benchmarking and it looks like doing it the way I have it is O(n^2) but has a smaller constant time than the other similar methods I mentioned above.

Total number of files in all default gems at the moment is 257, total number of require paths per gem is one or two, so I think it's ok to do it the less computationally intensive way, if this only applies to default gems not everything ever.

@headius Does JRuby include other gems in the default set that I should be checking when I do my pseudo-benchmarking? Any with, say, dozens of include paths and thousands of files, for example? Otherwise I think this is an ok patch.

@headius
Copy link
Contributor

headius commented Aug 22, 2013

Ok, getting back into this today finally.

JRuby and MRI only include a handful of default gems right now, but that could change in the future. However...am I right in thinking this scan could completely go away if we were able to just use the new format?

I have a compromise position...

Whatever patch resolves this is fine with me if there's a way for the per-impl defaults.rb file to specify that it only supports either new or old-style defaults. Current default will be to scan and determine which format to use. Future default would be to always assume new-style defaults, perhaps with specific MRI versions filtered out to use old style (only 2.0, hopefully).

This would allow implementations to opt out of the scanning altogether by specifying which format they use, and the complexity of the scan would be irrelevant.

@drbrain
Copy link
Member

drbrain commented Aug 22, 2013

I like the compromise position. To make it easier on JRuby, CRuby, etc. we can set the default based on RUBY_ENGINE. If it is not "ruby" use the new style. When CRuby switches to the new style we can add a version check for "ruby"-only.

If someone wants to use the old style they can override the default.

@jaggederest do you want to implement it?

@jaggederest
Copy link
Contributor Author

On it! :)

@headius
Copy link
Contributor

headius commented Aug 22, 2013

Good call, @drbrain. Should work on JRuby with new format out of the box then.

@jaggederest
Copy link
Contributor Author

I'd appreciate it if one of you fine fellows would test it on non-mri versions of ruby, I only have 2.0 installed on this machine. (and of course the mark one eyeball check is also appropriate 😃 )

@drbrain
Copy link
Member

drbrain commented Aug 22, 2013

Can you move the default to a new method in lib/rubygems/defaults.rb?

Maybe def full_path_default_gems (false for RUBY_ENGINE == 'ruby')

@jaggederest
Copy link
Contributor Author

Updated, should this new method have tests? It seems pretty trivial, but maybe there's a subtle behavior I'm missing?

@drbrain
Copy link
Member

drbrain commented Aug 23, 2013

A test for the defaults would be nice!

@headius
Copy link
Contributor

headius commented Aug 26, 2013

Change looks good to me at a glance. Thanks!

drbrain added a commit that referenced this pull request Aug 26, 2013
Fix logic of register_default_spec

Issue #611 is needed for #612 which will sort the files list for packagers.

By fixing the issue now this method should not need to change as much.
@drbrain drbrain merged commit effc037 into rubygems:master Aug 26, 2013
drbrain added a commit that referenced this pull request Aug 26, 2013
Old CRuby versions have no RUBY_ENGINE, but the new tests don't account
for this.  This allows the tests to pass on these old rubies (even
though they don't use default gems).

See #611
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

3 participants