I think it's debatable which is the most common usage of
`FileUtils.mkdir_p`, but even assuming the most common use case is
creating a folder when it doesn't previously exist but the parent does,
this optimization doesn't seem to have a noticiable effect there while
harming other use cases.
For benchmarks, I created this script
```ruby
require "benchmark/ips"
Benchmark.ips do |x|
x.report("old mkdir_p - exists") do
FileUtils.mkdir_p "/tmp"
end
x.report("new_mkdir_p - exists") do
FileUtils.mkdir_p_new "/tmp"
end
x.compare!
end
FileUtils.rm_rf "/tmp/foo"
Benchmark.ips do |x|
x.report("old mkdir_p - doesnt exist, parent exists") do
FileUtils.mkdir_p "/tmp/foo"
FileUtils.rm_rf "/tmp/foo"
end
x.report("new_mkdir_p - doesnt exist, parent exists") do
FileUtils.mkdir_p_new "/tmp/foo"
FileUtils.rm_rf "/tmp/foo"
end
x.compare!
end
Benchmark.ips do |x|
x.report("old mkdir_p - doesnt exist, parent either") do
FileUtils.mkdir_p "/tmp/foo/bar"
FileUtils.rm_rf "/tmp/foo"
end
x.report("new_mkdir_p - doesnt exist, parent either") do
FileUtils.mkdir_p_new "/tmp/foo/bar"
FileUtils.rm_rf "/tmp/foo"
end
x.compare!
end
Benchmark.ips do |x|
x.report("old mkdir_p - more levels") do
FileUtils.mkdir_p "/tmp/foo/bar/baz"
FileUtils.rm_rf "/tmp/foo"
end
x.report("new_mkdir_p - more levels") do
FileUtils.mkdir_p_new "/tmp/foo/bar/baz"
FileUtils.rm_rf "/tmp/foo"
end
x.compare!
end
```
and copied the method with the "optimization" removed as
`FileUtils.mkdir_p_new`. The results are as below:
```
Warming up --------------------------------------
old mkdir_p - exists 15.914k i/100ms
new_mkdir_p - exists 46.512k i/100ms
Calculating -------------------------------------
old mkdir_p - exists 161.461k (± 3.2%) i/s - 811.614k in 5.032315s
new_mkdir_p - exists 468.192k (± 2.9%) i/s - 2.372M in 5.071225s
Comparison:
new_mkdir_p - exists: 468192.1 i/s
old mkdir_p - exists: 161461.0 i/s - 2.90x (± 0.00) slower
Warming up --------------------------------------
old mkdir_p - doesnt exist, parent exists
2.142k i/100ms
new_mkdir_p - doesnt exist, parent exists
1.961k i/100ms
Calculating -------------------------------------
old mkdir_p - doesnt exist, parent exists
21.242k (± 6.7%) i/s - 107.100k in 5.069206s
new_mkdir_p - doesnt exist, parent exists
19.682k (± 4.2%) i/s - 100.011k in 5.091961s
Comparison:
old mkdir_p - doesnt exist, parent exists: 21241.7 i/s
new_mkdir_p - doesnt exist, parent exists: 19681.7 i/s - same-ish: difference falls within error
Warming up --------------------------------------
old mkdir_p - doesnt exist, parent either
945.000 i/100ms
new_mkdir_p - doesnt exist, parent either
1.002k i/100ms
Calculating -------------------------------------
old mkdir_p - doesnt exist, parent either
9.689k (± 4.4%) i/s - 49.140k in 5.084342s
new_mkdir_p - doesnt exist, parent either
10.806k (± 4.6%) i/s - 54.108k in 5.020714s
Comparison:
new_mkdir_p - doesnt exist, parent either: 10806.3 i/s
old mkdir_p - doesnt exist, parent either: 9689.3 i/s - 1.12x (± 0.00) slower
Warming up --------------------------------------
old mkdir_p - more levels
702.000 i/100ms
new_mkdir_p - more levels
775.000 i/100ms
Calculating -------------------------------------
old mkdir_p - more levels
7.046k (± 3.5%) i/s - 35.802k in 5.087548s
new_mkdir_p - more levels
7.685k (± 5.5%) i/s - 38.750k in 5.061351s
Comparison:
new_mkdir_p - more levels: 7685.1 i/s
old mkdir_p - more levels: 7046.4 i/s - same-ish: difference falls within error
```
I think it's better to keep the code simpler is the optimization is not
so clear like in this case.
https://github.com/ruby/fileutils/commit/e842a0e70e
Now `$LOADED_FEATURES` list is being maintained by `setup` and
`teardown` and, only libaries under the temporary directory will
be removed. As `save_loaded_features` removes the rest libraries
other than this test directory, ordinary libraries loaded from
files under rubygems also removed, and often causes constant
redefinition warnings.
https://github.com/rubygems/rubygems/commit/9e1f92aafd
Previously they were printing the original command that was run, and
telling the user to rerun it. However, the command sometimes would not
match the exact command that was run (for example, when using the
`--local` flag), and in any case, it's simpler and more useful to print
the underlying error anyways.
https://github.com/rubygems/rubygems/commit/5bc0d51b58
In case we have a corrupted lockfile that claims to support a platform, but
it's missing platform specific gems for it, bundler has a check that
detects the situation and forces a re-resolve. The result of this check
is kept under the `@locked_specs_incomplete_for_platformn` instance
variable in `Definition`.
The installer, however, calls `Definition#nothing_changed?` before this
instance variable has been filled, so the result of it is actually
incorrect here since it will claim that nothing has changed, but
something has changed (locked specs are incomplete for the current
platform).
The consequence of this incorrect result is that the installer thinks it
can go on without re-resolving, resulting in the incomplete resolution
from the lockfile being used, and in a crash being triggered due to
that.
The solution is to make sure the `@locked_specs_incomplete_for_platform`
instance variable is filled before `nothing_changed?` gets called.
Moving it to `initialize` makes the most sense, not because it's the
best place for it (we can refactor this later), but because all of the
other "outdated definition" checks are already set there.
https://github.com/rubygems/rubygems/commit/708afdd789
The other way, in particular matching a substring in the gemspec
summary, is brittle and no longer used since Ruby 2.0.
This needed rewriting the specs that depended on that way.
https://github.com/rubygems/rubygems/commit/059dbfa971
The spec was just faking an installed gemspec without any installed gem
backing it up, resulting in `bundle install` claiming that the gem was
already installed when it was not.
https://github.com/rubygems/rubygems/commit/c35531d1c7